blob: b624943f96943664d2fbd9058c0b72f3f7ac636a [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
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>
Andy McFaddenfcd00eb2010-05-28 13:31:45 -070033#include <cutils/atomic-inline.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034
35int sem_init(sem_t *sem, int pshared, unsigned int value)
36{
37 if (sem == NULL) {
38 errno = EINVAL;
39 return -1;
40 }
41
42 if (pshared != 0) {
43 errno = ENOSYS;
44 return -1;
45 }
46
47 sem->count = value;
48 return 0;
49}
50
51
52int sem_destroy(sem_t *sem)
53{
54 if (sem == NULL) {
55 errno = EINVAL;
56 return -1;
57 }
58 if (sem->count == 0) {
59 errno = EBUSY;
60 return -1;
61 }
62 return 0;
63}
64
65
66sem_t *sem_open(const char *name, int oflag, ...)
67{
68 name=name;
69 oflag=oflag;
70
71 errno = ENOSYS;
72 return SEM_FAILED;
73}
74
75
76int sem_close(sem_t *sem)
77{
78 if (sem == NULL) {
79 errno = EINVAL;
80 return -1;
81 }
82 errno = ENOSYS;
83 return -1;
84}
85
86
87int sem_unlink(const char * name)
88{
89 errno = ENOSYS;
90 return -1;
91}
92
93
94static int
95__atomic_dec_if_positive( volatile unsigned int* pvalue )
96{
97 unsigned int old;
98
99 do {
100 old = *pvalue;
101 }
102 while ( old != 0 && __atomic_cmpxchg( (int)old, (int)old-1, (volatile int*)pvalue ) != 0 );
103
104 return old;
105}
106
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700107/* lock a semaphore */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800108int sem_wait(sem_t *sem)
109{
110 if (sem == NULL) {
111 errno = EINVAL;
112 return -1;
113 }
114
115 for (;;) {
116 if (__atomic_dec_if_positive(&sem->count))
117 break;
118
119 __futex_wait(&sem->count, 0, 0);
120 }
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700121 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800122 return 0;
123}
124
125int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
126{
127 int ret;
128
129 if (sem == NULL) {
130 errno = EINVAL;
131 return -1;
132 }
133
134 /* POSIX says we need to try to decrement the semaphore
135 * before checking the timeout value */
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700136 if (__atomic_dec_if_positive(&sem->count)) {
137 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800138 return 0;
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700139 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800140
141 /* check it as per Posix */
142 if (abs_timeout == NULL ||
143 abs_timeout->tv_sec < 0 ||
144 abs_timeout->tv_nsec < 0 ||
145 abs_timeout->tv_nsec >= 1000000000)
146 {
147 errno = EINVAL;
148 return -1;
149 }
150
151 for (;;) {
152 struct timespec ts;
153 int ret;
154
155 /* Posix mandates CLOCK_REALTIME here */
156 clock_gettime( CLOCK_REALTIME, &ts );
157 ts.tv_sec = abs_timeout->tv_sec - ts.tv_sec;
158 ts.tv_nsec = abs_timeout->tv_nsec - ts.tv_nsec;
159 if (ts.tv_nsec < 0) {
160 ts.tv_nsec += 1000000000;
161 ts.tv_sec -= 1;
162 }
163
164 if (ts.tv_sec < 0 || ts.tv_nsec < 0) {
165 errno = ETIMEDOUT;
166 return -1;
167 }
168
169 ret = __futex_wait(&sem->count, 0, &ts);
170
171 /* return in case of timeout or interrupt */
172 if (ret == -ETIMEDOUT || ret == -EINTR) {
173 errno = -ret;
174 return -1;
175 }
176
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700177 if (__atomic_dec_if_positive(&sem->count)) {
178 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800179 break;
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700180 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800181 }
182 return 0;
183}
184
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700185/* unlock a semaphore */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186int sem_post(sem_t *sem)
187{
188 if (sem == NULL)
189 return EINVAL;
190
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700191 ANDROID_MEMBAR_FULL();
David 'Digit' Turner4f920f62010-02-12 12:50:32 -0800192 if (__atomic_inc((volatile int*)&sem->count) >= 0)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800193 __futex_wake(&sem->count, 1);
194
195 return 0;
196}
197
198int sem_trywait(sem_t *sem)
199{
200 if (sem == NULL) {
201 errno = EINVAL;
202 return -1;
203 }
204
205 if (__atomic_dec_if_positive(&sem->count) > 0) {
Andy McFaddenfcd00eb2010-05-28 13:31:45 -0700206 ANDROID_MEMBAR_FULL();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800207 return 0;
208 } else {
David 'Digit' Turner294dd0b2010-02-12 12:18:37 -0800209 errno = EAGAIN;
210 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800211 }
212}
213
214int sem_getvalue(sem_t *sem, int *sval)
215{
216 if (sem == NULL || sval == NULL) {
217 errno = EINVAL;
218 return -1;
219 }
220
221 *sval = sem->count;
222 return 0;
223}