summaryrefslogtreecommitdiff
path: root/src/thread/win32
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread/win32')
-rw-r--r--src/thread/win32/SDL_sysmutex.c95
-rw-r--r--src/thread/win32/SDL_syssem.c164
-rw-r--r--src/thread/win32/SDL_systhread.c150
-rw-r--r--src/thread/win32/SDL_systhread_c.h28
-rw-r--r--src/thread/win32/win_ce_semaphore.c216
-rw-r--r--src/thread/win32/win_ce_semaphore.h22
6 files changed, 675 insertions, 0 deletions
diff --git a/src/thread/win32/SDL_sysmutex.c b/src/thread/win32/SDL_sysmutex.c
new file mode 100644
index 0000000..d9a8161
--- /dev/null
+++ b/src/thread/win32/SDL_sysmutex.c
@@ -0,0 +1,95 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Mutex functions using the Win32 API */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "SDL_mutex.h"
+
+
+struct SDL_mutex {
+ HANDLE id;
+};
+
+/* Create a mutex */
+SDL_mutex *SDL_CreateMutex(void)
+{
+ SDL_mutex *mutex;
+
+ /* Allocate mutex memory */
+ mutex = (SDL_mutex *)SDL_malloc(sizeof(*mutex));
+ if ( mutex ) {
+ /* Create the mutex, with initial value signaled */
+ mutex->id = CreateMutex(NULL, FALSE, NULL);
+ if ( ! mutex->id ) {
+ SDL_SetError("Couldn't create mutex");
+ SDL_free(mutex);
+ mutex = NULL;
+ }
+ } else {
+ SDL_OutOfMemory();
+ }
+ return(mutex);
+}
+
+/* Free the mutex */
+void SDL_DestroyMutex(SDL_mutex *mutex)
+{
+ if ( mutex ) {
+ if ( mutex->id ) {
+ CloseHandle(mutex->id);
+ mutex->id = 0;
+ }
+ SDL_free(mutex);
+ }
+}
+
+/* Lock the mutex */
+int SDL_mutexP(SDL_mutex *mutex)
+{
+ if ( mutex == NULL ) {
+ SDL_SetError("Passed a NULL mutex");
+ return -1;
+ }
+ if ( WaitForSingleObject(mutex->id, INFINITE) == WAIT_FAILED ) {
+ SDL_SetError("Couldn't wait on mutex");
+ return -1;
+ }
+ return(0);
+}
+
+/* Unlock the mutex */
+int SDL_mutexV(SDL_mutex *mutex)
+{
+ if ( mutex == NULL ) {
+ SDL_SetError("Passed a NULL mutex");
+ return -1;
+ }
+ if ( ReleaseMutex(mutex->id) == FALSE ) {
+ SDL_SetError("Couldn't release mutex");
+ return -1;
+ }
+ return(0);
+}
diff --git a/src/thread/win32/SDL_syssem.c b/src/thread/win32/SDL_syssem.c
new file mode 100644
index 0000000..43c2f95
--- /dev/null
+++ b/src/thread/win32/SDL_syssem.c
@@ -0,0 +1,164 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Semaphore functions using the Win32 API */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "SDL_thread.h"
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+#include "win_ce_semaphore.h"
+#endif
+
+
+struct SDL_semaphore {
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ SYNCHHANDLE id;
+#else
+ HANDLE id;
+#endif
+ Uint32 volatile count;
+};
+
+
+/* Create a semaphore */
+SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
+{
+ SDL_sem *sem;
+
+ /* Allocate sem memory */
+ sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
+ if ( sem ) {
+ /* Create the semaphore, with max value 32K */
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ sem->id = CreateSemaphoreCE(NULL, initial_value, 32*1024, NULL);
+#else
+ sem->id = CreateSemaphore(NULL, initial_value, 32*1024, NULL);
+#endif
+ sem->count = initial_value;
+ if ( ! sem->id ) {
+ SDL_SetError("Couldn't create semaphore");
+ SDL_free(sem);
+ sem = NULL;
+ }
+ } else {
+ SDL_OutOfMemory();
+ }
+ return(sem);
+}
+
+/* Free the semaphore */
+void SDL_DestroySemaphore(SDL_sem *sem)
+{
+ if ( sem ) {
+ if ( sem->id ) {
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ CloseSynchHandle(sem->id);
+#else
+ CloseHandle(sem->id);
+#endif
+ sem->id = 0;
+ }
+ SDL_free(sem);
+ }
+}
+
+int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
+{
+ int retval;
+ DWORD dwMilliseconds;
+
+ if ( ! sem ) {
+ SDL_SetError("Passed a NULL sem");
+ return -1;
+ }
+
+ if ( timeout == SDL_MUTEX_MAXWAIT ) {
+ dwMilliseconds = INFINITE;
+ } else {
+ dwMilliseconds = (DWORD)timeout;
+ }
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ switch (WaitForSemaphoreCE(sem->id, dwMilliseconds)) {
+#else
+ switch (WaitForSingleObject(sem->id, dwMilliseconds)) {
+#endif
+ case WAIT_OBJECT_0:
+ InterlockedDecrement(&sem->count);
+ retval = 0;
+ break;
+ case WAIT_TIMEOUT:
+ retval = SDL_MUTEX_TIMEDOUT;
+ break;
+ default:
+ SDL_SetError("WaitForSingleObject() failed");
+ retval = -1;
+ break;
+ }
+ return retval;
+}
+
+int SDL_SemTryWait(SDL_sem *sem)
+{
+ return SDL_SemWaitTimeout(sem, 0);
+}
+
+int SDL_SemWait(SDL_sem *sem)
+{
+ return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
+}
+
+/* Returns the current count of the semaphore */
+Uint32 SDL_SemValue(SDL_sem *sem)
+{
+ if ( ! sem ) {
+ SDL_SetError("Passed a NULL sem");
+ return 0;
+ }
+ return sem->count;
+}
+
+int SDL_SemPost(SDL_sem *sem)
+{
+ if ( ! sem ) {
+ SDL_SetError("Passed a NULL sem");
+ return -1;
+ }
+ /* Increase the counter in the first place, because
+ * after a successful release the semaphore may
+ * immediately get destroyed by another thread which
+ * is waiting for this semaphore.
+ */
+ InterlockedIncrement(&sem->count);
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ if ( ReleaseSemaphoreCE(sem->id, 1, NULL) == FALSE ) {
+#else
+ if ( ReleaseSemaphore(sem->id, 1, NULL) == FALSE ) {
+#endif
+ InterlockedDecrement(&sem->count); /* restore */
+ SDL_SetError("ReleaseSemaphore() failed");
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/thread/win32/SDL_systhread.c b/src/thread/win32/SDL_systhread.c
new file mode 100644
index 0000000..a0fb2f5
--- /dev/null
+++ b/src/thread/win32/SDL_systhread.c
@@ -0,0 +1,150 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Win32 thread management routines for SDL */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "SDL_thread.h"
+#include "../SDL_thread_c.h"
+#include "../SDL_systhread.h"
+
+#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD
+#ifndef _WIN32_WCE
+/* We'll use the C library from this DLL */
+#include <process.h>
+#endif
+
+#if __GNUC__
+typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned,
+ unsigned (__stdcall *func)(void *), void *arg,
+ unsigned, unsigned *threadID);
+typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code);
+#elif defined(__WATCOMC__)
+/* This is for Watcom targets except OS2 */
+#if __WATCOMC__ < 1240
+#define __watcall
+#endif
+typedef unsigned long (__watcall *pfnSDL_CurrentBeginThread) (void *, unsigned,
+ unsigned (__stdcall *func)(void *), void *arg,
+ unsigned, unsigned *threadID);
+typedef void (__watcall *pfnSDL_CurrentEndThread)(unsigned code);
+#else
+typedef uintptr_t (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned,
+ unsigned (__stdcall *func)(void *), void *arg,
+ unsigned, unsigned *threadID);
+typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code);
+#endif
+#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */
+
+
+typedef struct ThreadStartParms
+{
+ void *args;
+ pfnSDL_CurrentEndThread pfnCurrentEndThread;
+} tThreadStartParms, *pThreadStartParms;
+
+static unsigned __stdcall RunThread(void *data)
+{
+ pThreadStartParms pThreadParms = (pThreadStartParms)data;
+ pfnSDL_CurrentEndThread pfnCurrentEndThread = NULL;
+
+ // Call the thread function!
+ SDL_RunThread(pThreadParms->args);
+
+ // Get the current endthread we have to use!
+ if (pThreadParms)
+ {
+ pfnCurrentEndThread = pThreadParms->pfnCurrentEndThread;
+ SDL_free(pThreadParms);
+ }
+ // Call endthread!
+ if (pfnCurrentEndThread)
+ (*pfnCurrentEndThread)(0);
+ return(0);
+}
+
+#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
+int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
+{
+#else
+int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
+{
+#ifdef _WIN32_WCE
+ pfnSDL_CurrentBeginThread pfnBeginThread = NULL;
+ pfnSDL_CurrentEndThread pfnEndThread = NULL;
+#else
+ pfnSDL_CurrentBeginThread pfnBeginThread = _beginthreadex;
+ pfnSDL_CurrentEndThread pfnEndThread = _endthreadex;
+#endif
+#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */
+ unsigned threadid;
+ pThreadStartParms pThreadParms = (pThreadStartParms)SDL_malloc(sizeof(tThreadStartParms));
+ if (!pThreadParms) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+
+ // Save the function which we will have to call to clear the RTL of calling app!
+ pThreadParms->pfnCurrentEndThread = pfnEndThread;
+ // Also save the real parameters we have to pass to thread function
+ pThreadParms->args = args;
+
+ if (pfnBeginThread) {
+ thread->handle = (SYS_ThreadHandle) pfnBeginThread(NULL, 0, RunThread,
+ pThreadParms, 0, &threadid);
+ } else {
+ thread->handle = CreateThread(NULL, 0, RunThread, pThreadParms, 0, &threadid);
+ }
+ if (thread->handle == NULL) {
+ SDL_SetError("Not enough resources to create thread");
+ return(-1);
+ }
+ return(0);
+}
+
+void SDL_SYS_SetupThread(void)
+{
+ return;
+}
+
+Uint32 SDL_ThreadID(void)
+{
+ return((Uint32)GetCurrentThreadId());
+}
+
+void SDL_SYS_WaitThread(SDL_Thread *thread)
+{
+ WaitForSingleObject(thread->handle, INFINITE);
+ CloseHandle(thread->handle);
+}
+
+/* WARNING: This function is really a last resort.
+ * Threads should be signaled and then exit by themselves.
+ * TerminateThread() doesn't perform stack and DLL cleanup.
+ */
+void SDL_SYS_KillThread(SDL_Thread *thread)
+{
+ TerminateThread(thread->handle, FALSE);
+}
diff --git a/src/thread/win32/SDL_systhread_c.h b/src/thread/win32/SDL_systhread_c.h
new file mode 100644
index 0000000..ab6124e
--- /dev/null
+++ b/src/thread/win32/SDL_systhread_c.h
@@ -0,0 +1,28 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef HANDLE SYS_ThreadHandle;
+
diff --git a/src/thread/win32/win_ce_semaphore.c b/src/thread/win32/win_ce_semaphore.c
new file mode 100644
index 0000000..9db45c4
--- /dev/null
+++ b/src/thread/win32/win_ce_semaphore.c
@@ -0,0 +1,216 @@
+/* win_ce_semaphore.c
+
+ Copyright (c) 1998, Johnson M. Hart
+ (with corrections 2001 by Rainer Loritz)
+ Permission is granted for any and all use providing that this
+ copyright is properly acknowledged.
+ There are no assurances of suitability for any use whatsoever.
+
+ WINDOWS CE: There is a collection of Windows CE functions to simulate
+ semaphores using only a mutex and an event. As Windows CE events cannot
+ be named, these simulated semaphores cannot be named either.
+
+ Implementation notes:
+ 1. All required internal data structures are allocated on the process's heap.
+ 2. Where appropriate, a new error code is returned (see the header
+ file), or, if the error is a Win32 error, that code is unchanged.
+ 3. Notice the new handle type "SYNCHHANDLE" that has handles, counters,
+ and other information. This structure will grow as new objects are added
+ to this set; some members are specific to only one or two of the objects.
+ 4. Mutexes are used for critical sections. These could be replaced with
+ CRITICAL_SECTION objects but then this would give up the time out
+ capability.
+ 5. The implementation shows several interesting aspects of synchronization, some
+ of which are specific to Win32 and some of which are general. These are pointed
+ out in the comments as appropriate.
+ 6. The wait function emulates WaitForSingleObject only. An emulation of
+ WaitForMultipleObjects is much harder to implement outside the kernel,
+ and it is not clear how to handle a mixture of WCE semaphores and normal
+ events and mutexes. */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "win_ce_semaphore.h"
+
+static SYNCHHANDLE CleanUp (SYNCHHANDLE hSynch, DWORD Flags);
+
+SYNCHHANDLE CreateSemaphoreCE (
+
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, /* pointer to security attributes */
+ LONG lInitialCount, /* initial count */
+ LONG lMaximumCount, /* maximum count */
+ LPCTSTR lpName )
+
+/* Semaphore for use with Windows CE that does not support them directly.
+ Requires a counter, a mutex to protect the counter, and an
+ autoreset event.
+
+ Here are the rules that must always hold between the autoreset event
+ and the mutex (any violation of these rules by the CE semaphore functions
+ will, in all likelihood, result in a defect):
+ 1. No thread can set, pulse, or reset the event,
+ nor can it access any part of the SYNCHHANDLE structure,
+ without first gaining ownership of the mutex.
+ BUT, a thread can wait on the event without owning the mutex
+ (this is clearly necessary or else the event could never be set).
+ 2. The event is in a signaled state if and only if the current semaphore
+ count ("CurCount") is greater than zero.
+ 3. The semaphore count is always >= 0 and <= the maximum count */
+
+{
+ SYNCHHANDLE hSynch = NULL, result = NULL;
+
+ __try
+ {
+ if (lInitialCount > lMaximumCount || lMaximumCount < 0 || lInitialCount < 0)
+ {
+ /* Bad parameters */
+ SetLastError (SYNCH_ERROR);
+ __leave;
+ }
+
+ hSynch = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, SYNCH_HANDLE_SIZE);
+ if (hSynch == NULL) __leave;
+
+ hSynch->MaxCount = lMaximumCount;
+ hSynch->CurCount = lInitialCount;
+ hSynch->lpName = lpName;
+
+ hSynch->hMutex = CreateMutex (lpSemaphoreAttributes, FALSE, NULL);
+
+ WaitForSingleObject (hSynch->hMutex, INFINITE);
+ /* Create the event. It is initially signaled if and only if the
+ initial count is > 0 */
+ hSynch->hEvent = CreateEvent (lpSemaphoreAttributes, FALSE,
+ lInitialCount > 0, NULL);
+ ReleaseMutex (hSynch->hMutex);
+ hSynch->hSemph = NULL;
+ }
+ __finally
+ {
+ /* Return with the handle, or, if there was any error, return
+ a null after closing any open handles and freeing any allocated memory. */
+ result=CleanUp(hSynch, 6 /* An event and a mutex, but no semaphore. */);
+ }
+
+ return result;
+}
+
+BOOL ReleaseSemaphoreCE (SYNCHHANDLE hSemCE, LONG cReleaseCount, LPLONG lpPreviousCount)
+/* Windows CE equivalent to ReleaseSemaphore. */
+{
+ BOOL Result = TRUE;
+
+ /* Gain access to the object to assure that the release count
+ would not cause the total count to exceed the maximum. */
+
+ __try
+ {
+ WaitForSingleObject (hSemCE->hMutex, INFINITE);
+ /* reply only if asked to */
+ if (lpPreviousCount!=NULL)
+ *lpPreviousCount = hSemCE->CurCount;
+ if (hSemCE->CurCount + cReleaseCount > hSemCE->MaxCount || cReleaseCount <= 0)
+ {
+ SetLastError (SYNCH_ERROR);
+ Result = FALSE;
+ __leave;
+ }
+ hSemCE->CurCount += cReleaseCount;
+
+ /* Set the autoreset event, releasing exactly one waiting thread, now or
+ in the future. */
+
+ SetEvent (hSemCE->hEvent);
+ }
+ __finally
+ {
+ ReleaseMutex (hSemCE->hMutex);
+ }
+
+ return Result;
+}
+
+DWORD WaitForSemaphoreCE (SYNCHHANDLE hSemCE, DWORD dwMilliseconds)
+ /* Windows CE semaphore equivalent of WaitForSingleObject. */
+{
+ DWORD WaitResult;
+
+ WaitResult = WaitForSingleObject (hSemCE->hMutex, dwMilliseconds);
+ if (WaitResult != WAIT_OBJECT_0 && WaitResult != WAIT_ABANDONED_0) return WaitResult;
+ while (hSemCE->CurCount <= 0)
+ {
+
+ /* The count is 0, and the thread must wait on the event (which, by
+ the rules, is currently reset) for semaphore resources to become
+ available. First, of course, the mutex must be released so that another
+ thread will be capable of setting the event. */
+
+ ReleaseMutex (hSemCE->hMutex);
+
+ /* Wait for the event to be signaled, indicating a semaphore state change.
+ The event is autoreset and signaled with a SetEvent (not PulseEvent)
+ so exactly one waiting thread (whether or not there is currently
+ a waiting thread) is released as a result of the SetEvent. */
+
+ WaitResult = WaitForSingleObject (hSemCE->hEvent, dwMilliseconds);
+ if (WaitResult != WAIT_OBJECT_0) return WaitResult;
+
+ /* This is where the properties of setting of an autoreset event is critical
+ to assure that, even if the semaphore state changes between the
+ preceding Wait and the next, and even if NO threads are waiting
+ on the event at the time of the SetEvent, at least one thread
+ will be released.
+ Pulsing a manual reset event would appear to work, but it would have
+ a defect which could appear if the semaphore state changed between
+ the two waits. */
+
+ WaitResult = WaitForSingleObject (hSemCE->hMutex, dwMilliseconds);
+ if (WaitResult != WAIT_OBJECT_0 && WaitResult != WAIT_ABANDONED_0) return WaitResult;
+
+ }
+ /* The count is not zero and this thread owns the mutex. */
+
+ hSemCE->CurCount--;
+ /* The event is now unsignaled, BUT, the semaphore count may not be
+ zero, in which case the event should be signaled again
+ before releasing the mutex. */
+
+ if (hSemCE->CurCount > 0) SetEvent (hSemCE->hEvent);
+ ReleaseMutex (hSemCE->hMutex);
+ return WaitResult;
+}
+
+BOOL CloseSynchHandle (SYNCHHANDLE hSynch)
+/* Close a synchronization handle.
+ Improvement: Test for a valid handle before dereferencing the handle. */
+{
+ BOOL Result = TRUE;
+ if (hSynch->hEvent != NULL) Result = Result && CloseHandle (hSynch->hEvent);
+ if (hSynch->hMutex != NULL) Result = Result && CloseHandle (hSynch->hMutex);
+ if (hSynch->hSemph != NULL) Result = Result && CloseHandle (hSynch->hSemph);
+ HeapFree (GetProcessHeap (), 0, hSynch);
+ return (Result);
+}
+
+static SYNCHHANDLE CleanUp (SYNCHHANDLE hSynch, DWORD Flags)
+{ /* Prepare to return from a create of a synchronization handle.
+ If there was any failure, free any allocated resources.
+ "Flags" indicates which Win32 objects are required in the
+ synchronization handle. */
+
+ BOOL ok = TRUE;
+
+ if (hSynch == NULL) return NULL;
+ if ((Flags & 4) == 1 && (hSynch->hEvent == NULL)) ok = FALSE;
+ if ((Flags & 2) == 1 && (hSynch->hMutex == NULL)) ok = FALSE;
+ if ((Flags & 1) == 1 && (hSynch->hEvent == NULL)) ok = FALSE;
+ if (!ok)
+ {
+ CloseSynchHandle (hSynch);
+ return NULL;
+ }
+ /* Everything worked */
+ return hSynch;
+}
diff --git a/src/thread/win32/win_ce_semaphore.h b/src/thread/win32/win_ce_semaphore.h
new file mode 100644
index 0000000..af2d7b6
--- /dev/null
+++ b/src/thread/win32/win_ce_semaphore.h
@@ -0,0 +1,22 @@
+/* win_ce_semaphore.h - header file to go with win_ce_semaphore.c */
+
+typedef struct _SYNCH_HANDLE_STRUCTURE {
+ HANDLE hEvent;
+ HANDLE hMutex;
+ HANDLE hSemph;
+ LONG MaxCount;
+ volatile LONG CurCount;
+ LPCTSTR lpName;
+} SYNCH_HANDLE_STRUCTURE, *SYNCHHANDLE;
+
+#define SYNCH_HANDLE_SIZE sizeof (SYNCH_HANDLE_STRUCTURE)
+
+ /* Error codes - all must have bit 29 set */
+#define SYNCH_ERROR 0X20000000 /* EXERCISE - REFINE THE ERROR NUMBERS */
+
+extern SYNCHHANDLE CreateSemaphoreCE (LPSECURITY_ATTRIBUTES, LONG, LONG, LPCTSTR);
+
+extern BOOL ReleaseSemaphoreCE (SYNCHHANDLE, LONG, LPLONG);
+extern DWORD WaitForSemaphoreCE (SYNCHHANDLE, DWORD);
+
+extern BOOL CloseSynchHandle (SYNCHHANDLE);