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/* Semaphore functions using the Win32 API */ 25 26#define WIN32_LEAN_AND_MEAN 27#include <windows.h> 28 29#include "SDL_thread.h" 30#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 31#include "win_ce_semaphore.h" 32#endif 33 34 35struct SDL_semaphore { 36#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 37 SYNCHHANDLE id; 38#else 39 HANDLE id; 40#endif 41 volatile LONG count; 42}; 43 44 45/* Create a semaphore */ 46SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) 47{ 48 SDL_sem *sem; 49 50 /* Allocate sem memory */ 51 sem = (SDL_sem *)SDL_malloc(sizeof(*sem)); 52 if ( sem ) { 53 /* Create the semaphore, with max value 32K */ 54#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 55 sem->id = CreateSemaphoreCE(NULL, initial_value, 32*1024, NULL); 56#else 57 sem->id = CreateSemaphore(NULL, initial_value, 32*1024, NULL); 58#endif 59 sem->count = (LONG) initial_value; 60 if ( ! sem->id ) { 61 SDL_SetError("Couldn't create semaphore"); 62 SDL_free(sem); 63 sem = NULL; 64 } 65 } else { 66 SDL_OutOfMemory(); 67 } 68 return(sem); 69} 70 71/* Free the semaphore */ 72void SDL_DestroySemaphore(SDL_sem *sem) 73{ 74 if ( sem ) { 75 if ( sem->id ) { 76#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 77 CloseSynchHandle(sem->id); 78#else 79 CloseHandle(sem->id); 80#endif 81 sem->id = 0; 82 } 83 SDL_free(sem); 84 } 85} 86 87int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) 88{ 89 int retval; 90 DWORD dwMilliseconds; 91 92 if ( ! sem ) { 93 SDL_SetError("Passed a NULL sem"); 94 return -1; 95 } 96 97 if ( timeout == SDL_MUTEX_MAXWAIT ) { 98 dwMilliseconds = INFINITE; 99 } else { 100 dwMilliseconds = (DWORD)timeout; 101 } 102#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 103 switch (WaitForSemaphoreCE(sem->id, dwMilliseconds)) { 104#else 105 switch (WaitForSingleObject(sem->id, dwMilliseconds)) { 106#endif 107 case WAIT_OBJECT_0: 108 InterlockedDecrement(&sem->count); 109 retval = 0; 110 break; 111 case WAIT_TIMEOUT: 112 retval = SDL_MUTEX_TIMEDOUT; 113 break; 114 default: 115 SDL_SetError("WaitForSingleObject() failed"); 116 retval = -1; 117 break; 118 } 119 return retval; 120} 121 122int SDL_SemTryWait(SDL_sem *sem) 123{ 124 return SDL_SemWaitTimeout(sem, 0); 125} 126 127int SDL_SemWait(SDL_sem *sem) 128{ 129 return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); 130} 131 132/* Returns the current count of the semaphore */ 133Uint32 SDL_SemValue(SDL_sem *sem) 134{ 135 if ( ! sem ) { 136 SDL_SetError("Passed a NULL sem"); 137 return 0; 138 } 139 return (Uint32) sem->count; 140} 141 142int SDL_SemPost(SDL_sem *sem) 143{ 144 if ( ! sem ) { 145 SDL_SetError("Passed a NULL sem"); 146 return -1; 147 } 148 /* Increase the counter in the first place, because 149 * after a successful release the semaphore may 150 * immediately get destroyed by another thread which 151 * is waiting for this semaphore. 152 */ 153 InterlockedIncrement(&sem->count); 154#if defined(_WIN32_WCE) && (_WIN32_WCE < 300) 155 if ( ReleaseSemaphoreCE(sem->id, 1, NULL) == FALSE ) { 156#else 157 if ( ReleaseSemaphore(sem->id, 1, NULL) == FALSE ) { 158#endif 159 InterlockedDecrement(&sem->count); /* restore */ 160 SDL_SetError("ReleaseSemaphore() failed"); 161 return -1; 162 } 163 return 0; 164} 165