Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
228 lines (192 loc) · 8.55 KB

win_ce_semaphore.c

File metadata and controls

228 lines (192 loc) · 8.55 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* 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. */
Feb 25, 2006
Feb 25, 2006
31
32
33
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
34
35
#include "win_ce_semaphore.h"
Jul 10, 2006
Jul 10, 2006
36
static SYNCHHANDLE CleanUp(SYNCHHANDLE hSynch, DWORD Flags);
Jul 10, 2006
Jul 10, 2006
38
39
40
41
42
SYNCHHANDLE
CreateSemaphoreCE(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, /* pointer to security attributes */
LONG lInitialCount, /* initial count */
LONG lMaximumCount, /* maximum count */
LPCTSTR lpName)
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* 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 */
{
Jul 10, 2006
Jul 10, 2006
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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;
Jul 10, 2006
Jul 10, 2006
98
99
100
BOOL
ReleaseSemaphoreCE(SYNCHHANDLE hSemCE, LONG cReleaseCount,
LPLONG lpPreviousCount)
101
102
/* Windows CE equivalent to ReleaseSemaphore. */
{
Jul 10, 2006
Jul 10, 2006
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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;
131
132
}
Jul 10, 2006
Jul 10, 2006
133
134
DWORD
WaitForSemaphoreCE(SYNCHHANDLE hSemCE, DWORD dwMilliseconds)
135
136
/* Windows CE semaphore equivalent of WaitForSingleObject. */
{
Jul 10, 2006
Jul 10, 2006
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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;
185
186
}
Jul 10, 2006
Jul 10, 2006
187
188
BOOL
CloseSynchHandle(SYNCHHANDLE hSynch)
189
190
191
/* Close a synchronization handle.
Improvement: Test for a valid handle before dereferencing the handle. */
{
Jul 10, 2006
Jul 10, 2006
192
193
194
195
196
197
198
199
200
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);
201
202
}
Jul 10, 2006
Jul 10, 2006
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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;
Jul 10, 2006
Jul 10, 2006
227
228
/* vi: set ts=4 sw=4 expandtab: */