comparison src/thread/windows/win_ce_semaphore.c @ 5062:e8916fe9cfc8

Fixed bug #925 Changed "win32" to "windows"
author Sam Lantinga <slouken@libsdl.org>
date Thu, 20 Jan 2011 18:04:05 -0800
parents src/thread/win32/win_ce_semaphore.c@c121d94672cb
children 327f181542f1
comparison
equal deleted inserted replaced
5061:9e9940eae455 5062:e8916fe9cfc8
1 /* win_ce_semaphore.c
2
3 Copyright (c) 1998, Johnson M. Hart
4 (with corrections 2001 by Rainer Loritz)
5 Permission is granted for any and all use providing that this
6 copyright is properly acknowledged.
7 There are no assurances of suitability for any use whatsoever.
8
9 WINDOWS CE: There is a collection of Windows CE functions to simulate
10 semaphores using only a mutex and an event. As Windows CE events cannot
11 be named, these simulated semaphores cannot be named either.
12
13 Implementation notes:
14 1. All required internal data structures are allocated on the process's heap.
15 2. Where appropriate, a new error code is returned (see the header
16 file), or, if the error is a Win32 error, that code is unchanged.
17 3. Notice the new handle type "SYNCHHANDLE" that has handles, counters,
18 and other information. This structure will grow as new objects are added
19 to this set; some members are specific to only one or two of the objects.
20 4. Mutexes are used for critical sections. These could be replaced with
21 CRITICAL_SECTION objects but then this would give up the time out
22 capability.
23 5. The implementation shows several interesting aspects of synchronization, some
24 of which are specific to Win32 and some of which are general. These are pointed
25 out in the comments as appropriate.
26 6. The wait function emulates WaitForSingleObject only. An emulation of
27 WaitForMultipleObjects is much harder to implement outside the kernel,
28 and it is not clear how to handle a mixture of WCE semaphores and normal
29 events and mutexes. */
30
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33
34 #include "win_ce_semaphore.h"
35
36 static SYNCHHANDLE CleanUp(SYNCHHANDLE hSynch, DWORD Flags);
37
38 SYNCHHANDLE
39 CreateSemaphoreCE(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, /* pointer to security attributes */
40 LONG lInitialCount, /* initial count */
41 LONG lMaximumCount, /* maximum count */
42 LPCTSTR lpName)
43 /* Semaphore for use with Windows CE that does not support them directly.
44 Requires a counter, a mutex to protect the counter, and an
45 autoreset event.
46
47 Here are the rules that must always hold between the autoreset event
48 and the mutex (any violation of these rules by the CE semaphore functions
49 will, in all likelihood, result in a defect):
50 1. No thread can set, pulse, or reset the event,
51 nor can it access any part of the SYNCHHANDLE structure,
52 without first gaining ownership of the mutex.
53 BUT, a thread can wait on the event without owning the mutex
54 (this is clearly necessary or else the event could never be set).
55 2. The event is in a signaled state if and only if the current semaphore
56 count ("CurCount") is greater than zero.
57 3. The semaphore count is always >= 0 and <= the maximum count */
58 {
59 SYNCHHANDLE hSynch = NULL, result = NULL;
60
61 __try {
62 if (lInitialCount > lMaximumCount || lMaximumCount < 0
63 || lInitialCount < 0) {
64 /* Bad parameters */
65 SetLastError(SYNCH_ERROR);
66 __leave;
67 }
68
69 hSynch =
70 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SYNCH_HANDLE_SIZE);
71 if (hSynch == NULL)
72 __leave;
73
74 hSynch->MaxCount = lMaximumCount;
75 hSynch->CurCount = lInitialCount;
76 hSynch->lpName = lpName;
77
78 hSynch->hMutex = CreateMutex(lpSemaphoreAttributes, FALSE, NULL);
79
80 WaitForSingleObject(hSynch->hMutex, INFINITE);
81 /* Create the event. It is initially signaled if and only if the
82 initial count is > 0 */
83 hSynch->hEvent = CreateEvent(lpSemaphoreAttributes, FALSE,
84 lInitialCount > 0, NULL);
85 ReleaseMutex(hSynch->hMutex);
86 hSynch->hSemph = NULL;
87 }
88 __finally {
89 /* Return with the handle, or, if there was any error, return
90 a null after closing any open handles and freeing any allocated memory. */
91 result =
92 CleanUp(hSynch, 6 /* An event and a mutex, but no semaphore. */ );
93 }
94
95 return result;
96 }
97
98 BOOL
99 ReleaseSemaphoreCE(SYNCHHANDLE hSemCE, LONG cReleaseCount,
100 LPLONG lpPreviousCount)
101 /* Windows CE equivalent to ReleaseSemaphore. */
102 {
103 BOOL Result = TRUE;
104
105 /* Gain access to the object to assure that the release count
106 would not cause the total count to exceed the maximum. */
107
108 __try {
109 WaitForSingleObject(hSemCE->hMutex, INFINITE);
110 /* reply only if asked to */
111 if (lpPreviousCount != NULL)
112 *lpPreviousCount = hSemCE->CurCount;
113 if (hSemCE->CurCount + cReleaseCount > hSemCE->MaxCount
114 || cReleaseCount <= 0) {
115 SetLastError(SYNCH_ERROR);
116 Result = FALSE;
117 __leave;
118 }
119 hSemCE->CurCount += cReleaseCount;
120
121 /* Set the autoreset event, releasing exactly one waiting thread, now or
122 in the future. */
123
124 SetEvent(hSemCE->hEvent);
125 }
126 __finally {
127 ReleaseMutex(hSemCE->hMutex);
128 }
129
130 return Result;
131 }
132
133 DWORD
134 WaitForSemaphoreCE(SYNCHHANDLE hSemCE, DWORD dwMilliseconds)
135 /* Windows CE semaphore equivalent of WaitForSingleObject. */
136 {
137 DWORD WaitResult;
138
139 WaitResult = WaitForSingleObject(hSemCE->hMutex, dwMilliseconds);
140 if (WaitResult != WAIT_OBJECT_0 && WaitResult != WAIT_ABANDONED_0)
141 return WaitResult;
142 while (hSemCE->CurCount <= 0) {
143
144 /* The count is 0, and the thread must wait on the event (which, by
145 the rules, is currently reset) for semaphore resources to become
146 available. First, of course, the mutex must be released so that another
147 thread will be capable of setting the event. */
148
149 ReleaseMutex(hSemCE->hMutex);
150
151 /* Wait for the event to be signaled, indicating a semaphore state change.
152 The event is autoreset and signaled with a SetEvent (not PulseEvent)
153 so exactly one waiting thread (whether or not there is currently
154 a waiting thread) is released as a result of the SetEvent. */
155
156 WaitResult = WaitForSingleObject(hSemCE->hEvent, dwMilliseconds);
157 if (WaitResult != WAIT_OBJECT_0)
158 return WaitResult;
159
160 /* This is where the properties of setting of an autoreset event is critical
161 to assure that, even if the semaphore state changes between the
162 preceding Wait and the next, and even if NO threads are waiting
163 on the event at the time of the SetEvent, at least one thread
164 will be released.
165 Pulsing a manual reset event would appear to work, but it would have
166 a defect which could appear if the semaphore state changed between
167 the two waits. */
168
169 WaitResult = WaitForSingleObject(hSemCE->hMutex, dwMilliseconds);
170 if (WaitResult != WAIT_OBJECT_0 && WaitResult != WAIT_ABANDONED_0)
171 return WaitResult;
172
173 }
174 /* The count is not zero and this thread owns the mutex. */
175
176 hSemCE->CurCount--;
177 /* The event is now unsignaled, BUT, the semaphore count may not be
178 zero, in which case the event should be signaled again
179 before releasing the mutex. */
180
181 if (hSemCE->CurCount > 0)
182 SetEvent(hSemCE->hEvent);
183 ReleaseMutex(hSemCE->hMutex);
184 return WaitResult;
185 }
186
187 BOOL
188 CloseSynchHandle(SYNCHHANDLE hSynch)
189 /* Close a synchronization handle.
190 Improvement: Test for a valid handle before dereferencing the handle. */
191 {
192 BOOL Result = TRUE;
193 if (hSynch->hEvent != NULL)
194 Result = Result && CloseHandle(hSynch->hEvent);
195 if (hSynch->hMutex != NULL)
196 Result = Result && CloseHandle(hSynch->hMutex);
197 if (hSynch->hSemph != NULL)
198 Result = Result && CloseHandle(hSynch->hSemph);
199 HeapFree(GetProcessHeap(), 0, hSynch);
200 return (Result);
201 }
202
203 static SYNCHHANDLE
204 CleanUp(SYNCHHANDLE hSynch, DWORD Flags)
205 { /* Prepare to return from a create of a synchronization handle.
206 If there was any failure, free any allocated resources.
207 "Flags" indicates which Win32 objects are required in the
208 synchronization handle. */
209
210 BOOL ok = TRUE;
211
212 if (hSynch == NULL)
213 return NULL;
214 if ((Flags & 4) == 1 && (hSynch->hEvent == NULL))
215 ok = FALSE;
216 if ((Flags & 2) == 1 && (hSynch->hMutex == NULL))
217 ok = FALSE;
218 if ((Flags & 1) == 1 && (hSynch->hEvent == NULL))
219 ok = FALSE;
220 if (!ok) {
221 CloseSynchHandle(hSynch);
222 return NULL;
223 }
224 /* Everything worked */
225 return hSynch;
226 }
227
228 /* vi: set ts=4 sw=4 expandtab: */