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@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 33SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) 34{ 35 SDL_SetError("SDL not configured with thread support"); 36 return (SDL_sem *)0; 37} 38 39void SDL_DestroySemaphore(SDL_sem *sem) 40{ 41 return; 42} 43 44int SDL_SemTryWait(SDL_sem *sem) 45{ 46 SDL_SetError("SDL not configured with thread support"); 47 return -1; 48} 49 50int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) 51{ 52 SDL_SetError("SDL not configured with thread support"); 53 return -1; 54} 55 56int SDL_SemWait(SDL_sem *sem) 57{ 58 SDL_SetError("SDL not configured with thread support"); 59 return -1; 60} 61 62Uint32 SDL_SemValue(SDL_sem *sem) 63{ 64 return 0; 65} 66 67int SDL_SemPost(SDL_sem *sem) 68{ 69 SDL_SetError("SDL not configured with thread support"); 70 return -1; 71} 72 73#else 74 75struct SDL_semaphore 76{ 77 Uint32 count; 78 Uint32 waiters_count; 79 SDL_mutex *count_lock; 80 SDL_cond *count_nonzero; 81}; 82 83SDL_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*/ 108void 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 126int 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 146int 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 176int SDL_SemWait(SDL_sem *sem) 177{ 178 return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); 179} 180 181Uint32 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 194int 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