/*1* sync abstraction2* Copyright 2015-2016 Collabora Ltd.3*4* Based on the implementation from the Android Open Source Project,5*6* Copyright 2012 Google, Inc7*8* Permission is hereby granted, free of charge, to any person obtaining a9* copy of this software and associated documentation files (the "Software"),10* to deal in the Software without restriction, including without limitation11* the rights to use, copy, modify, merge, publish, distribute, sublicense,12* and/or sell copies of the Software, and to permit persons to whom the13* Software is furnished to do so, subject to the following conditions:14*15* The above copyright notice and this permission notice shall be included in16* all copies or substantial portions of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL21* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR22* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,23* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR24* OTHER DEALINGS IN THE SOFTWARE.25*/2627#ifndef _LIBSYNC_H28#define _LIBSYNC_H2930#include <assert.h>31#include <errno.h>32#include <stdbool.h>33#include <stdint.h>34#include <string.h>35#include <sys/ioctl.h>36#include <sys/poll.h>37#include <unistd.h>3839#if defined(__cplusplus)40extern "C" {41#endif4243//#ifdef ANDROID44#if ANDROID_API_LEVEL >= 2645/* On Android, rely on the system's libsync instead of rolling our own46* sync_wait() and sync_merge(). This gives us compatibility with pre-4.747* Android kernels.48*/49#include <android/sync.h>5051/**52* Check if the fd represents a valid fence-fd.53*54* The android variant of this debug helper is implemented on top of the55* system's libsync for compatibility with pre-4.7 android kernels.56*/57static inline bool58sync_valid_fd(int fd)59{60/* sync_file_info() only available in SDK 26. */61#if ANDROID_API_LEVEL >= 2662struct sync_file_info *info = sync_file_info(fd);63if (!info)64return false;65sync_file_info_free(info);66#endif67return true;68}69#else7071#ifndef SYNC_IOC_MERGE72/* duplicated from linux/sync_file.h to avoid build-time dependency73* on new (v4.7) kernel headers. Once distro's are mostly using74* something newer than v4.7 drop this and #include <linux/sync_file.h>75* instead.76*/77struct sync_merge_data {78char name[32];79int32_t fd2;80int32_t fence;81uint32_t flags;82uint32_t pad;83};8485struct sync_file_info {86char name[32];87int32_t status;88uint32_t flags;89uint32_t num_fences;90uint32_t pad;9192uint64_t sync_fence_info;93};9495#define SYNC_IOC_MAGIC '>'96#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)97#define SYNC_IOC_FILE_INFO _IOWR(SYNC_IOC_MAGIC, 4, struct sync_file_info)98#endif99100101static inline int sync_wait(int fd, int timeout)102{103struct pollfd fds = {0};104int ret;105106fds.fd = fd;107fds.events = POLLIN;108109do {110ret = poll(&fds, 1, timeout);111if (ret > 0) {112if (fds.revents & (POLLERR | POLLNVAL)) {113errno = EINVAL;114return -1;115}116return 0;117} else if (ret == 0) {118errno = ETIME;119return -1;120}121} while (ret == -1 && (errno == EINTR || errno == EAGAIN));122123return ret;124}125126static inline int sync_merge(const char *name, int fd1, int fd2)127{128struct sync_merge_data data = {0};129int ret;130131data.fd2 = fd2;132strncpy(data.name, name, sizeof(data.name));133134do {135ret = ioctl(fd1, SYNC_IOC_MERGE, &data);136} while (ret == -1 && (errno == EINTR || errno == EAGAIN));137138if (ret < 0)139return ret;140141return data.fence;142}143144/**145* Check if the fd represents a valid fence-fd.146*/147static inline bool148sync_valid_fd(int fd)149{150struct sync_file_info info = {{0}};151return ioctl(fd, SYNC_IOC_FILE_INFO, &info) >= 0;152}153154#endif /* !ANDROID */155156/* accumulate fd2 into fd1. If *fd1 is not a valid fd then dup fd2,157* otherwise sync_merge() and close the old *fd1. This can be used158* to implement the pattern:159*160* init()161* {162* batch.fence_fd = -1;163* }164*165* // does *NOT* take ownership of fd166* server_sync(int fd)167* {168* if (sync_accumulate("foo", &batch.fence_fd, fd)) {169* ... error ...170* }171* }172*/173static inline int sync_accumulate(const char *name, int *fd1, int fd2)174{175int ret;176177assert(fd2 >= 0);178179if (*fd1 < 0) {180*fd1 = dup(fd2);181return 0;182}183184ret = sync_merge(name, *fd1, fd2);185if (ret < 0) {186/* leave *fd1 as it is */187return ret;188}189190close(*fd1);191*fd1 = ret;192193return 0;194}195196#if defined(__cplusplus)197}198#endif199200#endif201202203