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