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>
26 #include "semaphore.h"
30 #define EOVERFLOW EINVAL
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
);
45 sem_t
*sem_open(const char *name
, int oflag
, mode_t mode
, unsigned int value
)
49 D(bug("%s(%s, %d, %u, %u)\n", __FUNCTION__
, name
, oflag
, mode
, value
));
51 pthread_once(&once_control
, _Init_Semaphore
);
59 ObtainSemaphore(&sema_sem
);
60 sem
= (sem_t
*)FindName(&semaphores
, (STRPTR
)name
);
63 if ((oflag
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
65 ReleaseSemaphore(&sema_sem
);
72 if (!(oflag
& O_CREAT
))
74 ReleaseSemaphore(&sema_sem
);
79 sem
= malloc(sizeof(sem_t
));
82 ReleaseSemaphore(&sema_sem
);
87 if (sem_init(sem
, 0, value
))
90 ReleaseSemaphore(&sema_sem
);
93 // TODO: this string should be duplicated
94 sem
->node
.ln_Name
= (char *)name
;
95 AddTail(&semaphores
, (struct Node
*)sem
);
97 ReleaseSemaphore(&sema_sem
);
102 int sem_close(sem_t
*sem
)
104 D(bug("%s(%p)\n", __FUNCTION__
, sem
));
109 int sem_unlink(const char *name
)
113 D(bug("%s(%s)\n", __FUNCTION__
, name
));
115 pthread_once(&once_control
, _Init_Semaphore
);
123 ObtainSemaphore(&sema_sem
);
124 sem
= (sem_t
*)FindName(&semaphores
, (STRPTR
)name
);
128 ReleaseSemaphore(&sema_sem
);
133 if (sem_destroy(sem
) != 0)
135 ReleaseSemaphore(&sema_sem
);
139 Remove((struct Node
*)sem
);
141 ReleaseSemaphore(&sema_sem
);
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
)
157 sem
->waiters_count
= 0;
158 pthread_mutex_init(&sem
->lock
, NULL
);
159 pthread_cond_init(&sem
->count_nonzero
, NULL
);
164 int sem_destroy(sem_t
*sem
)
166 D(bug("%s(%p)\n", __FUNCTION__
, sem
));
174 if (pthread_mutex_trylock(&sem
->lock
) != 0)
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;
188 int sem_trywait(sem_t
*sem
)
192 D(bug("%s(%p)\n", __FUNCTION__
, sem
));
200 pthread_mutex_lock(&sem
->lock
);
207 pthread_mutex_unlock(&sem
->lock
);
218 int sem_timedwait(sem_t
*sem
, const struct timespec
*abstime
)
222 D(bug("%s(%p, %p)\n", __FUNCTION__
, sem
, abstime
));
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
--;
241 pthread_mutex_unlock(&sem
->lock
);
248 pthread_mutex_unlock(&sem
->lock
);
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
));
270 pthread_mutex_lock(&sem
->lock
);
272 if (sem
->value
>= SEM_VALUE_MAX
)
274 pthread_mutex_unlock(&sem
->lock
);
281 if (sem
->waiters_count
> 0)
282 pthread_cond_signal(&sem
->count_nonzero
);
284 pthread_mutex_unlock(&sem
->lock
);
289 int sem_getvalue(sem_t
*sem
, int *sval
)
291 D(bug("%s(%p)\n", __FUNCTION__
, sem
));
293 if (sem
== NULL
|| sval
== NULL
)
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
;
307 pthread_mutex_unlock(&sem
->lock
);
311 // TODO: should I lock the mutex here?
312 *sval
= -sem
->waiters_count
;