Windows CE patches contributed by Rainer Loritz
--HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%4037
This commit is contained in:
parent
09112109c3
commit
a95fb10027
11 changed files with 413 additions and 63 deletions
214
src/thread/win32/win_ce_semaphore.c
Normal file
214
src/thread/win32/win_ce_semaphore.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
/* 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. */
|
||||
|
||||
#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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue