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     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
    221 
    222     err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
    223     if (err < 0) {
    224         free(info);
    225         return NULL;
    226     }
    227 
    228     return info;
    229 }
    230 
    231 static struct sync_fence_info_data *sync_file_info_to_legacy_fence_info(
    232     const struct sync_file_info *info)
    233 {
    234     struct sync_fence_info_data *legacy_info;
    235     struct sync_pt_info *legacy_pt_info;
    236     const struct sync_fence_info *fence_info = sync_get_fence_info(info);
    237     const uint32_t num_fences = info->num_fences;
    238 
    239     legacy_info = malloc(4096);
    240     if (legacy_info == NULL)
    241         return NULL;
    242     legacy_info->len = sizeof(*legacy_info) +
    243                         num_fences * sizeof(struct sync_pt_info);
    244     strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
    245     legacy_info->status = info->status;
    246 
    247     legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
    248     for (uint32_t i = 0; i < num_fences; i++) {
    249         legacy_pt_info[i].len = sizeof(*legacy_pt_info);
    250         strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
    251                 sizeof(legacy_pt_info->obj_name));
    252         strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
    253                 sizeof(legacy_pt_info->driver_name));
    254         legacy_pt_info[i].status = fence_info[i].status;
    255         legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
    256     }
    257 
    258     return legacy_info;
    259 }
    260 
    261 static struct sync_file_info* legacy_fence_info_to_sync_file_info(
    262                                     struct sync_fence_info_data *legacy_info)
    263 {
    264     struct sync_file_info *info;
    265     struct sync_pt_info *pt;
    266     struct sync_fence_info *fence;
    267     size_t num_fences;
    268     int err;
    269 
    270     pt = NULL;
    271     num_fences = 0;
    272     while ((pt = sync_pt_info(legacy_info, pt)) != NULL)
    273         num_fences++;
    274 
    275     info = calloc(1, sizeof(struct sync_file_info) +
    276                      num_fences * sizeof(struct sync_fence_info));
    277     if (!info) {
    278         free(legacy_info);
    279         return NULL;
    280     }
    281     info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
    282 
    283     strlcpy(info->name, legacy_info->name, sizeof(info->name));
    284     info->status = legacy_info->status;
    285     info->num_fences = num_fences;
    286 
    287     pt = NULL;
    288     fence = sync_get_fence_info(info);
    289     while ((pt = sync_pt_info(legacy_info, pt)) != NULL) {
    290         strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name));
    291         strlcpy(fence->driver_name, pt->driver_name,
    292                 sizeof(fence->driver_name));
    293         fence->status = pt->status;
    294         fence->timestamp_ns = pt->timestamp_ns;
    295         fence++;
    296     }
    297 
    298     return info;
    299 }
    300 
    301 struct sync_fence_info_data *sync_fence_info(int fd)
    302 {
    303     struct sync_fence_info_data *legacy_info;
    304     int uapi;
    305 
    306     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    307 
    308     if (uapi == UAPI_LEGACY || uapi == UAPI_UNKNOWN) {
    309         legacy_info = legacy_sync_fence_info(fd);
    310         if (legacy_info || errno != ENOTTY) {
    311             if (legacy_info && uapi == UAPI_UNKNOWN) {
    312                 atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    313                                       memory_order_release);
    314             }
    315             return legacy_info;
    316         }
    317     }
    318 
    319     struct sync_file_info* file_info;
    320     file_info = modern_sync_file_info(fd);
    321     if (!file_info)
    322         return NULL;
    323     if (uapi == UAPI_UNKNOWN) {
    324         atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    325                               memory_order_release);
    326     }
    327     legacy_info = sync_file_info_to_legacy_fence_info(file_info);
    328     sync_file_info_free(file_info);
    329     return legacy_info;
    330 }
    331 
    332 struct sync_file_info* sync_file_info(int32_t fd)
    333 {
    334     struct sync_file_info *info;
    335     int uapi;
    336 
    337     uapi = atomic_load_explicit(&g_uapi_version, memory_order_acquire);
    338 
    339     if (uapi == UAPI_MODERN || uapi == UAPI_UNKNOWN) {
    340         info = modern_sync_file_info(fd);
    341         if (info || errno != ENOTTY) {
    342             if (info && uapi == UAPI_UNKNOWN) {
    343                 atomic_store_explicit(&g_uapi_version, UAPI_MODERN,
    344                                       memory_order_release);
    345             }
    346             return info;
    347         }
    348     }
    349 
    350     struct sync_fence_info_data *legacy_info;
    351     legacy_info = legacy_sync_fence_info(fd);
    352     if (!legacy_info)
    353         return NULL;
    354     if (uapi == UAPI_UNKNOWN) {
    355         atomic_store_explicit(&g_uapi_version, UAPI_LEGACY,
    356                               memory_order_release);
    357     }
    358     info = legacy_fence_info_to_sync_file_info(legacy_info);
    359     sync_fence_info_free(legacy_info);
    360     return info;
    361 }
    362 
    363 struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
    364                                   struct sync_pt_info *itr)
    365 {
    366     if (itr == NULL)
    367         itr = (struct sync_pt_info *) info->pt_info;
    368     else
    369         itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
    370 
    371     if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
    372         return NULL;
    373 
    374     return itr;
    375 }
    376 
    377 void sync_fence_info_free(struct sync_fence_info_data *info)
    378 {
    379     free(info);
    380 }
    381 
    382 void sync_file_info_free(struct sync_file_info *info)
    383 {
    384     free(info);
    385 }
    386 
    387 
    388 int sw_sync_timeline_create(void)
    389 {
    390     int ret;
    391 
    392     ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
    393     if (ret < 0)
    394         ret = open("/dev/sw_sync", O_RDWR);
    395 
    396     return ret;
    397 }
    398 
    399 int sw_sync_timeline_inc(int fd, unsigned count)
    400 {
    401     __u32 arg = count;
    402 
    403     return ioctl(fd, SW_SYNC_IOC_INC, &arg);
    404 }
    405 
    406 int sw_sync_fence_create(int fd, const char *name, unsigned value)
    407 {
    408     struct sw_sync_create_fence_data data;
    409     int err;
    410 
    411     data.value = value;
    412     strlcpy(data.name, name, sizeof(data.name));
    413 
    414     err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
    415     if (err < 0)
    416         return err;
    417 
    418     return data.fence;
    419 }
    420