146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    SDL - Simple DirectMedia Layer
346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Copyright (C) 1997-2006 Sam Lantinga
446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is free software; you can redistribute it and/or
646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    modify it under the terms of the GNU Lesser General Public
746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License as published by the Free Software Foundation; either
846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    version 2.1 of the License, or (at your option) any later version.
946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is distributed in the hope that it will be useful,
1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    but WITHOUT ANY WARRANTY; without even the implied warranty of
1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Lesser General Public License for more details.
1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    You should have received a copy of the GNU Lesser General Public
1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License along with this library; if not, write to the Free Software
1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Sam Lantinga
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    slouken@libsdl.org
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <pthread.h>
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <semaphore.h>
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <errno.h>
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_thread.h"
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_timer.h"
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Wrapper around POSIX 1003.1b semaphores */
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef __MACOSX__
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Mac OS X doesn't support sem_getvalue() as of version 10.4 */
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../generic/SDL_syssem.c"
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstruct SDL_semaphore {
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	sem_t sem;
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner};
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Create a semaphore, initialized with value */
4346be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerSDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem));
4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem ) {
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( sem_init(&sem->sem, 0, initial_value) < 0 ) {
4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_SetError("sem_init() failed");
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_free(sem);
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			sem = NULL;
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_OutOfMemory();
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return sem;
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnervoid SDL_DestroySemaphore(SDL_sem *sem)
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem ) {
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		sem_destroy(&sem->sem);
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_free(sem);
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemTryWait(SDL_sem *sem)
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int retval;
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL semaphore");
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	retval = SDL_MUTEX_TIMEDOUT;
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem_trywait(&sem->sem) == 0 ) {
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = 0;
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemWait(SDL_sem *sem)
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int retval;
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL semaphore");
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	while ( ((retval = sem_wait(&sem->sem)) == -1) && (errno == EINTR) ) {}
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( retval < 0 ) {
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("sem_wait() failed");
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int retval;
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL semaphore");
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Try the easy cases first */
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( timeout == 0 ) {
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return SDL_SemTryWait(sem);
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( timeout == SDL_MUTEX_MAXWAIT ) {
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return SDL_SemWait(sem);
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Ack!  We have to busy wait... */
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* FIXME: Use sem_timedwait()? */
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	timeout += SDL_GetTicks();
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	do {
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = SDL_SemTryWait(sem);
11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( retval == 0 ) {
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_Delay(1);
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} while ( SDL_GetTicks() < timeout );
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12846be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerUint32 SDL_SemValue(SDL_sem *sem)
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int ret = 0;
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem ) {
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		sem_getvalue(&sem->sem, &ret);
13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( ret < 0 ) {
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			ret = 0;
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return (Uint32)ret;
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemPost(SDL_sem *sem)
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int retval;
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL semaphore");
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	retval = sem_post(&sem->sem);
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( retval < 0 ) {
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("sem_post() failed");
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif /* __MACOSX__ */
157