xref: /OK3568_Linux_fs/external/linux-rga/core/rga_sync.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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