SDL_syssem.c (4551B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#include <errno.h> 24#include <pthread.h> 25#include <semaphore.h> 26#include <sys/time.h> 27 28#include "SDL_thread.h" 29#include "SDL_timer.h" 30 31/* Wrapper around POSIX 1003.1b semaphores */ 32 33#if defined(__MACOSX__) || defined(__IPHONEOS__) 34/* Mac OS X doesn't support sem_getvalue() as of version 10.4 */ 35#include "../generic/SDL_syssem.c" 36#else 37 38struct SDL_semaphore 39{ 40 sem_t sem; 41}; 42 43/* Create a semaphore, initialized with value */ 44SDL_sem * 45SDL_CreateSemaphore(Uint32 initial_value) 46{ 47 SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem)); 48 if (sem) { 49 if (sem_init(&sem->sem, 0, initial_value) < 0) { 50 SDL_SetError("sem_init() failed"); 51 SDL_free(sem); 52 sem = NULL; 53 } 54 } else { 55 SDL_OutOfMemory(); 56 } 57 return sem; 58} 59 60void 61SDL_DestroySemaphore(SDL_sem * sem) 62{ 63 if (sem) { 64 sem_destroy(&sem->sem); 65 SDL_free(sem); 66 } 67} 68 69int 70SDL_SemTryWait(SDL_sem * sem) 71{ 72 int retval; 73 74 if (!sem) { 75 return SDL_SetError("Passed a NULL semaphore"); 76 } 77 retval = SDL_MUTEX_TIMEDOUT; 78 if (sem_trywait(&sem->sem) == 0) { 79 retval = 0; 80 } 81 return retval; 82} 83 84int 85SDL_SemWait(SDL_sem * sem) 86{ 87 int retval; 88 89 if (!sem) { 90 return SDL_SetError("Passed a NULL semaphore"); 91 } 92 93 retval = sem_wait(&sem->sem); 94 if (retval < 0) { 95 retval = SDL_SetError("sem_wait() failed"); 96 } 97 return retval; 98} 99 100int 101SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) 102{ 103 int retval; 104#ifdef HAVE_SEM_TIMEDWAIT 105 struct timeval now; 106 struct timespec ts_timeout; 107#else 108 Uint32 end; 109#endif 110 111 if (!sem) { 112 return SDL_SetError("Passed a NULL semaphore"); 113 } 114 115 /* Try the easy cases first */ 116 if (timeout == 0) { 117 return SDL_SemTryWait(sem); 118 } 119 if (timeout == SDL_MUTEX_MAXWAIT) { 120 return SDL_SemWait(sem); 121 } 122 123#ifdef HAVE_SEM_TIMEDWAIT 124 /* Setup the timeout. sem_timedwait doesn't wait for 125 * a lapse of time, but until we reach a certain time. 126 * This time is now plus the timeout. 127 */ 128 gettimeofday(&now, NULL); 129 130 /* Add our timeout to current time */ 131 now.tv_usec += (timeout % 1000) * 1000; 132 now.tv_sec += timeout / 1000; 133 134 /* Wrap the second if needed */ 135 if ( now.tv_usec >= 1000000 ) { 136 now.tv_usec -= 1000000; 137 now.tv_sec ++; 138 } 139 140 /* Convert to timespec */ 141 ts_timeout.tv_sec = now.tv_sec; 142 ts_timeout.tv_nsec = now.tv_usec * 1000; 143 144 /* Wait. */ 145 do { 146 retval = sem_timedwait(&sem->sem, &ts_timeout); 147 } while (retval < 0 && errno == EINTR); 148 149 if (retval < 0) { 150 if (errno == ETIMEDOUT) { 151 retval = SDL_MUTEX_TIMEDOUT; 152 } else { 153 SDL_SetError("sem_timedwait returned an error: %s", strerror(errno)); 154 } 155 } 156#else 157 end = SDL_GetTicks() + timeout; 158 while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) { 159 if (SDL_TICKS_PASSED(SDL_GetTicks(), end)) { 160 break; 161 } 162 SDL_Delay(1); 163 } 164#endif /* HAVE_SEM_TIMEDWAIT */ 165 166 return retval; 167} 168 169Uint32 170SDL_SemValue(SDL_sem * sem) 171{ 172 int ret = 0; 173 if (sem) { 174 sem_getvalue(&sem->sem, &ret); 175 if (ret < 0) { 176 ret = 0; 177 } 178 } 179 return (Uint32) ret; 180} 181 182int 183SDL_SemPost(SDL_sem * sem) 184{ 185 int retval; 186 187 if (!sem) { 188 return SDL_SetError("Passed a NULL semaphore"); 189 } 190 191 retval = sem_post(&sem->sem); 192 if (retval < 0) { 193 SDL_SetError("sem_post() failed"); 194 } 195 return retval; 196} 197 198#endif /* __MACOSX__ */ 199/* vi: set ts=4 sw=4 expandtab: */