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         free(legacy_info);
    281         return NULL;
    282     }
    283     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
    284 
    285     strlcpy(info->name, legacy_info->name, sizeof(info->name));
    286     info->status = legacy_info->status;
    287     info->num_fences = num_fences;
    288 
    289     pt = NULL;
    290     fence = sync_get_fence_info(info);
    291     while ((pt = sync_pt_info(legacy_info, pt)) != NULL) {
    292         strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name));
    293         strlcpy(fence->driver_name, pt->driver_name,
    294                 sizeof(fence->driver_name));
    295         fence->status = pt->status;
    296         fence->timestamp_ns = pt->timestamp_ns;
    297         fence++;
    298     }
    299 
    300     return info;
    301 }
    302 
    303 struct sync_fence_info_data *sync_fence_info(int fd)
    304 {
    305     struct sync_fence_info_data *legacy_info;
    306     int uapi;
    307 
    308     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    309 
    310     if (uapi == UAPI_LEGACY || uapi == UAPI_UNKNOWN) {
    311         legacy_info = legacy_sync_fence_info(fd);
    312         if (legacy_info || errno != ENOTTY) {
    313             if (legacy_info && uapi == UAPI_UNKNOWN) {
    314                 atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    315                                       memory_order_release);
    316             }
    317             return legacy_info;
    318         }
    319     }
    320 
    321     struct sync_file_info* file_info;
    322     file_info = modern_sync_file_info(fd);
    323     if (!file_info)
    324         return NULL;
    325     if (uapi == UAPI_UNKNOWN) {
    326         atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    327                               memory_order_release);
    328     }
    329     legacy_info = sync_file_info_to_legacy_fence_info(file_info);
    330     sync_file_info_free(file_info);
    331     return legacy_info;
    332 }
    333 
    334 struct sync_file_info* sync_file_info(int32_t fd)
    335 {
    336     struct sync_file_info *info;
    337     int uapi;
    338 
    339     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    340 
    341     if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
    342         info = modern_sync_file_info(fd);
    343         if (info || errno != ENOTTY) {
    344             if (info && uapi == UAPI_UNKNOWN) {
    345                 atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    346                                       memory_order_release);
    347             }
    348             return info;
    349         }
    350     }
    351 
    352     struct sync_fence_info_data *legacy_info;
    353     legacy_info = legacy_sync_fence_info(fd);
    354     if (!legacy_info)
    355         return NULL;
    356     if (uapi == UAPI_UNKNOWN) {
    357         atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    358                               memory_order_release);
    359     }
    360     info = legacy_fence_info_to_sync_file_info(legacy_info);
    361     sync_fence_info_free(legacy_info);
    362     return info;
    363 }
    364 
    365 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
    366                                   struct sync_pt_info *itr)
    367 {
    368     if (itr == NULL)
    369         itr = (struct sync_pt_info *) info->pt_info;
    370     else
    371         itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
    372 
    373     if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
    374         return NULL;
    375 
    376     return itr;
    377 }
    378 
    379 void sync_fence_info_free(struct sync_fence_info_data *info)
    380 {
    381     free(info);
    382 }
    383 
    384 void sync_file_info_free(struct sync_file_info *info)
    385 {
    386     free(info);
    387 }
    388 
    389 
    390 int sw_sync_timeline_create(void)
    391 {
    392     int ret;
    393 
    394     ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
    395     if (ret < 0)
    396         ret = open("/dev/sw_sync", O_RDWR);
    397 
    398     return ret;
    399 }
    400 
    401 int sw_sync_timeline_inc(int fd, unsigned count)
    402 {
    403     __u32 arg = count;
    404 
    405     return ioctl(fd, SW_SYNC_IOC_INC, &arg);
    406 }
    407 
    408 int sw_sync_fence_create(int fd, const char *name, unsigned value)
    409 {
    410     struct sw_sync_create_fence_data data;
    411     int err;
    412 
    413     data.value = value;
    414     strlcpy(data.name, name, sizeof(data.name));
    415 
    416     err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
    417     if (err < 0)
    418         return err;
    419 
    420     return data.fence;
    421 }
    422