semaphore.c revision 4f920f685bb4af8400c70383eecf347a35353778
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 34int 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 51int 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 65sem_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 75int 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 86int sem_unlink(const char * name) 87{ 88 errno = ENOSYS; 89 return -1; 90} 91 92 93static 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 106int 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 122int 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 178int 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 189int 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 204int 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