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