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