blob: f4eebce57fe06ba36e481fd52737222c27ea3dca [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>
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 {
David 'Digit' Turner294dd0b2010-02-12 12:18:37 -0800199 errno = EAGAIN;
200 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201 }
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}