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 <errno.h>
20 #include <fcntl.h>
21 #include <malloc.h>
22 #include <poll.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29
30 #include <linux/sync_file.h>
31
32 #ifndef __cplusplus
33 # include <stdatomic.h>
34 #else
35 # include <atomic>
36 # define _Atomic(X) std::atomic< X >
37 using namespace std;
38 #endif
39
40 #include "rga_sync.h"
41
42 /* Legacy Sync API */
43 struct sync_legacy_merge_data {
44 int32_t fd2;
45 char name[32];
46 int32_t fence;
47 };
48
49 /**
50 * DOC: SYNC_IOC_MERGE - merge two fences
51 *
52 * Takes a struct sync_merge_data. Creates a new fence containing copies of
53 * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
54 * new fence's fd in sync_merge_data.fence
55 *
56 * This is the legacy version of the Sync API before the de-stage that happened
57 * on Linux kernel 4.7.
58 */
59 #define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \
60 struct sync_legacy_merge_data)
61
62 // ---------------------------------------------------------------------------
63 // Support for caching the sync uapi version.
64 //
65 // This library supports both legacy (android/staging) uapi and modern
66 // (mainline) sync uapi. Library calls first try one uapi, and if that fails,
67 // try the other. Since any given kernel only supports one uapi version, after
68 // the first successful syscall we know what the kernel supports and can skip
69 // trying the other.
70 enum uapi_version {
71 UAPI_UNKNOWN,
72 UAPI_MODERN,
73 UAPI_LEGACY
74 };
75 static atomic_int g_uapi_version = ATOMIC_VAR_INIT(UAPI_UNKNOWN);
76
rga_strlcpy(char * dest,const char * src,size_t size)77 static size_t rga_strlcpy(char *dest, const char *src, size_t size) {
78 size_t src_len = strlen(src);
79
80 if (size) {
81 size_t len = src_len >= size ? (size - 1) : src_len;
82 // strncpy(dest, src, len);
83 memcpy(dest, src, len);
84 dest[len] = '\0';
85 }
86
87 return src_len;
88 }
89
90 /* sync wait */
rga_sync_wait(int fd,int timeout)91 int rga_sync_wait(int fd, int timeout)
92 {
93 struct pollfd fds;
94 int ret;
95
96 if (fd < 0) {
97 errno = EINVAL;
98 return -1;
99 }
100
101 fds.fd = fd;
102 fds.events = POLLIN;
103
104 do {
105 ret = poll(&fds, 1, timeout);
106 if (ret > 0) {
107 if (fds.revents & (POLLERR | POLLNVAL)) {
108 errno = EINVAL;
109 return -1;
110 }
111 return 0;
112 } else if (ret == 0) {
113 errno = ETIME;
114 return -1;
115 }
116 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
117
118 return ret;
119 }
120
121 /* sync merge */
legacy_sync_merge(const char * name,int fd1,int fd2)122 static int legacy_sync_merge(const char *name, int fd1, int fd2)
123 {
124 struct sync_legacy_merge_data data;
125 int ret;
126
127 data.fd2 = fd2;
128 rga_strlcpy(data.name, name, sizeof(data.name));
129 ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &data);
130 if (ret < 0)
131 return ret;
132 return data.fence;
133 }
134
modern_sync_merge(const char * name,int fd1,int fd2)135 static int modern_sync_merge(const char *name, int fd1, int fd2)
136 {
137 struct sync_merge_data data;
138 int ret;
139
140 data.fd2 = fd2;
141 rga_strlcpy(data.name, name, sizeof(data.name));
142 data.flags = 0;
143 data.pad = 0;
144
145 ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
146 if (ret < 0)
147 return ret;
148 return data.fence;
149 }
150
rga_sync_merge(const char * name,int fd1,int fd2)151 int rga_sync_merge(const char *name, int fd1, int fd2)
152 {
153 int uapi;
154 int ret;
155
156 uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
157
158 if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
159 ret = modern_sync_merge(name, fd1, fd2);
160 if (ret >= 0 || errno != ENOTTY) {
161 if (ret >= 0 && uapi == UAPI_UNKNOWN) {
162 atomic_store_explicit(&g_uapi_version, (int)UAPI_MODERN,
163 memory_order_release);
164 }
165 return ret;
166 }
167 }
168
169 ret = legacy_sync_merge(name, fd1, fd2);
170 if (ret >= 0 && uapi == UAPI_UNKNOWN) {
171 atomic_store_explicit(&g_uapi_version, (int)UAPI_LEGACY,
172 memory_order_release);
173 }
174 return ret;
175 }
176