revert between 56095 -> 55830 in arch
[AROS.git] / compiler / pthread / semaphore.c
blobda28dc877999516062f4659f1e8a09a9c91754f4
1 /*
2 Copyright (C) 2015 Szilard Biro
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
21 #include <proto/exec.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
26 #include "semaphore.h"
27 #include "debug.h"
29 #ifndef EOVERFLOW
30 #define EOVERFLOW EINVAL
31 #endif
33 static struct List semaphores;
34 static struct SignalSemaphore sema_sem;
35 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
37 static void _Init_Semaphore(void)
39 DB2(bug("%s()\n", __FUNCTION__));
41 InitSemaphore(&sema_sem);
42 NEWLIST(&semaphores);
45 sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value)
47 sem_t *sem;
49 D(bug("%s(%s, %d, %u, %u)\n", __FUNCTION__, name, oflag, mode, value));
51 pthread_once(&once_control, _Init_Semaphore);
53 if (name == NULL)
55 errno = EINVAL;
56 return SEM_FAILED;
59 ObtainSemaphore(&sema_sem);
60 sem = (sem_t *)FindName(&semaphores, (STRPTR)name);
61 if (sem != NULL)
63 if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
65 ReleaseSemaphore(&sema_sem);
66 errno = EEXIST;
67 return SEM_FAILED;
70 else
72 if (!(oflag & O_CREAT))
74 ReleaseSemaphore(&sema_sem);
75 errno = ENOENT;
76 return SEM_FAILED;
79 sem = malloc(sizeof(sem_t));
80 if (sem == NULL)
82 ReleaseSemaphore(&sema_sem);
83 errno = ENOMEM;
84 return SEM_FAILED;
87 if (sem_init(sem, 0, value))
89 free(sem);
90 ReleaseSemaphore(&sema_sem);
91 return SEM_FAILED;
93 // TODO: this string should be duplicated
94 sem->node.ln_Name = (char *)name;
95 AddTail(&semaphores, (struct Node *)sem);
97 ReleaseSemaphore(&sema_sem);
99 return sem;
102 int sem_close(sem_t *sem)
104 D(bug("%s(%p)\n", __FUNCTION__, sem));
106 return 0;
109 int sem_unlink(const char *name)
111 sem_t *sem;
113 D(bug("%s(%s)\n", __FUNCTION__, name));
115 pthread_once(&once_control, _Init_Semaphore);
117 if (name == NULL)
119 errno = EINVAL;
120 return -1;
123 ObtainSemaphore(&sema_sem);
124 sem = (sem_t *)FindName(&semaphores, (STRPTR)name);
126 if (sem == NULL)
128 ReleaseSemaphore(&sema_sem);
129 errno = ENOENT;
130 return -1;
133 if (sem_destroy(sem) != 0)
135 ReleaseSemaphore(&sema_sem);
136 return -1;
139 Remove((struct Node *)sem);
140 free(sem);
141 ReleaseSemaphore(&sema_sem);
143 return 0;
146 int sem_init(sem_t *sem, int pshared, unsigned int value)
148 D(bug("%s(%p, %d, %u)\n", __FUNCTION__, sem, pshared, value));
150 if (sem == NULL || value > (unsigned int)SEM_VALUE_MAX)
152 errno = EINVAL;
153 return -1;
156 sem->value = value;
157 sem->waiters_count = 0;
158 pthread_mutex_init(&sem->lock, NULL);
159 pthread_cond_init(&sem->count_nonzero, NULL);
161 return 0;
164 int sem_destroy(sem_t *sem)
166 D(bug("%s(%p)\n", __FUNCTION__, sem));
168 if (sem == NULL)
170 errno = EINVAL;
171 return -1;
174 if (pthread_mutex_trylock(&sem->lock) != 0)
176 errno = EBUSY;
177 return -1;
180 pthread_mutex_unlock(&sem->lock);
181 pthread_mutex_destroy(&sem->lock);
182 pthread_cond_destroy(&sem->count_nonzero);
183 sem->value = sem->waiters_count = 0;
185 return 0;
188 int sem_trywait(sem_t *sem)
190 int result = 0;
192 D(bug("%s(%p)\n", __FUNCTION__, sem));
194 if (sem == NULL)
196 errno = EINVAL;
197 return -1;
200 pthread_mutex_lock(&sem->lock);
202 if (sem->value > 0)
203 sem->value--;
204 else
205 result = EAGAIN;
207 pthread_mutex_unlock(&sem->lock);
209 if (result != 0)
211 errno = result;
212 return -1;
215 return 0;
218 int sem_timedwait(sem_t *sem, const struct timespec *abstime)
220 int result = 0;
222 D(bug("%s(%p, %p)\n", __FUNCTION__, sem, abstime));
224 if (sem == NULL)
226 errno = EINVAL;
227 return -1;
230 pthread_mutex_lock(&sem->lock);
232 sem->waiters_count++;
234 while (sem->value == 0 && result == 0)
235 result = pthread_cond_timedwait(&sem->count_nonzero, &sem->lock, abstime);
237 sem->waiters_count--;
239 if (result != 0)
241 pthread_mutex_unlock(&sem->lock);
242 errno = result;
243 return -1;
246 sem->value--;
248 pthread_mutex_unlock(&sem->lock);
250 return 0;
253 int sem_wait(sem_t *sem)
255 D(bug("%s(%p)\n", __FUNCTION__, sem));
257 return sem_timedwait(sem, NULL);
260 int sem_post(sem_t *sem)
262 D(bug("%s(%p)\n", __FUNCTION__, sem));
264 if (sem == NULL)
266 errno = EINVAL;
267 return -1;
270 pthread_mutex_lock(&sem->lock);
272 if (sem->value >= SEM_VALUE_MAX)
274 pthread_mutex_unlock(&sem->lock);
275 errno = EOVERFLOW;
276 return -1;
279 sem->value++;
281 if (sem->waiters_count > 0)
282 pthread_cond_signal(&sem->count_nonzero);
284 pthread_mutex_unlock(&sem->lock);
286 return 0;
289 int sem_getvalue(sem_t *sem, int *sval)
291 D(bug("%s(%p)\n", __FUNCTION__, sem));
293 if (sem == NULL || sval == NULL)
295 errno = EINVAL;
296 return -1;
299 // if one or more threads are waiting to lock the semaphore,
300 // then return the negative of the waiters
301 if (pthread_mutex_trylock(&sem->lock) == 0)
303 if (sem->lock.incond)
304 *sval = -sem->waiters_count;
305 else
306 *sval = sem->value;
307 pthread_mutex_unlock(&sem->lock);
309 else
311 // TODO: should I lock the mutex here?
312 *sval = -sem->waiters_count;
315 return 0;