Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 #include <semaphore.h>
     29 #include <errno.h>
     30 #include <sys/time.h>
     31 #include <sys/atomics.h>
     32 #include <time.h>
     33 
     34 int sem_init(sem_t *sem, int pshared, unsigned int value)
     35 {
     36     if (sem == NULL) {
     37         errno = EINVAL;
     38         return -1;
     39     }
     40 
     41     if (pshared != 0) {
     42         errno = ENOSYS;
     43         return -1;
     44     }
     45 
     46     sem->count = value;
     47     return 0;
     48 }
     49 
     50 
     51 int sem_destroy(sem_t *sem)
     52 {
     53     if (sem == NULL) {
     54         errno = EINVAL;
     55         return -1;
     56     }
     57     if (sem->count == 0) {
     58         errno = EBUSY;
     59         return -1;
     60     }
     61     return 0;
     62 }
     63 
     64 
     65 sem_t *sem_open(const char *name, int oflag, ...)
     66 {
     67     name=name;
     68     oflag=oflag;
     69 
     70     errno = ENOSYS;
     71     return SEM_FAILED;
     72 }
     73 
     74 
     75 int sem_close(sem_t *sem)
     76 {
     77     if (sem == NULL) {
     78         errno = EINVAL;
     79         return -1;
     80     }
     81     errno = ENOSYS;
     82     return -1;
     83 }
     84 
     85 
     86 int sem_unlink(const char * name)
     87 {
     88     errno = ENOSYS;
     89     return -1;
     90 }
     91 
     92 
     93 static int
     94 __atomic_dec_if_positive( volatile unsigned int*  pvalue )
     95 {
     96     unsigned int  old;
     97 
     98     do {
     99         old = *pvalue;
    100     }
    101     while ( old != 0 && __atomic_cmpxchg( (int)old, (int)old-1, (volatile int*)pvalue ) != 0 );
    102 
    103     return old;
    104 }
    105 
    106 int sem_wait(sem_t *sem)
    107 {
    108     if (sem == NULL) {
    109         errno = EINVAL;
    110         return -1;
    111     }
    112 
    113     for (;;) {
    114         if (__atomic_dec_if_positive(&sem->count))
    115             break;
    116 
    117         __futex_wait(&sem->count, 0, 0);
    118     }
    119     return 0;
    120 }
    121 
    122 int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
    123 {
    124     int  ret;
    125 
    126     if (sem == NULL) {
    127         errno = EINVAL;
    128         return -1;
    129     }
    130 
    131     /* POSIX says we need to try to decrement the semaphore
    132      * before checking the timeout value */
    133     if (__atomic_dec_if_positive(&sem->count))
    134         return 0;
    135 
    136     /* check it as per Posix */
    137     if (abs_timeout == NULL    ||
    138         abs_timeout->tv_sec < 0 ||
    139         abs_timeout->tv_nsec < 0 ||
    140         abs_timeout->tv_nsec >= 1000000000)
    141     {
    142         errno = EINVAL;
    143         return -1;
    144     }
    145 
    146     for (;;) {
    147         struct timespec ts;
    148         int             ret;
    149 
    150         /* Posix mandates CLOCK_REALTIME here */
    151         clock_gettime( CLOCK_REALTIME, &ts );
    152         ts.tv_sec  = abs_timeout->tv_sec - ts.tv_sec;
    153         ts.tv_nsec = abs_timeout->tv_nsec - ts.tv_nsec;
    154         if (ts.tv_nsec < 0) {
    155             ts.tv_nsec += 1000000000;
    156             ts.tv_sec  -= 1;
    157         }
    158 
    159         if (ts.tv_sec < 0 || ts.tv_nsec < 0) {
    160             errno = ETIMEDOUT;
    161             return -1;
    162         }
    163 
    164         ret = __futex_wait(&sem->count, 0, &ts);
    165 
    166         /* return in case of timeout or interrupt */
    167         if (ret == -ETIMEDOUT || ret == -EINTR) {
    168             errno = -ret;
    169             return -1;
    170         }
    171 
    172         if (__atomic_dec_if_positive(&sem->count))
    173             break;
    174     }
    175     return 0;
    176 }
    177 
    178 int sem_post(sem_t *sem)
    179 {
    180     if (sem == NULL)
    181         return EINVAL;
    182 
    183     if (__atomic_inc((volatile int*)&sem->count) >= 0)
    184         __futex_wake(&sem->count, 1);
    185 
    186     return 0;
    187 }
    188 
    189 int  sem_trywait(sem_t *sem)
    190 {
    191     if (sem == NULL) {
    192         errno = EINVAL;
    193         return -1;
    194     }
    195 
    196     if (__atomic_dec_if_positive(&sem->count) > 0) {
    197         return 0;
    198     } else {
    199         errno = EAGAIN;
    200         return -1;
    201     }
    202 }
    203 
    204 int  sem_getvalue(sem_t *sem, int *sval)
    205 {
    206     if (sem == NULL || sval == NULL) {
    207         errno = EINVAL;
    208         return -1;
    209     }
    210 
    211     *sval = sem->count;
    212     return 0;
    213 }
    214