diff options
author | Franklin Wei <git@fwei.tk> | 2017-01-21 15:18:31 -0500 |
---|---|---|
committer | Franklin Wei <git@fwei.tk> | 2017-12-23 21:01:26 -0500 |
commit | a855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch) | |
tree | 8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c | |
parent | 01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff) | |
download | rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip |
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.
Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c')
-rw-r--r-- | apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c b/apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c new file mode 100644 index 0000000000..9db45c4391 --- /dev/null +++ b/apps/plugins/sdl/src/thread/win32/win_ce_semaphore.c | |||
@@ -0,0 +1,216 @@ | |||
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 CreateSemaphoreCE ( | ||
39 | |||
40 | LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, /* pointer to security attributes */ | ||
41 | LONG lInitialCount, /* initial count */ | ||
42 | LONG lMaximumCount, /* maximum count */ | ||
43 | LPCTSTR lpName ) | ||
44 | |||
45 | /* Semaphore for use with Windows CE that does not support them directly. | ||
46 | Requires a counter, a mutex to protect the counter, and an | ||
47 | autoreset event. | ||
48 | |||
49 | Here are the rules that must always hold between the autoreset event | ||
50 | and the mutex (any violation of these rules by the CE semaphore functions | ||
51 | will, in all likelihood, result in a defect): | ||
52 | 1. No thread can set, pulse, or reset the event, | ||
53 | nor can it access any part of the SYNCHHANDLE structure, | ||
54 | without first gaining ownership of the mutex. | ||
55 | BUT, a thread can wait on the event without owning the mutex | ||
56 | (this is clearly necessary or else the event could never be set). | ||
57 | 2. The event is in a signaled state if and only if the current semaphore | ||
58 | count ("CurCount") is greater than zero. | ||
59 | 3. The semaphore count is always >= 0 and <= the maximum count */ | ||
60 | |||
61 | { | ||
62 | SYNCHHANDLE hSynch = NULL, result = NULL; | ||
63 | |||
64 | __try | ||
65 | { | ||
66 | if (lInitialCount > lMaximumCount || lMaximumCount < 0 || lInitialCount < 0) | ||
67 | { | ||
68 | /* Bad parameters */ | ||
69 | SetLastError (SYNCH_ERROR); | ||
70 | __leave; | ||
71 | } | ||
72 | |||
73 | hSynch = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, SYNCH_HANDLE_SIZE); | ||
74 | if (hSynch == NULL) __leave; | ||
75 | |||
76 | hSynch->MaxCount = lMaximumCount; | ||
77 | hSynch->CurCount = lInitialCount; | ||
78 | hSynch->lpName = lpName; | ||
79 | |||
80 | hSynch->hMutex = CreateMutex (lpSemaphoreAttributes, FALSE, NULL); | ||
81 | |||
82 | WaitForSingleObject (hSynch->hMutex, INFINITE); | ||
83 | /* Create the event. It is initially signaled if and only if the | ||
84 | initial count is > 0 */ | ||
85 | hSynch->hEvent = CreateEvent (lpSemaphoreAttributes, FALSE, | ||
86 | lInitialCount > 0, NULL); | ||
87 | ReleaseMutex (hSynch->hMutex); | ||
88 | hSynch->hSemph = NULL; | ||
89 | } | ||
90 | __finally | ||
91 | { | ||
92 | /* Return with the handle, or, if there was any error, return | ||
93 | a null after closing any open handles and freeing any allocated memory. */ | ||
94 | result=CleanUp(hSynch, 6 /* An event and a mutex, but no semaphore. */); | ||
95 | } | ||
96 | |||
97 | return result; | ||
98 | } | ||
99 | |||
100 | BOOL ReleaseSemaphoreCE (SYNCHHANDLE hSemCE, LONG cReleaseCount, 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 | { | ||
110 | WaitForSingleObject (hSemCE->hMutex, INFINITE); | ||
111 | /* reply only if asked to */ | ||
112 | if (lpPreviousCount!=NULL) | ||
113 | *lpPreviousCount = hSemCE->CurCount; | ||
114 | if (hSemCE->CurCount + cReleaseCount > hSemCE->MaxCount || cReleaseCount <= 0) | ||
115 | { | ||
116 | SetLastError (SYNCH_ERROR); | ||
117 | Result = FALSE; | ||
118 | __leave; | ||
119 | } | ||
120 | hSemCE->CurCount += cReleaseCount; | ||
121 | |||
122 | /* Set the autoreset event, releasing exactly one waiting thread, now or | ||
123 | in the future. */ | ||
124 | |||
125 | SetEvent (hSemCE->hEvent); | ||
126 | } | ||
127 | __finally | ||
128 | { | ||
129 | ReleaseMutex (hSemCE->hMutex); | ||
130 | } | ||
131 | |||
132 | return Result; | ||
133 | } | ||
134 | |||
135 | DWORD WaitForSemaphoreCE (SYNCHHANDLE hSemCE, DWORD dwMilliseconds) | ||
136 | /* Windows CE semaphore equivalent of WaitForSingleObject. */ | ||
137 | { | ||
138 | DWORD WaitResult; | ||
139 | |||
140 | WaitResult = WaitForSingleObject (hSemCE->hMutex, dwMilliseconds); | ||
141 | if (WaitResult != WAIT_OBJECT_0 && WaitResult != WAIT_ABANDONED_0) return WaitResult; | ||
142 | while (hSemCE->CurCount <= 0) | ||
143 | { | ||
144 | |||
145 | /* The count is 0, and the thread must wait on the event (which, by | ||
146 | the rules, is currently reset) for semaphore resources to become | ||
147 | available. First, of course, the mutex must be released so that another | ||
148 | thread will be capable of setting the event. */ | ||
149 | |||
150 | ReleaseMutex (hSemCE->hMutex); | ||
151 | |||
152 | /* Wait for the event to be signaled, indicating a semaphore state change. | ||
153 | The event is autoreset and signaled with a SetEvent (not PulseEvent) | ||
154 | so exactly one waiting thread (whether or not there is currently | ||
155 | a waiting thread) is released as a result of the SetEvent. */ | ||
156 | |||
157 | WaitResult = WaitForSingleObject (hSemCE->hEvent, dwMilliseconds); | ||
158 | if (WaitResult != WAIT_OBJECT_0) 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) return WaitResult; | ||
171 | |||
172 | } | ||
173 | /* The count is not zero and this thread owns the mutex. */ | ||
174 | |||
175 | hSemCE->CurCount--; | ||
176 | /* The event is now unsignaled, BUT, the semaphore count may not be | ||
177 | zero, in which case the event should be signaled again | ||
178 | before releasing the mutex. */ | ||
179 | |||
180 | if (hSemCE->CurCount > 0) SetEvent (hSemCE->hEvent); | ||
181 | ReleaseMutex (hSemCE->hMutex); | ||
182 | return WaitResult; | ||
183 | } | ||
184 | |||
185 | BOOL CloseSynchHandle (SYNCHHANDLE hSynch) | ||
186 | /* Close a synchronization handle. | ||
187 | Improvement: Test for a valid handle before dereferencing the handle. */ | ||
188 | { | ||
189 | BOOL Result = TRUE; | ||
190 | if (hSynch->hEvent != NULL) Result = Result && CloseHandle (hSynch->hEvent); | ||
191 | if (hSynch->hMutex != NULL) Result = Result && CloseHandle (hSynch->hMutex); | ||
192 | if (hSynch->hSemph != NULL) Result = Result && CloseHandle (hSynch->hSemph); | ||
193 | HeapFree (GetProcessHeap (), 0, hSynch); | ||
194 | return (Result); | ||
195 | } | ||
196 | |||
197 | static SYNCHHANDLE CleanUp (SYNCHHANDLE hSynch, DWORD Flags) | ||
198 | { /* Prepare to return from a create of a synchronization handle. | ||
199 | If there was any failure, free any allocated resources. | ||
200 | "Flags" indicates which Win32 objects are required in the | ||
201 | synchronization handle. */ | ||
202 | |||
203 | BOOL ok = TRUE; | ||
204 | |||
205 | if (hSynch == NULL) return NULL; | ||
206 | if ((Flags & 4) == 1 && (hSynch->hEvent == NULL)) ok = FALSE; | ||
207 | if ((Flags & 2) == 1 && (hSynch->hMutex == NULL)) ok = FALSE; | ||
208 | if ((Flags & 1) == 1 && (hSynch->hEvent == NULL)) ok = FALSE; | ||
209 | if (!ok) | ||
210 | { | ||
211 | CloseSynchHandle (hSynch); | ||
212 | return NULL; | ||
213 | } | ||
214 | /* Everything worked */ | ||
215 | return hSynch; | ||
216 | } | ||