Home | History | Annotate | Download | only in generic
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /* An implementation of semaphores using mutexes and condition variables */
     25 
     26 #include "SDL_timer.h"
     27 #include "SDL_thread.h"
     28 #include "SDL_systhread_c.h"
     29 
     30 
     31 #if SDL_THREADS_DISABLED
     32 
     33 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
     34 {
     35 	SDL_SetError("SDL not configured with thread support");
     36 	return (SDL_sem *)0;
     37 }
     38 
     39 void SDL_DestroySemaphore(SDL_sem *sem)
     40 {
     41 	return;
     42 }
     43 
     44 int SDL_SemTryWait(SDL_sem *sem)
     45 {
     46 	SDL_SetError("SDL not configured with thread support");
     47 	return -1;
     48 }
     49 
     50 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
     51 {
     52 	SDL_SetError("SDL not configured with thread support");
     53 	return -1;
     54 }
     55 
     56 int SDL_SemWait(SDL_sem *sem)
     57 {
     58 	SDL_SetError("SDL not configured with thread support");
     59 	return -1;
     60 }
     61 
     62 Uint32 SDL_SemValue(SDL_sem *sem)
     63 {
     64 	return 0;
     65 }
     66 
     67 int SDL_SemPost(SDL_sem *sem)
     68 {
     69 	SDL_SetError("SDL not configured with thread support");
     70 	return -1;
     71 }
     72 
     73 #else
     74 
     75 struct SDL_semaphore
     76 {
     77 	Uint32 count;
     78 	Uint32 waiters_count;
     79 	SDL_mutex *count_lock;
     80 	SDL_cond *count_nonzero;
     81 };
     82 
     83 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
     84 {
     85 	SDL_sem *sem;
     86 
     87 	sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
     88 	if ( ! sem ) {
     89 		SDL_OutOfMemory();
     90 		return NULL;
     91 	}
     92 	sem->count = initial_value;
     93 	sem->waiters_count = 0;
     94 
     95 	sem->count_lock = SDL_CreateMutex();
     96 	sem->count_nonzero = SDL_CreateCond();
     97 	if ( ! sem->count_lock || ! sem->count_nonzero ) {
     98 		SDL_DestroySemaphore(sem);
     99 		return NULL;
    100 	}
    101 
    102 	return sem;
    103 }
    104 
    105 /* WARNING:
    106    You cannot call this function when another thread is using the semaphore.
    107 */
    108 void SDL_DestroySemaphore(SDL_sem *sem)
    109 {
    110 	if ( sem ) {
    111 		sem->count = 0xFFFFFFFF;
    112 		while ( sem->waiters_count > 0) {
    113 			SDL_CondSignal(sem->count_nonzero);
    114 			SDL_Delay(10);
    115 		}
    116 		SDL_DestroyCond(sem->count_nonzero);
    117 		if ( sem->count_lock ) {
    118 			SDL_mutexP(sem->count_lock);
    119 			SDL_mutexV(sem->count_lock);
    120 			SDL_DestroyMutex(sem->count_lock);
    121 		}
    122 		SDL_free(sem);
    123 	}
    124 }
    125 
    126 int SDL_SemTryWait(SDL_sem *sem)
    127 {
    128 	int retval;
    129 
    130 	if ( ! sem ) {
    131 		SDL_SetError("Passed a NULL semaphore");
    132 		return -1;
    133 	}
    134 
    135 	retval = SDL_MUTEX_TIMEDOUT;
    136 	SDL_LockMutex(sem->count_lock);
    137 	if ( sem->count > 0 ) {
    138 		--sem->count;
    139 		retval = 0;
    140 	}
    141 	SDL_UnlockMutex(sem->count_lock);
    142 
    143 	return retval;
    144 }
    145 
    146 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
    147 {
    148 	int retval;
    149 
    150 	if ( ! sem ) {
    151 		SDL_SetError("Passed a NULL semaphore");
    152 		return -1;
    153 	}
    154 
    155 	/* A timeout of 0 is an easy case */
    156 	if ( timeout == 0 ) {
    157 		return SDL_SemTryWait(sem);
    158 	}
    159 
    160 	SDL_LockMutex(sem->count_lock);
    161 	++sem->waiters_count;
    162 	retval = 0;
    163 	while ( (sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT) ) {
    164 		retval = SDL_CondWaitTimeout(sem->count_nonzero,
    165 		                             sem->count_lock, timeout);
    166 	}
    167 	--sem->waiters_count;
    168 	if (retval == 0) {
    169 		--sem->count;
    170 	}
    171 	SDL_UnlockMutex(sem->count_lock);
    172 
    173 	return retval;
    174 }
    175 
    176 int SDL_SemWait(SDL_sem *sem)
    177 {
    178 	return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
    179 }
    180 
    181 Uint32 SDL_SemValue(SDL_sem *sem)
    182 {
    183 	Uint32 value;
    184 
    185 	value = 0;
    186 	if ( sem ) {
    187 		SDL_LockMutex(sem->count_lock);
    188 		value = sem->count;
    189 		SDL_UnlockMutex(sem->count_lock);
    190 	}
    191 	return value;
    192 }
    193 
    194 int SDL_SemPost(SDL_sem *sem)
    195 {
    196 	if ( ! sem ) {
    197 		SDL_SetError("Passed a NULL semaphore");
    198 		return -1;
    199 	}
    200 
    201 	SDL_LockMutex(sem->count_lock);
    202 	if ( sem->waiters_count > 0 ) {
    203 		SDL_CondSignal(sem->count_nonzero);
    204 	}
    205 	++sem->count;
    206 	SDL_UnlockMutex(sem->count_lock);
    207 
    208 	return 0;
    209 }
    210 
    211 #endif /* SDL_THREADS_DISABLED */
    212