1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2006 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* Semaphores in the BeOS environment */
25
26#include <be/kernel/OS.h>
27
28#include "SDL_thread.h"
29
30
31struct SDL_semaphore {
32	sem_id id;
33};
34
35/* Create a counting semaphore */
36SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
37{
38	SDL_sem *sem;
39
40	sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
41	if ( sem ) {
42		sem->id = create_sem(initial_value, "SDL semaphore");
43		if ( sem->id < B_NO_ERROR ) {
44			SDL_SetError("create_sem() failed");
45			SDL_free(sem);
46			sem = NULL;
47		}
48	} else {
49		SDL_OutOfMemory();
50	}
51	return(sem);
52}
53
54/* Free the semaphore */
55void SDL_DestroySemaphore(SDL_sem *sem)
56{
57	if ( sem ) {
58		if ( sem->id >= B_NO_ERROR ) {
59			delete_sem(sem->id);
60		}
61		SDL_free(sem);
62	}
63}
64
65int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
66{
67	int32 val;
68	int retval;
69
70	if ( ! sem ) {
71		SDL_SetError("Passed a NULL semaphore");
72		return -1;
73	}
74
75  tryagain:
76	if ( timeout == SDL_MUTEX_MAXWAIT ) {
77		val = acquire_sem(sem->id);
78	} else {
79		timeout *= 1000; /* BeOS uses a timeout in microseconds */
80		val = acquire_sem_etc(sem->id, 1, B_RELATIVE_TIMEOUT, timeout);
81	}
82	switch (val) {
83	    case B_INTERRUPTED:
84		goto tryagain;
85	    case B_NO_ERROR:
86		retval = 0;
87		break;
88	    case B_TIMED_OUT:
89		retval = SDL_MUTEX_TIMEDOUT;
90		break;
91	    case B_WOULD_BLOCK:
92		retval = SDL_MUTEX_TIMEDOUT;
93		break;
94	    default:
95		SDL_SetError("acquire_sem() failed");
96		retval = -1;
97		break;
98	}
99
100	return retval;
101}
102
103int SDL_SemTryWait(SDL_sem *sem)
104{
105	return SDL_SemWaitTimeout(sem, 0);
106}
107
108int SDL_SemWait(SDL_sem *sem)
109{
110	return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
111}
112
113/* Returns the current count of the semaphore */
114Uint32 SDL_SemValue(SDL_sem *sem)
115{
116	int32 count;
117	Uint32 value;
118
119	value = 0;
120	if ( sem ) {
121		get_sem_count(sem->id, &count);
122		if ( count > 0 ) {
123			value = (Uint32)count;
124		}
125	}
126	return value;
127}
128
129/* Atomically increases the semaphore's count (not blocking) */
130int SDL_SemPost(SDL_sem *sem)
131{
132	if ( ! sem ) {
133		SDL_SetError("Passed a NULL semaphore");
134		return -1;
135	}
136
137	if ( release_sem(sem->id) != B_NO_ERROR ) {
138		SDL_SetError("release_sem() failed");
139		return -1;
140	}
141	return 0;
142}
143