146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    SDL - Simple DirectMedia Layer
346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Copyright (C) 1997-2006 Sam Lantinga
446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is free software; you can redistribute it and/or
646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    modify it under the terms of the GNU Lesser General Public
746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License as published by the Free Software Foundation; either
846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    version 2.1 of the License, or (at your option) any later version.
946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is distributed in the hope that it will be useful,
1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    but WITHOUT ANY WARRANTY; without even the implied warranty of
1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Lesser General Public License for more details.
1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    You should have received a copy of the GNU Lesser General Public
1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License along with this library; if not, write to the Free Software
1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Sam Lantinga
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    slouken@libsdl.org
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Semaphore functions using the Win32 API */
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define WIN32_LEAN_AND_MEAN
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <windows.h>
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_thread.h"
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "win_ce_semaphore.h"
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstruct SDL_semaphore {
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SYNCHHANDLE id;
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	HANDLE id;
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint32 volatile count;
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner};
4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Create a semaphore */
4646be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerSDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_sem *sem;
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Allocate sem memory */
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem ) {
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Create the semaphore, with max value 32K */
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		sem->id = CreateSemaphoreCE(NULL, initial_value, 32*1024, NULL);
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		sem->id = CreateSemaphore(NULL, initial_value, 32*1024, NULL);
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		sem->count = initial_value;
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( ! sem->id ) {
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_SetError("Couldn't create semaphore");
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_free(sem);
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			sem = NULL;
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_OutOfMemory();
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(sem);
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Free the semaphore */
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnervoid SDL_DestroySemaphore(SDL_sem *sem)
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( sem ) {
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( sem->id ) {
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			CloseSynchHandle(sem->id);
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			CloseHandle(sem->id);
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			sem->id = 0;
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_free(sem);
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int retval;
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	DWORD dwMilliseconds;
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL sem");
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( timeout == SDL_MUTEX_MAXWAIT ) {
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		dwMilliseconds = INFINITE;
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		dwMilliseconds = (DWORD)timeout;
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch (WaitForSemaphoreCE(sem->id, dwMilliseconds)) {
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch (WaitForSingleObject(sem->id, dwMilliseconds)) {
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case WAIT_OBJECT_0:
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		--sem->count;
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = 0;
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case WAIT_TIMEOUT:
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = SDL_MUTEX_TIMEDOUT;
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    default:
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("WaitForSingleObject() failed");
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = -1;
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemTryWait(SDL_sem *sem)
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return SDL_SemWaitTimeout(sem, 0);
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemWait(SDL_sem *sem)
12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Returns the current count of the semaphore */
13346be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerUint32 SDL_SemValue(SDL_sem *sem)
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL sem");
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return 0;
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return sem->count;
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SemPost(SDL_sem *sem)
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ! sem ) {
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Passed a NULL sem");
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Increase the counter in the first place, because
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * after a successful release the semaphore may
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * immediately get destroyed by another thread which
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * is waiting for this semaphore.
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	++sem->count;
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ReleaseSemaphoreCE(sem->id, 1, NULL) == FALSE ) {
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ReleaseSemaphore(sem->id, 1, NULL) == FALSE ) {
15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		--sem->count;	/* restore */
16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("ReleaseSemaphore() failed");
16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return 0;
16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
165