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