1 /*
2  *  sync.c
3  *
4  *   Copyright 2012 Google, Inc
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 #include <fcntl.h>
20 #include <malloc.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <poll.h>
25 
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 
30 #include <sync/sync.h>
31 
32 
33 struct sw_sync_create_fence_data {
34   __u32 value;
35   char name[32];
36   __s32 fence;
37 };
38 
39 #define SW_SYNC_IOC_MAGIC 'W'
40 #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
41 #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
42 
sync_wait(int fd,int timeout)43 int sync_wait(int fd, int timeout)
44 {
45     struct pollfd fds;
46     int ret;
47 
48     if (fd < 0) {
49         errno = EINVAL;
50         return -1;
51     }
52 
53     fds.fd = fd;
54     fds.events = POLLIN;
55 
56     do {
57         ret = poll(&fds, 1, timeout);
58         if (ret > 0) {
59             if (fds.revents & (POLLERR | POLLNVAL)) {
60                 errno = EINVAL;
61                 return -1;
62             }
63             return 0;
64         } else if (ret == 0) {
65             errno = ETIME;
66             return -1;
67         }
68     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
69 
70     return ret;
71 }
72 
sync_merge(const char * name,int fd1,int fd2)73 int sync_merge(const char *name, int fd1, int fd2)
74 {
75     struct sync_legacy_merge_data legacy_data;
76     struct sync_merge_data data;
77     int ret;
78 
79     data.fd2 = fd2;
80     strlcpy(data.name, name, sizeof(data.name));
81     data.flags = 0;
82     data.pad = 0;
83 
84     ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
85     if (ret < 0 && errno == ENOTTY) {
86         legacy_data.fd2 = fd2;
87         strlcpy(legacy_data.name, name, sizeof(legacy_data.name));
88 
89         ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &legacy_data);
90         if (ret < 0)
91             return ret;
92 
93         return legacy_data.fence;
94     } else if (ret < 0) {
95         return ret;
96     }
97 
98     return data.fence;
99 }
100 
sync_fence_info(int fd)101 struct sync_fence_info_data *sync_fence_info(int fd)
102 {
103     struct sync_fence_info_data *legacy_info;
104     struct sync_pt_info *legacy_pt_info;
105     struct sync_file_info *info;
106     struct sync_fence_info *fence_info;
107     int err, num_fences, i;
108 
109     legacy_info = malloc(4096);
110     if (legacy_info == NULL)
111         return NULL;
112 
113     legacy_info->len = 4096;
114     err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info);
115     if (err < 0 && errno != ENOTTY) {
116         free(legacy_info);
117         return NULL;
118     } else if (err == 0) {
119         return legacy_info;
120     }
121 
122     info = calloc(1, sizeof(*info));
123     if (info == NULL)
124         goto free;
125 
126     err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
127     if (err < 0)
128         goto free;
129 
130     num_fences = info->num_fences;
131 
132     if (num_fences) {
133         info->flags = 0;
134         info->num_fences = num_fences;
135         info->sync_fence_info = (uint64_t) calloc(num_fences,
136                                         sizeof(struct sync_fence_info));
137         if ((void *)info->sync_fence_info == NULL)
138             goto free;
139 
140         err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
141         if (err < 0) {
142             free((void *)info->sync_fence_info);
143             goto free;
144         }
145     }
146 
147     legacy_info->len = sizeof(*legacy_info) +
148                         num_fences * sizeof(struct sync_fence_info);
149     strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
150     legacy_info->status = info->status;
151 
152     legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
153     fence_info = (struct sync_fence_info *)info->sync_fence_info;
154     for (i = 0 ; i < num_fences ; i++) {
155         legacy_pt_info[i].len = sizeof(*legacy_pt_info);
156         strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
157                 sizeof(legacy_pt_info->obj_name));
158         strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
159                 sizeof(legacy_pt_info->driver_name));
160         legacy_pt_info[i].status = fence_info[i].status;
161         legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
162     }
163 
164     free((void *)info->sync_fence_info);
165     free(info);
166     return legacy_info;
167 
168 free:
169     free(legacy_info);
170     free(info);
171     return NULL;
172 }
173 
sync_pt_info(struct sync_fence_info_data * info,struct sync_pt_info * itr)174 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
175                                   struct sync_pt_info *itr)
176 {
177     if (itr == NULL)
178         itr = (struct sync_pt_info *) info->pt_info;
179     else
180         itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
181 
182     if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
183         return NULL;
184 
185     return itr;
186 }
187 
sync_fence_info_free(struct sync_fence_info_data * info)188 void sync_fence_info_free(struct sync_fence_info_data *info)
189 {
190     free(info);
191 }
192 
193 
sw_sync_timeline_create(void)194 int sw_sync_timeline_create(void)
195 {
196     int ret;
197 
198     ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
199     if (ret < 0)
200         ret = open("/dev/sw_sync", O_RDWR);
201 
202     return ret;
203 }
204 
sw_sync_timeline_inc(int fd,unsigned count)205 int sw_sync_timeline_inc(int fd, unsigned count)
206 {
207     __u32 arg = count;
208 
209     return ioctl(fd, SW_SYNC_IOC_INC, &arg);
210 }
211 
sw_sync_fence_create(int fd,const char * name,unsigned value)212 int sw_sync_fence_create(int fd, const char *name, unsigned value)
213 {
214     struct sw_sync_create_fence_data data;
215     int err;
216 
217     data.value = value;
218     strlcpy(data.name, name, sizeof(data.name));
219 
220     err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
221     if (err < 0)
222         return err;
223 
224     return data.fence;
225 }
226