Home | History | Annotate | Download | only in libgenlock
      1 /*
      2  * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
      3 
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *   * Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  *   * Redistributions in binary form must reproduce the above
     10  *     copyright notice, this list of conditions and the following
     11  *     disclaimer in the documentation and/or other materials provided
     12  *     with the distribution.
     13  *   * Neither the name of The Linux Foundation nor the names of its
     14  *     contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <cutils/log.h>
     31 #include <cutils/native_handle.h>
     32 #include <gralloc_priv.h>
     33 #ifdef USE_GENLOCK
     34 #include <linux/genlock.h>
     35 #endif
     36 #include <fcntl.h>
     37 #include <sys/ioctl.h>
     38 
     39 #include "genlock.h"
     40 
     41 #define GENLOCK_DEVICE "/dev/genlock"
     42 
     43 namespace {
     44 /* Internal function to map the userspace locks to the kernel lock types */
     45     int get_kernel_lock_type(genlock_lock_type lockType)
     46     {
     47         int kLockType = 0;
     48 #ifdef USE_GENLOCK
     49         // If the user sets both a read and write lock, higher preference is
     50         // given to the write lock.
     51         if (lockType & GENLOCK_WRITE_LOCK) {
     52             kLockType = GENLOCK_WRLOCK;
     53         } else if (lockType & GENLOCK_READ_LOCK) {
     54             kLockType = GENLOCK_RDLOCK;
     55         } else {
     56             ALOGE("%s: invalid lockType (lockType = %d)",
     57                   __FUNCTION__, lockType);
     58             return -1;
     59         }
     60 #endif
     61         return kLockType;
     62     }
     63 
     64     /* Internal function to perform the actual lock/unlock operations */
     65     genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
     66                                                    int lockType, int timeout,
     67                                                    int flags)
     68     {
     69 #ifdef USE_GENLOCK
     70         if (private_handle_t::validate(buffer_handle)) {
     71             ALOGE("%s: handle is invalid", __FUNCTION__);
     72             return GENLOCK_FAILURE;
     73         }
     74 
     75         private_handle_t *hnd = reinterpret_cast<private_handle_t*>
     76                                 (buffer_handle);
     77         if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
     78             if (hnd->genlockPrivFd < 0) {
     79                 ALOGE("%s: the lock has not been created,"
     80                       "or has not been attached", __FUNCTION__);
     81                 return GENLOCK_FAILURE;
     82             }
     83 
     84             genlock_lock lock;
     85             lock.op = lockType;
     86             lock.flags = flags;
     87             lock.timeout = timeout;
     88             lock.fd = hnd->genlockHandle;
     89 
     90 #ifdef GENLOCK_IOC_DREADLOCK
     91             if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
     92                 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
     93                        "err=%s fd=%d)", __FUNCTION__,
     94                       lockType, strerror(errno), hnd->fd);
     95                 if (ETIMEDOUT == errno)
     96                     return GENLOCK_TIMEDOUT;
     97 
     98                 return GENLOCK_FAILURE;
     99             }
    100 #else
    101             // depreciated
    102             if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
    103                 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
    104                       ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
    105                 if (ETIMEDOUT == errno)
    106                     return GENLOCK_TIMEDOUT;
    107 
    108                 return GENLOCK_FAILURE;
    109             }
    110 #endif
    111         }
    112 #endif
    113         return GENLOCK_NO_ERROR;
    114     }
    115 
    116     /* Internal function to close the fd and release the handle */
    117     void close_genlock_fd_and_handle(int& fd, int& handle)
    118     {
    119         if (fd >=0 ) {
    120             close(fd);
    121             fd = -1;
    122         }
    123 
    124         if (handle >= 0) {
    125             close(handle);
    126             handle = -1;
    127         }
    128     }
    129 }
    130 /*
    131  * Create a genlock lock. The genlock lock file descriptor and the lock
    132  * handle are stored in the buffer_handle.
    133  *
    134  * @param: handle of the buffer
    135  * @return error status.
    136  */
    137 genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
    138 {
    139     genlock_status_t ret = GENLOCK_NO_ERROR;
    140 #ifdef USE_GENLOCK
    141     if (private_handle_t::validate(buffer_handle)) {
    142         ALOGE("%s: handle is invalid", __FUNCTION__);
    143         return GENLOCK_FAILURE;
    144     }
    145 
    146     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    147     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    148         // Open the genlock device
    149         int fd = open(GENLOCK_DEVICE, O_RDWR);
    150         if (fd < 0) {
    151             ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
    152                   strerror(errno));
    153             return GENLOCK_FAILURE;
    154         }
    155 
    156         // Create a new lock
    157         genlock_lock lock;
    158         if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
    159             ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
    160                   strerror(errno));
    161             close_genlock_fd_and_handle(fd, lock.fd);
    162             ret = GENLOCK_FAILURE;
    163         }
    164 
    165         // Export the lock for other processes to be able to use it.
    166         if (GENLOCK_FAILURE != ret) {
    167             if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
    168                 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
    169                       strerror(errno));
    170                 close_genlock_fd_and_handle(fd, lock.fd);
    171                 ret = GENLOCK_FAILURE;
    172             }
    173         }
    174 
    175         // Store the lock params in the handle.
    176         hnd->genlockPrivFd = fd;
    177         hnd->genlockHandle = lock.fd;
    178     } else {
    179         hnd->genlockHandle = 0;
    180     }
    181 #endif
    182     return ret;
    183 }
    184 
    185 
    186 /*
    187  * Release a genlock lock associated with the handle.
    188  *
    189  * @param: handle of the buffer
    190  * @return error status.
    191  */
    192 genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
    193 {
    194     genlock_status_t ret = GENLOCK_NO_ERROR;
    195 #ifdef USE_GENLOCK
    196     if (private_handle_t::validate(buffer_handle)) {
    197         ALOGE("%s: handle is invalid", __FUNCTION__);
    198         return GENLOCK_FAILURE;
    199     }
    200 
    201     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    202     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    203         if (hnd->genlockPrivFd < 0) {
    204             ALOGE("%s: the lock is invalid", __FUNCTION__);
    205             return GENLOCK_FAILURE;
    206         }
    207 
    208         // Close the fd and reset the parameters.
    209         close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
    210     }
    211 #endif
    212     return ret;
    213 }
    214 
    215 
    216 /*
    217  * Attach a lock to the buffer handle passed via an IPC.
    218  *
    219  * @param: handle of the buffer
    220  * @return error status.
    221  */
    222 genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
    223 {
    224     genlock_status_t ret = GENLOCK_NO_ERROR;
    225 #ifdef USE_GENLOCK
    226     if (private_handle_t::validate(buffer_handle)) {
    227         ALOGE("%s: handle is invalid", __FUNCTION__);
    228         return GENLOCK_FAILURE;
    229     }
    230 
    231     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    232     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    233         // Open the genlock device
    234         int fd = open(GENLOCK_DEVICE, O_RDWR);
    235         if (fd < 0) {
    236             ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
    237                   strerror(errno));
    238             return GENLOCK_FAILURE;
    239         }
    240 
    241         // Attach the local handle to an existing lock
    242         genlock_lock lock;
    243         lock.fd = hnd->genlockHandle;
    244         if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
    245             ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
    246                   strerror(errno));
    247             close_genlock_fd_and_handle(fd, lock.fd);
    248             ret = GENLOCK_FAILURE;
    249         }
    250 
    251         // Store the relavant information in the handle
    252         hnd->genlockPrivFd = fd;
    253     }
    254 #endif
    255     return ret;
    256 }
    257 
    258 /*
    259  * Lock the buffer specified by the buffer handle. The lock held by the buffer
    260  * is specified by the lockType. This function will block if a write lock is
    261  * requested on the buffer which has previously been locked for a read or write
    262  * operation. A buffer can be locked by multiple clients for read. An optional
    263  * timeout value can be specified. By default, there is no timeout.
    264  *
    265  * @param: handle of the buffer
    266  * @param: type of lock to be acquired by the buffer.
    267  * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
    268  * @return error status.
    269  */
    270 genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
    271                                      genlock_lock_type_t lockType,
    272                                      int timeout)
    273 {
    274     genlock_status_t ret = GENLOCK_NO_ERROR;
    275 #ifdef USE_GENLOCK
    276     // Translate the locktype
    277     int kLockType = get_kernel_lock_type(lockType);
    278     if (-1 == kLockType) {
    279         ALOGE("%s: invalid lockType", __FUNCTION__);
    280         return GENLOCK_FAILURE;
    281     }
    282 
    283     if (0 == timeout) {
    284         ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
    285     }
    286     // Call the private function to perform the lock operation specified.
    287     ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
    288 #endif
    289     return ret;
    290 }
    291 
    292 
    293 /*
    294  * Unlocks a buffer that has previously been locked by the client.
    295  *
    296  * @param: handle of the buffer to be unlocked.
    297  * @return: error status.
    298  */
    299 genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
    300 {
    301     genlock_status_t ret = GENLOCK_NO_ERROR;
    302 #ifdef USE_GENLOCK
    303     // Do the unlock operation by setting the unlock flag. Timeout is always
    304     // 0 in this case.
    305     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
    306 #endif
    307     return ret;
    308 }
    309 
    310 /*
    311  * Blocks the calling process until the lock held on the handle is unlocked.
    312  *
    313  * @param: handle of the buffer
    314  * @param: timeout value for the wait.
    315  * return: error status.
    316  */
    317 genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
    318 #ifdef USE_GENLOCK
    319     if (private_handle_t::validate(buffer_handle)) {
    320         ALOGE("%s: handle is invalid", __FUNCTION__);
    321         return GENLOCK_FAILURE;
    322     }
    323 
    324     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    325     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    326         if (hnd->genlockPrivFd < 0) {
    327             ALOGE("%s: the lock is invalid", __FUNCTION__);
    328             return GENLOCK_FAILURE;
    329         }
    330 
    331         if (0 == timeout)
    332             ALOGW("%s: timeout = 0", __FUNCTION__);
    333 
    334         genlock_lock lock;
    335         lock.fd = hnd->genlockHandle;
    336         lock.timeout = timeout;
    337         if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
    338             ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)",  __FUNCTION__,
    339                   strerror(errno));
    340             return GENLOCK_FAILURE;
    341         }
    342     }
    343 #endif
    344     return GENLOCK_NO_ERROR;
    345 }
    346 
    347 /*
    348  * Convert a write lock that we own to a read lock
    349  *
    350  * @param: handle of the buffer
    351  * @param: timeout value for the wait.
    352  * return: error status.
    353  */
    354 genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
    355                                        int timeout) {
    356     genlock_status_t ret = GENLOCK_NO_ERROR;
    357 #ifdef USE_GENLOCK
    358     if (0 == timeout) {
    359         ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
    360     }
    361     // Call the private function to perform the lock operation specified.
    362 #ifdef GENLOCK_IOC_DREADLOCK
    363     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
    364                                         GENLOCK_WRITE_TO_READ);
    365 #else
    366     // depreciated
    367     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
    368                                         timeout, 0);
    369 #endif
    370 #endif
    371     return ret;
    372 }
    373