1*7688df22SAndroid Build Coastguard Worker /*
2*7688df22SAndroid Build Coastguard Worker * sync abstraction
3*7688df22SAndroid Build Coastguard Worker * Copyright 2015-2016 Collabora Ltd.
4*7688df22SAndroid Build Coastguard Worker *
5*7688df22SAndroid Build Coastguard Worker * Based on the implementation from the Android Open Source Project,
6*7688df22SAndroid Build Coastguard Worker *
7*7688df22SAndroid Build Coastguard Worker * Copyright 2012 Google, Inc
8*7688df22SAndroid Build Coastguard Worker *
9*7688df22SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
10*7688df22SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
11*7688df22SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
12*7688df22SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13*7688df22SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
14*7688df22SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
15*7688df22SAndroid Build Coastguard Worker *
16*7688df22SAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
17*7688df22SAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
18*7688df22SAndroid Build Coastguard Worker *
19*7688df22SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*7688df22SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*7688df22SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22*7688df22SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23*7688df22SAndroid Build Coastguard Worker * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24*7688df22SAndroid Build Coastguard Worker * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25*7688df22SAndroid Build Coastguard Worker * OTHER DEALINGS IN THE SOFTWARE.
26*7688df22SAndroid Build Coastguard Worker */
27*7688df22SAndroid Build Coastguard Worker
28*7688df22SAndroid Build Coastguard Worker #ifndef _LIBSYNC_H
29*7688df22SAndroid Build Coastguard Worker #define _LIBSYNC_H
30*7688df22SAndroid Build Coastguard Worker
31*7688df22SAndroid Build Coastguard Worker #include <assert.h>
32*7688df22SAndroid Build Coastguard Worker #include <errno.h>
33*7688df22SAndroid Build Coastguard Worker #include <stdint.h>
34*7688df22SAndroid Build Coastguard Worker #include <string.h>
35*7688df22SAndroid Build Coastguard Worker #include <sys/ioctl.h>
36*7688df22SAndroid Build Coastguard Worker #include <poll.h>
37*7688df22SAndroid Build Coastguard Worker #include <unistd.h>
38*7688df22SAndroid Build Coastguard Worker
39*7688df22SAndroid Build Coastguard Worker #if defined(__cplusplus)
40*7688df22SAndroid Build Coastguard Worker extern "C" {
41*7688df22SAndroid Build Coastguard Worker #endif
42*7688df22SAndroid Build Coastguard Worker
43*7688df22SAndroid Build Coastguard Worker #ifndef SYNC_IOC_MERGE
44*7688df22SAndroid Build Coastguard Worker /* duplicated from linux/sync_file.h to avoid build-time dependency
45*7688df22SAndroid Build Coastguard Worker * on new (v4.7) kernel headers. Once distro's are mostly using
46*7688df22SAndroid Build Coastguard Worker * something newer than v4.7 drop this and #include <linux/sync_file.h>
47*7688df22SAndroid Build Coastguard Worker * instead.
48*7688df22SAndroid Build Coastguard Worker */
49*7688df22SAndroid Build Coastguard Worker struct sync_merge_data {
50*7688df22SAndroid Build Coastguard Worker char name[32];
51*7688df22SAndroid Build Coastguard Worker int32_t fd2;
52*7688df22SAndroid Build Coastguard Worker int32_t fence;
53*7688df22SAndroid Build Coastguard Worker uint32_t flags;
54*7688df22SAndroid Build Coastguard Worker uint32_t pad;
55*7688df22SAndroid Build Coastguard Worker };
56*7688df22SAndroid Build Coastguard Worker #define SYNC_IOC_MAGIC '>'
57*7688df22SAndroid Build Coastguard Worker #define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
58*7688df22SAndroid Build Coastguard Worker #endif
59*7688df22SAndroid Build Coastguard Worker
60*7688df22SAndroid Build Coastguard Worker
sync_wait(int fd,int timeout)61*7688df22SAndroid Build Coastguard Worker static inline int sync_wait(int fd, int timeout)
62*7688df22SAndroid Build Coastguard Worker {
63*7688df22SAndroid Build Coastguard Worker struct pollfd fds = {0};
64*7688df22SAndroid Build Coastguard Worker int ret;
65*7688df22SAndroid Build Coastguard Worker
66*7688df22SAndroid Build Coastguard Worker fds.fd = fd;
67*7688df22SAndroid Build Coastguard Worker fds.events = POLLIN;
68*7688df22SAndroid Build Coastguard Worker
69*7688df22SAndroid Build Coastguard Worker do {
70*7688df22SAndroid Build Coastguard Worker ret = poll(&fds, 1, timeout);
71*7688df22SAndroid Build Coastguard Worker if (ret > 0) {
72*7688df22SAndroid Build Coastguard Worker if (fds.revents & (POLLERR | POLLNVAL)) {
73*7688df22SAndroid Build Coastguard Worker errno = EINVAL;
74*7688df22SAndroid Build Coastguard Worker return -1;
75*7688df22SAndroid Build Coastguard Worker }
76*7688df22SAndroid Build Coastguard Worker return 0;
77*7688df22SAndroid Build Coastguard Worker } else if (ret == 0) {
78*7688df22SAndroid Build Coastguard Worker errno = ETIME;
79*7688df22SAndroid Build Coastguard Worker return -1;
80*7688df22SAndroid Build Coastguard Worker }
81*7688df22SAndroid Build Coastguard Worker } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
82*7688df22SAndroid Build Coastguard Worker
83*7688df22SAndroid Build Coastguard Worker return ret;
84*7688df22SAndroid Build Coastguard Worker }
85*7688df22SAndroid Build Coastguard Worker
sync_merge(const char * name,int fd1,int fd2)86*7688df22SAndroid Build Coastguard Worker static inline int sync_merge(const char *name, int fd1, int fd2)
87*7688df22SAndroid Build Coastguard Worker {
88*7688df22SAndroid Build Coastguard Worker struct sync_merge_data data = {0};
89*7688df22SAndroid Build Coastguard Worker int ret;
90*7688df22SAndroid Build Coastguard Worker
91*7688df22SAndroid Build Coastguard Worker data.fd2 = fd2;
92*7688df22SAndroid Build Coastguard Worker strncpy(data.name, name, sizeof(data.name));
93*7688df22SAndroid Build Coastguard Worker
94*7688df22SAndroid Build Coastguard Worker do {
95*7688df22SAndroid Build Coastguard Worker ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
96*7688df22SAndroid Build Coastguard Worker } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
97*7688df22SAndroid Build Coastguard Worker
98*7688df22SAndroid Build Coastguard Worker if (ret < 0)
99*7688df22SAndroid Build Coastguard Worker return ret;
100*7688df22SAndroid Build Coastguard Worker
101*7688df22SAndroid Build Coastguard Worker return data.fence;
102*7688df22SAndroid Build Coastguard Worker }
103*7688df22SAndroid Build Coastguard Worker
104*7688df22SAndroid Build Coastguard Worker /* accumulate fd2 into fd1. If *fd1 is not a valid fd then dup fd2,
105*7688df22SAndroid Build Coastguard Worker * otherwise sync_merge() and close the old *fd1. This can be used
106*7688df22SAndroid Build Coastguard Worker * to implement the pattern:
107*7688df22SAndroid Build Coastguard Worker *
108*7688df22SAndroid Build Coastguard Worker * init()
109*7688df22SAndroid Build Coastguard Worker * {
110*7688df22SAndroid Build Coastguard Worker * batch.fence_fd = -1;
111*7688df22SAndroid Build Coastguard Worker * }
112*7688df22SAndroid Build Coastguard Worker *
113*7688df22SAndroid Build Coastguard Worker * // does *NOT* take ownership of fd
114*7688df22SAndroid Build Coastguard Worker * server_sync(int fd)
115*7688df22SAndroid Build Coastguard Worker * {
116*7688df22SAndroid Build Coastguard Worker * if (sync_accumulate("foo", &batch.fence_fd, fd)) {
117*7688df22SAndroid Build Coastguard Worker * ... error ...
118*7688df22SAndroid Build Coastguard Worker * }
119*7688df22SAndroid Build Coastguard Worker * }
120*7688df22SAndroid Build Coastguard Worker */
sync_accumulate(const char * name,int * fd1,int fd2)121*7688df22SAndroid Build Coastguard Worker static inline int sync_accumulate(const char *name, int *fd1, int fd2)
122*7688df22SAndroid Build Coastguard Worker {
123*7688df22SAndroid Build Coastguard Worker int ret;
124*7688df22SAndroid Build Coastguard Worker
125*7688df22SAndroid Build Coastguard Worker assert(fd2 >= 0);
126*7688df22SAndroid Build Coastguard Worker
127*7688df22SAndroid Build Coastguard Worker if (*fd1 < 0) {
128*7688df22SAndroid Build Coastguard Worker *fd1 = dup(fd2);
129*7688df22SAndroid Build Coastguard Worker return 0;
130*7688df22SAndroid Build Coastguard Worker }
131*7688df22SAndroid Build Coastguard Worker
132*7688df22SAndroid Build Coastguard Worker ret = sync_merge(name, *fd1, fd2);
133*7688df22SAndroid Build Coastguard Worker if (ret < 0) {
134*7688df22SAndroid Build Coastguard Worker /* leave *fd1 as it is */
135*7688df22SAndroid Build Coastguard Worker return ret;
136*7688df22SAndroid Build Coastguard Worker }
137*7688df22SAndroid Build Coastguard Worker
138*7688df22SAndroid Build Coastguard Worker close(*fd1);
139*7688df22SAndroid Build Coastguard Worker *fd1 = ret;
140*7688df22SAndroid Build Coastguard Worker
141*7688df22SAndroid Build Coastguard Worker return 0;
142*7688df22SAndroid Build Coastguard Worker }
143*7688df22SAndroid Build Coastguard Worker
144*7688df22SAndroid Build Coastguard Worker #if defined(__cplusplus)
145*7688df22SAndroid Build Coastguard Worker }
146*7688df22SAndroid Build Coastguard Worker #endif
147*7688df22SAndroid Build Coastguard Worker
148*7688df22SAndroid Build Coastguard Worker #endif
149