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 #include <linux/genlock.h>
     34 #include <fcntl.h>
     35 #include <sys/ioctl.h>
     36 
     37 #include "genlock.h"
     38 
     39 #define GENLOCK_DEVICE "/dev/genlock"
     40 
     41 namespace {
     42 /* Internal function to map the userspace locks to the kernel lock types */
     43     int get_kernel_lock_type(genlock_lock_type lockType)
     44     {
     45         int kLockType = 0;
     46 #ifdef USE_GENLOCK
     47         // If the user sets both a read and write lock, higher preference is
     48         // given to the write lock.
     49         if (lockType & GENLOCK_WRITE_LOCK) {
     50             kLockType = GENLOCK_WRLOCK;
     51         } else if (lockType & GENLOCK_READ_LOCK) {
     52             kLockType = GENLOCK_RDLOCK;
     53         } else {
     54             ALOGE("%s: invalid lockType (lockType = %d)",
     55                   __FUNCTION__, lockType);
     56             return -1;
     57         }
     58 #endif
     59         return kLockType;
     60     }
     61 
     62     /* Internal function to perform the actual lock/unlock operations */
     63     genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
     64                                                    int lockType, int timeout,
     65                                                    int flags)
     66     {
     67 #ifdef USE_GENLOCK
     68         if (private_handle_t::validate(buffer_handle)) {
     69             ALOGE("%s: handle is invalid", __FUNCTION__);
     70             return GENLOCK_FAILURE;
     71         }
     72 
     73         private_handle_t *hnd = reinterpret_cast<private_handle_t*>
     74                                 (buffer_handle);
     75         if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
     76             if (hnd->genlockPrivFd < 0) {
     77                 ALOGE("%s: the lock has not been created,"
     78                       "or has not been attached", __FUNCTION__);
     79                 return GENLOCK_FAILURE;
     80             }
     81 
     82             genlock_lock lock;
     83             lock.op = lockType;
     84             lock.flags = flags;
     85             lock.timeout = timeout;
     86             lock.fd = hnd->genlockHandle;
     87 
     88 #ifdef GENLOCK_IOC_DREADLOCK
     89             if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
     90                 ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
     91                        "err=%s fd=%d)", __FUNCTION__,
     92                       lockType, strerror(errno), hnd->fd);
     93                 if (ETIMEDOUT == errno)
     94                     return GENLOCK_TIMEDOUT;
     95 
     96                 return GENLOCK_FAILURE;
     97             }
     98 #else
     99             // depreciated
    100             if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
    101                 ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
    102                       ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
    103                 if (ETIMEDOUT == errno)
    104                     return GENLOCK_TIMEDOUT;
    105 
    106                 return GENLOCK_FAILURE;
    107             }
    108 #endif
    109         }
    110 #endif
    111         return GENLOCK_NO_ERROR;
    112     }
    113 
    114     /* Internal function to close the fd and release the handle */
    115     void close_genlock_fd_and_handle(int& fd, int& handle)
    116     {
    117         if (fd >=0 ) {
    118             close(fd);
    119             fd = -1;
    120         }
    121 
    122         if (handle >= 0) {
    123             close(handle);
    124             handle = -1;
    125         }
    126     }
    127 }
    128 /*
    129  * Create a genlock lock. The genlock lock file descriptor and the lock
    130  * handle are stored in the buffer_handle.
    131  *
    132  * @param: handle of the buffer
    133  * @return error status.
    134  */
    135 genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
    136 {
    137     genlock_status_t ret = GENLOCK_NO_ERROR;
    138 #ifdef USE_GENLOCK
    139     if (private_handle_t::validate(buffer_handle)) {
    140         ALOGE("%s: handle is invalid", __FUNCTION__);
    141         return GENLOCK_FAILURE;
    142     }
    143 
    144     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    145     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    146         // Open the genlock device
    147         int fd = open(GENLOCK_DEVICE, O_RDWR);
    148         if (fd < 0) {
    149             ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
    150                   strerror(errno));
    151             return GENLOCK_FAILURE;
    152         }
    153 
    154         // Create a new lock
    155         genlock_lock lock;
    156         if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
    157             ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
    158                   strerror(errno));
    159             close_genlock_fd_and_handle(fd, lock.fd);
    160             ret = GENLOCK_FAILURE;
    161         }
    162 
    163         // Export the lock for other processes to be able to use it.
    164         if (GENLOCK_FAILURE != ret) {
    165             if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
    166                 ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
    167                       strerror(errno));
    168                 close_genlock_fd_and_handle(fd, lock.fd);
    169                 ret = GENLOCK_FAILURE;
    170             }
    171         }
    172 
    173         // Store the lock params in the handle.
    174         hnd->genlockPrivFd = fd;
    175         hnd->genlockHandle = lock.fd;
    176     } else {
    177         hnd->genlockHandle = 0;
    178     }
    179 #endif
    180     return ret;
    181 }
    182 
    183 
    184 /*
    185  * Release a genlock lock associated with the handle.
    186  *
    187  * @param: handle of the buffer
    188  * @return error status.
    189  */
    190 genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
    191 {
    192     genlock_status_t ret = GENLOCK_NO_ERROR;
    193 #ifdef USE_GENLOCK
    194     if (private_handle_t::validate(buffer_handle)) {
    195         ALOGE("%s: handle is invalid", __FUNCTION__);
    196         return GENLOCK_FAILURE;
    197     }
    198 
    199     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    200     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    201         if (hnd->genlockPrivFd < 0) {
    202             ALOGE("%s: the lock is invalid", __FUNCTION__);
    203             return GENLOCK_FAILURE;
    204         }
    205 
    206         // Close the fd and reset the parameters.
    207         close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
    208     }
    209 #endif
    210     return ret;
    211 }
    212 
    213 
    214 /*
    215  * Attach a lock to the buffer handle passed via an IPC.
    216  *
    217  * @param: handle of the buffer
    218  * @return error status.
    219  */
    220 genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
    221 {
    222     genlock_status_t ret = GENLOCK_NO_ERROR;
    223 #ifdef USE_GENLOCK
    224     if (private_handle_t::validate(buffer_handle)) {
    225         ALOGE("%s: handle is invalid", __FUNCTION__);
    226         return GENLOCK_FAILURE;
    227     }
    228 
    229     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    230     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    231         // Open the genlock device
    232         int fd = open(GENLOCK_DEVICE, O_RDWR);
    233         if (fd < 0) {
    234             ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
    235                   strerror(errno));
    236             return GENLOCK_FAILURE;
    237         }
    238 
    239         // Attach the local handle to an existing lock
    240         genlock_lock lock;
    241         lock.fd = hnd->genlockHandle;
    242         if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
    243             ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
    244                   strerror(errno));
    245             close_genlock_fd_and_handle(fd, lock.fd);
    246             ret = GENLOCK_FAILURE;
    247         }
    248 
    249         // Store the relavant information in the handle
    250         hnd->genlockPrivFd = fd;
    251     }
    252 #endif
    253     return ret;
    254 }
    255 
    256 /*
    257  * Lock the buffer specified by the buffer handle. The lock held by the buffer
    258  * is specified by the lockType. This function will block if a write lock is
    259  * requested on the buffer which has previously been locked for a read or write
    260  * operation. A buffer can be locked by multiple clients for read. An optional
    261  * timeout value can be specified. By default, there is no timeout.
    262  *
    263  * @param: handle of the buffer
    264  * @param: type of lock to be acquired by the buffer.
    265  * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
    266  * @return error status.
    267  */
    268 genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
    269                                      genlock_lock_type_t lockType,
    270                                      int timeout)
    271 {
    272     genlock_status_t ret = GENLOCK_NO_ERROR;
    273 #ifdef USE_GENLOCK
    274     // Translate the locktype
    275     int kLockType = get_kernel_lock_type(lockType);
    276     if (-1 == kLockType) {
    277         ALOGE("%s: invalid lockType", __FUNCTION__);
    278         return GENLOCK_FAILURE;
    279     }
    280 
    281     if (0 == timeout) {
    282         ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
    283     }
    284     // Call the private function to perform the lock operation specified.
    285     ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
    286 #endif
    287     return ret;
    288 }
    289 
    290 
    291 /*
    292  * Unlocks a buffer that has previously been locked by the client.
    293  *
    294  * @param: handle of the buffer to be unlocked.
    295  * @return: error status.
    296  */
    297 genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
    298 {
    299     genlock_status_t ret = GENLOCK_NO_ERROR;
    300 #ifdef USE_GENLOCK
    301     // Do the unlock operation by setting the unlock flag. Timeout is always
    302     // 0 in this case.
    303     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
    304 #endif
    305     return ret;
    306 }
    307 
    308 /*
    309  * Blocks the calling process until the lock held on the handle is unlocked.
    310  *
    311  * @param: handle of the buffer
    312  * @param: timeout value for the wait.
    313  * return: error status.
    314  */
    315 genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
    316 #ifdef USE_GENLOCK
    317     if (private_handle_t::validate(buffer_handle)) {
    318         ALOGE("%s: handle is invalid", __FUNCTION__);
    319         return GENLOCK_FAILURE;
    320     }
    321 
    322     private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
    323     if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
    324         if (hnd->genlockPrivFd < 0) {
    325             ALOGE("%s: the lock is invalid", __FUNCTION__);
    326             return GENLOCK_FAILURE;
    327         }
    328 
    329         if (0 == timeout)
    330             ALOGW("%s: timeout = 0", __FUNCTION__);
    331 
    332         genlock_lock lock;
    333         lock.fd = hnd->genlockHandle;
    334         lock.timeout = timeout;
    335         if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
    336             ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)",  __FUNCTION__,
    337                   strerror(errno));
    338             return GENLOCK_FAILURE;
    339         }
    340     }
    341 #endif
    342     return GENLOCK_NO_ERROR;
    343 }
    344 
    345 /*
    346  * Convert a write lock that we own to a read lock
    347  *
    348  * @param: handle of the buffer
    349  * @param: timeout value for the wait.
    350  * return: error status.
    351  */
    352 genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
    353                                        int timeout) {
    354     genlock_status_t ret = GENLOCK_NO_ERROR;
    355 #ifdef USE_GENLOCK
    356     if (0 == timeout) {
    357         ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
    358     }
    359     // Call the private function to perform the lock operation specified.
    360 #ifdef GENLOCK_IOC_DREADLOCK
    361     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
    362                                         GENLOCK_WRITE_TO_READ);
    363 #else
    364     // depreciated
    365     ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
    366                                         timeout, 0);
    367 #endif
    368 #endif
    369     return ret;
    370 }
    371