Home | History | Annotate | Download | only in libsync
      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 <stdatomic.h>
     24 #include <stdint.h>
     25 #include <string.h>
     26 
     27 #include <sys/ioctl.h>
     28 #include <sys/stat.h>
     29 #include <sys/types.h>
     30 
     31 #include <android/sync.h>
     32 
     33 /* Legacy Sync API */
     34 
     35 struct sync_legacy_merge_data {
     36  int32_t fd2;
     37  char name[32];
     38  int32_t fence;
     39 };
     40 
     41 /**
     42  * DOC: SYNC_IOC_MERGE - merge two fences
     43  *
     44  * Takes a struct sync_merge_data.  Creates a new fence containing copies of
     45  * the sync_pts in both the calling fd and sync_merge_data.fd2.  Returns the
     46  * new fence's fd in sync_merge_data.fence
     47  *
     48  * This is the legacy version of the Sync API before the de-stage that happened
     49  * on Linux kernel 4.7.
     50  */
     51 #define SYNC_IOC_LEGACY_MERGE   _IOWR(SYNC_IOC_MAGIC, 1, \
     52     struct sync_legacy_merge_data)
     53 
     54 /**
     55  * DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence
     56  *
     57  * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
     58  * Caller should write the size of the buffer into len.  On return, len is
     59  * updated to reflect the total size of the sync_fence_info_data including
     60  * pt_info.
     61  *
     62  * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
     63  * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
     64  *
     65  * This is the legacy version of the Sync API before the de-stage that happened
     66  * on Linux kernel 4.7.
     67  */
     68 #define SYNC_IOC_LEGACY_FENCE_INFO  _IOWR(SYNC_IOC_MAGIC, 2,\
     69     struct sync_fence_info_data)
     70 
     71 /* SW Sync API */
     72 
     73 struct sw_sync_create_fence_data {
     74   __u32 value;
     75   char name[32];
     76   __s32 fence;
     77 };
     78 
     79 #define SW_SYNC_IOC_MAGIC 'W'
     80 #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
     81 #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
     82 
     83 // ---------------------------------------------------------------------------
     84 // Support for caching the sync uapi version.
     85 //
     86 // This library supports both legacy (android/staging) uapi and modern
     87 // (mainline) sync uapi. Library calls first try one uapi, and if that fails,
     88 // try the other. Since any given kernel only supports one uapi version, after
     89 // the first successful syscall we know what the kernel supports and can skip
     90 // trying the other.
     91 
     92 enum uapi_version {
     93     UAPI_UNKNOWN,
     94     UAPI_MODERN,
     95     UAPI_LEGACY
     96 };
     97 static atomic_int g_uapi_version = ATOMIC_VAR_INIT(UAPI_UNKNOWN);
     98 
     99 // ---------------------------------------------------------------------------
    100 
    101 int sync_wait(int fd, int timeout)
    102 {
    103     struct pollfd fds;
    104     int ret;
    105 
    106     if (fd < 0) {
    107         errno = EINVAL;
    108         return -1;
    109     }
    110 
    111     fds.fd = fd;
    112     fds.events = POLLIN;
    113 
    114     do {
    115         ret = poll(&fds, 1, timeout);
    116         if (ret > 0) {
    117             if (fds.revents & (POLLERR | POLLNVAL)) {
    118                 errno = EINVAL;
    119                 return -1;
    120             }
    121             return 0;
    122         } else if (ret == 0) {
    123             errno = ETIME;
    124             return -1;
    125         }
    126     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
    127 
    128     return ret;
    129 }
    130 
    131 static int legacy_sync_merge(const char *name, int fd1, int fd2)
    132 {
    133     struct sync_legacy_merge_data data;
    134     int ret;
    135 
    136     data.fd2 = fd2;
    137     strlcpy(data.name, name, sizeof(data.name));
    138     ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &data);
    139     if (ret < 0)
    140         return ret;
    141     return data.fence;
    142 }
    143 
    144 static int modern_sync_merge(const char *name, int fd1, int fd2)
    145 {
    146     struct sync_merge_data data;
    147     int ret;
    148 
    149     data.fd2 = fd2;
    150     strlcpy(data.name, name, sizeof(data.name));
    151     data.flags = 0;
    152     data.pad = 0;
    153 
    154     ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
    155     if (ret < 0)
    156         return ret;
    157     return data.fence;
    158 }
    159 
    160 int sync_merge(const char *name, int fd1, int fd2)
    161 {
    162     int uapi;
    163     int ret;
    164 
    165     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    166 
    167     if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
    168         ret = modern_sync_merge(name, fd1, fd2);
    169         if (ret >= 0 || errno != ENOTTY) {
    170             if (ret >= 0 && uapi == UAPI_UNKNOWN) {
    171                 atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    172                                       memory_order_release);
    173             }
    174             return ret;
    175         }
    176     }
    177 
    178     ret = legacy_sync_merge(name, fd1, fd2);
    179     if (ret >= 0 && uapi == UAPI_UNKNOWN) {
    180         atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    181                               memory_order_release);
    182     }
    183     return ret;
    184 }
    185 
    186 static struct sync_fence_info_data *legacy_sync_fence_info(int fd)
    187 {
    188     struct sync_fence_info_data *legacy_info;
    189     struct sync_pt_info *legacy_pt_info;
    190     int err;
    191 
    192     legacy_info = malloc(4096);
    193     if (legacy_info == NULL)
    194         return NULL;
    195 
    196     legacy_info->len = 4096;
    197     err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info);
    198     if (err < 0) {
    199         free(legacy_info);
    200         return NULL;
    201     }
    202     return legacy_info;
    203 }
    204 
    205 static struct sync_file_info *modern_sync_file_info(int fd)
    206 {
    207     struct sync_file_info local_info;
    208     struct sync_file_info *info;
    209     int err;
    210 
    211     memset(&local_info, 0, sizeof(local_info));
    212     err = ioctl(fd, SYNC_IOC_FILE_INFO, &local_info);
    213     if (err < 0)
    214         return NULL;
    215 
    216     info = calloc(1, sizeof(struct sync_file_info) +
    217                   local_info.num_fences * sizeof(struct sync_fence_info));
    218     if (!info)
    219         return NULL;
    220 
    221     info->num_fences = local_info.num_fences;
    222     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
    223 
    224     err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
    225     if (err < 0) {
    226         free(info);
    227         return NULL;
    228     }
    229 
    230     return info;
    231 }
    232 
    233 static struct sync_fence_info_data *sync_file_info_to_legacy_fence_info(
    234     const struct sync_file_info *info)
    235 {
    236     struct sync_fence_info_data *legacy_info;
    237     struct sync_pt_info *legacy_pt_info;
    238     const struct sync_fence_info *fence_info = sync_get_fence_info(info);
    239     const uint32_t num_fences = info->num_fences;
    240 
    241     legacy_info = malloc(4096);
    242     if (legacy_info == NULL)
    243         return NULL;
    244     legacy_info->len = sizeof(*legacy_info) +
    245                         num_fences * sizeof(struct sync_pt_info);
    246     strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
    247     legacy_info->status = info->status;
    248 
    249     legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
    250     for (uint32_t i = 0; i < num_fences; i++) {
    251         legacy_pt_info[i].len = sizeof(*legacy_pt_info);
    252         strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
    253                 sizeof(legacy_pt_info->obj_name));
    254         strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
    255                 sizeof(legacy_pt_info->driver_name));
    256         legacy_pt_info[i].status = fence_info[i].status;
    257         legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
    258     }
    259 
    260     return legacy_info;
    261 }
    262 
    263 static struct sync_file_info* legacy_fence_info_to_sync_file_info(
    264                                     struct sync_fence_info_data *legacy_info)
    265 {
    266     struct sync_file_info *info;
    267     struct sync_pt_info *pt;
    268     struct sync_fence_info *fence;
    269     size_t num_fences;
    270     int err;
    271 
    272     pt = NULL;
    273     num_fences = 0;
    274     while ((pt = sync_pt_info(legacy_info, pt)) != NULL)
    275         num_fences++;
    276 
    277     info = calloc(1, sizeof(struct sync_file_info) +
    278                      num_fences * sizeof(struct sync_fence_info));
    279     if (!info) {
    280         return NULL;
    281     }
    282     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
    283 
    284     strlcpy(info->name, legacy_info->name, sizeof(info->name));
    285     info->status = legacy_info->status;
    286     info->num_fences = num_fences;
    287 
    288     pt = NULL;
    289     fence = sync_get_fence_info(info);
    290     while ((pt = sync_pt_info(legacy_info, pt)) != NULL) {
    291         strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name));
    292         strlcpy(fence->driver_name, pt->driver_name,
    293                 sizeof(fence->driver_name));
    294         fence->status = pt->status;
    295         fence->timestamp_ns = pt->timestamp_ns;
    296         fence++;
    297     }
    298 
    299     return info;
    300 }
    301 
    302 struct sync_fence_info_data *sync_fence_info(int fd)
    303 {
    304     struct sync_fence_info_data *legacy_info;
    305     int uapi;
    306 
    307     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    308 
    309     if (uapi == UAPI_LEGACY || uapi == UAPI_UNKNOWN) {
    310         legacy_info = legacy_sync_fence_info(fd);
    311         if (legacy_info || errno != ENOTTY) {
    312             if (legacy_info && uapi == UAPI_UNKNOWN) {
    313                 atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    314                                       memory_order_release);
    315             }
    316             return legacy_info;
    317         }
    318     }
    319 
    320     struct sync_file_info* file_info;
    321     file_info = modern_sync_file_info(fd);
    322     if (!file_info)
    323         return NULL;
    324     if (uapi == UAPI_UNKNOWN) {
    325         atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    326                               memory_order_release);
    327     }
    328     legacy_info = sync_file_info_to_legacy_fence_info(file_info);
    329     sync_file_info_free(file_info);
    330     return legacy_info;
    331 }
    332 
    333 struct sync_file_info* sync_file_info(int32_t fd)
    334 {
    335     struct sync_file_info *info;
    336     int uapi;
    337 
    338     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    339 
    340     if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
    341         info = modern_sync_file_info(fd);
    342         if (info || errno != ENOTTY) {
    343             if (info && uapi == UAPI_UNKNOWN) {
    344                 atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    345                                       memory_order_release);
    346             }
    347             return info;
    348         }
    349     }
    350 
    351     struct sync_fence_info_data *legacy_info;
    352     legacy_info = legacy_sync_fence_info(fd);
    353     if (!legacy_info)
    354         return NULL;
    355     if (uapi == UAPI_UNKNOWN) {
    356         atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    357                               memory_order_release);
    358     }
    359     info = legacy_fence_info_to_sync_file_info(legacy_info);
    360     sync_fence_info_free(legacy_info);
    361     return info;
    362 }
    363 
    364 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
    365                                   struct sync_pt_info *itr)
    366 {
    367     if (itr == NULL)
    368         itr = (struct sync_pt_info *) info->pt_info;
    369     else
    370         itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
    371 
    372     if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
    373         return NULL;
    374 
    375     return itr;
    376 }
    377 
    378 void sync_fence_info_free(struct sync_fence_info_data *info)
    379 {
    380     free(info);
    381 }
    382 
    383 void sync_file_info_free(struct sync_file_info *info)
    384 {
    385     free(info);
    386 }
    387 
    388 
    389 int sw_sync_timeline_create(void)
    390 {
    391     int ret;
    392 
    393     ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
    394     if (ret < 0)
    395         ret = open("/dev/sw_sync", O_RDWR);
    396 
    397     return ret;
    398 }
    399 
    400 int sw_sync_timeline_inc(int fd, unsigned count)
    401 {
    402     __u32 arg = count;
    403 
    404     return ioctl(fd, SW_SYNC_IOC_INC, &arg);
    405 }
    406 
    407 int sw_sync_fence_create(int fd, const char *name, unsigned value)
    408 {
    409     struct sw_sync_create_fence_data data;
    410     int err;
    411 
    412     data.value = value;
    413     strlcpy(data.name, name, sizeof(data.name));
    414 
    415     err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
    416     if (err < 0)
    417         return err;
    418 
    419     return data.fence;
    420 }
    421