Mercurial > sdl-ios-xcode
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: */ |