1 | /* |
2 | * sync / sw_sync abstraction |
3 | * Copyright 2015-2016 Collabora Ltd. |
4 | * |
5 | * Based on the implementation from the Android Open Source Project, |
6 | * |
7 | * Copyright 2012 Google, Inc |
8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a |
10 | * copy of this software and associated documentation files (the "Software"), |
11 | * to deal in the Software without restriction, including without limitation |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
13 | * and/or sell copies of the Software, and to permit persons to whom the |
14 | * Software is furnished to do so, subject to the following conditions: |
15 | * |
16 | * The above copyright notice and this permission notice shall be included in |
17 | * all copies or substantial portions of the Software. |
18 | * |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
22 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
25 | * OTHER DEALINGS IN THE SOFTWARE. |
26 | */ |
27 | |
28 | #include <fcntl.h> |
29 | #include <malloc.h> |
30 | #include <poll.h> |
31 | #include <stdint.h> |
32 | #include <string.h> |
33 | #include <unistd.h> |
34 | |
35 | #include <sys/ioctl.h> |
36 | #include <sys/stat.h> |
37 | #include <sys/types.h> |
38 | |
39 | #include "sync.h" |
40 | #include "sw_sync.h" |
41 | |
42 | #include <linux/sync_file.h> |
43 | |
44 | |
45 | /* SW_SYNC ioctls */ |
46 | struct sw_sync_create_fence_data { |
47 | __u32 value; |
48 | char name[32]; |
49 | __s32 fence; |
50 | }; |
51 | |
52 | #define SW_SYNC_IOC_MAGIC 'W' |
53 | #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ |
54 | struct sw_sync_create_fence_data) |
55 | #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) |
56 | |
57 | |
58 | int sync_wait(int fd, int timeout) |
59 | { |
60 | struct pollfd fds; |
61 | |
62 | fds.fd = fd; |
63 | fds.events = POLLIN | POLLERR; |
64 | |
65 | return poll(&fds, 1, timeout); |
66 | } |
67 | |
68 | int sync_merge(const char *name, int fd1, int fd2) |
69 | { |
70 | struct sync_merge_data data = {}; |
71 | int err; |
72 | |
73 | data.fd2 = fd2; |
74 | strncpy(data.name, name, sizeof(data.name) - 1); |
75 | data.name[sizeof(data.name) - 1] = '\0'; |
76 | |
77 | err = ioctl(fd1, SYNC_IOC_MERGE, &data); |
78 | if (err < 0) |
79 | return err; |
80 | |
81 | return data.fence; |
82 | } |
83 | |
84 | static struct sync_file_info *sync_file_info(int fd) |
85 | { |
86 | struct sync_file_info *info; |
87 | struct sync_fence_info *fence_info; |
88 | int err, num_fences; |
89 | |
90 | info = calloc(1, sizeof(*info)); |
91 | if (info == NULL) |
92 | return NULL; |
93 | |
94 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); |
95 | if (err < 0) { |
96 | free(info); |
97 | return NULL; |
98 | } |
99 | |
100 | num_fences = info->num_fences; |
101 | |
102 | if (num_fences) { |
103 | info->flags = 0; |
104 | info->num_fences = num_fences; |
105 | |
106 | fence_info = calloc(num_fences, sizeof(*fence_info)); |
107 | if (!fence_info) { |
108 | free(info); |
109 | return NULL; |
110 | } |
111 | |
112 | info->sync_fence_info = (uint64_t)(unsigned long)fence_info; |
113 | |
114 | err = ioctl(fd, SYNC_IOC_FILE_INFO, info); |
115 | if (err < 0) { |
116 | free(fence_info); |
117 | free(info); |
118 | return NULL; |
119 | } |
120 | } |
121 | |
122 | return info; |
123 | } |
124 | |
125 | static void sync_file_info_free(struct sync_file_info *info) |
126 | { |
127 | free((void *)(unsigned long)info->sync_fence_info); |
128 | free(info); |
129 | } |
130 | |
131 | int sync_fence_size(int fd) |
132 | { |
133 | int count; |
134 | struct sync_file_info *info = sync_file_info(fd); |
135 | |
136 | if (!info) |
137 | return 0; |
138 | |
139 | count = info->num_fences; |
140 | |
141 | sync_file_info_free(info); |
142 | |
143 | return count; |
144 | } |
145 | |
146 | int sync_fence_count_with_status(int fd, int status) |
147 | { |
148 | unsigned int i, count = 0; |
149 | struct sync_fence_info *fence_info = NULL; |
150 | struct sync_file_info *info = sync_file_info(fd); |
151 | |
152 | if (!info) |
153 | return -1; |
154 | |
155 | fence_info = (struct sync_fence_info *)(unsigned long)info->sync_fence_info; |
156 | for (i = 0 ; i < info->num_fences ; i++) { |
157 | if (fence_info[i].status == status) |
158 | count++; |
159 | } |
160 | |
161 | sync_file_info_free(info); |
162 | |
163 | return count; |
164 | } |
165 | |
166 | int sw_sync_timeline_create(void) |
167 | { |
168 | return open("/sys/kernel/debug/sync/sw_sync" , O_RDWR); |
169 | } |
170 | |
171 | int sw_sync_timeline_inc(int fd, unsigned int count) |
172 | { |
173 | __u32 arg = count; |
174 | |
175 | return ioctl(fd, SW_SYNC_IOC_INC, &arg); |
176 | } |
177 | |
178 | int sw_sync_timeline_is_valid(int fd) |
179 | { |
180 | int status; |
181 | |
182 | if (fd == -1) |
183 | return 0; |
184 | |
185 | status = fcntl(fd, F_GETFD, 0); |
186 | return (status >= 0); |
187 | } |
188 | |
189 | void sw_sync_timeline_destroy(int fd) |
190 | { |
191 | if (sw_sync_timeline_is_valid(fd)) |
192 | close(fd); |
193 | } |
194 | |
195 | int sw_sync_fence_create(int fd, const char *name, unsigned int value) |
196 | { |
197 | struct sw_sync_create_fence_data data = {}; |
198 | int err; |
199 | |
200 | data.value = value; |
201 | strncpy(p: data.name, q: name, size: sizeof(data.name) - 1); |
202 | data.name[sizeof(data.name) - 1] = '\0'; |
203 | |
204 | err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data); |
205 | if (err < 0) |
206 | return err; |
207 | |
208 | return data.fence; |
209 | } |
210 | |
211 | int sw_sync_fence_is_valid(int fd) |
212 | { |
213 | /* Same code! */ |
214 | return sw_sync_timeline_is_valid(fd); |
215 | } |
216 | |
217 | void sw_sync_fence_destroy(int fd) |
218 | { |
219 | if (sw_sync_fence_is_valid(fd)) |
220 | close(fd); |
221 | } |
222 | |