source: trunk/src/helpers/sem.c

Last change on this file was 243, checked in by umoeller, 23 years ago

New build system, multimedia, other misc fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 6.9 KB
Line 
1
2/*
3 *@@sourcefile sem.c:
4 * implements fast mutex semaphores.
5 *
6 * This is an OS/2 implementation of what Win32 calls
7 * "critical sections". This is highly optimized for
8 * the case where there is only one thread trying to
9 * access the critical section, i.e. it is available most
10 * of the time. Therefore we can use these critical
11 * sections for all our serialization and not lose any
12 * performance when concurrent access is unlikely.
13 *
14 * In case there is multiple access, we use the OS/2 kernel
15 * event semaphores.
16 *
17 * Function prefix:
18 *
19 * -- sem*: semaphore helpers.
20 *
21 *@@added V0.9.20 (2002-08-04) [umoeller]
22 *@@header "helpers\semaphores.h"
23 */
24
25/*
26 * Copyright (C) 2002 Sander van Leeuwen.
27 * Copyright (C) 2002 Ulrich M”ller.
28 * This file is part of the "XWorkplace helpers" source package.
29 * This is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published
31 * by the Free Software Foundation, in version 2 as it comes in the
32 * "COPYING" file of the XWorkplace main distribution.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 */
38
39#define OS2EMX_PLAIN_CHAR
40 // this is needed for "os2emx.h"; if this is defined,
41 // emx will define PSZ as _signed_ char, otherwise
42 // as unsigned char
43
44#define INCL_DOSPROCESS
45#define INCL_DOSSEMAPHORES
46#define INCL_DOSERRORS
47
48#define INCL_WINMESSAGEMGR
49#include <os2.h>
50
51#include <stdlib.h>
52
53#include "setup.h" // code generation and debugging options
54
55#include "helpers\sem.h"
56
57#pragma hdrstop
58
59/*
60 *@@category: Helpers\Control program helpers\Semaphores
61 * see sem.c.
62 */
63
64// encode PID and TID into one 32bit value
65#define MAKE_THREADID(processid, threadid) ((processid << 16) | threadid)
66
67/*
68 *@@ GetTID:
69 *
70 */
71
72ULONG GetTID(VOID)
73{
74 PTIB ptib;
75 PPIB ppib;
76 APIRET rc;
77
78 if (!(rc = DosGetInfoBlocks(&ptib, &ppib)))
79 return MAKE_THREADID(ppib->pib_ulpid,
80 ptib->tib_ptib2->tib2_ultid);
81
82 return 0;
83}
84
85/*
86 *@@ GetPID:
87 *
88 */
89
90ULONG GetPID(VOID)
91{
92 PTIB ptib;
93 PPIB ppib;
94 APIRET rc;
95
96 if (!(rc = DosGetInfoBlocks(&ptib, &ppib)))
97 return ppib->pib_ulpid;
98
99 return 0;
100}
101
102/*
103 *@@ semCreate:
104 * the equivalent to DosCreateMutexSem.
105 */
106
107APIRET semCreate(PFASTMTX pmtx,
108 PCSZ pszSemName)
109{
110 APIRET rc;
111
112 if (!pmtx)
113 return ERROR_INVALID_PARAMETER;
114
115 // initialize lock count with special value -1, meaning noone posesses it
116 pmtx->LockCount = -1;
117 pmtx->RecursionCount = 0;
118 pmtx->OwningThread = 0;
119
120 if (rc = DosCreateEventSem((PSZ)pszSemName,
121 &pmtx->hmtxLock,
122 (pszSemName) ? DC_SEM_SHARED : 0,
123 0))
124 pmtx->hmtxLock = 0;
125
126 pmtx->Reserved = GetPID();
127
128 return rc;
129}
130
131/*
132 *@@ semOpen:
133 * the equivalent to DosOpenMutexSem.
134 */
135
136APIRET semOpen(PFASTMTX pmtx,
137 PCSZ pszSemName)
138{
139 HMTX hmtxLock = 0;
140 APIRET rc;
141
142 if (!pszSemName)
143 return ERROR_INVALID_PARAMETER;
144
145 return DosOpenEventSem((PSZ)pszSemName, &hmtxLock);
146}
147
148/*
149 *@@ semClose:
150 * the equivalent to DosCloseMutexSem.
151 */
152
153APIRET semClose(PFASTMTX pmtx)
154{
155 APIRET rc;
156
157 if (!pmtx)
158 return ERROR_INVALID_PARAMETER;
159
160 if (!pmtx->hmtxLock)
161 return ERROR_INVALID_HANDLE;
162
163 if (pmtx->RecursionCount) /* Should not happen */
164 return ERROR_SEM_BUSY;
165
166 pmtx->LockCount = -1;
167 pmtx->RecursionCount = 0;
168 pmtx->OwningThread = 0;
169 rc = DosCloseEventSem(pmtx->hmtxLock);
170 pmtx->hmtxLock = 0;
171 pmtx->Reserved = (ULONG)-1;
172
173 return rc;
174}
175
176/*
177 *@@ semRequest:
178 * the equivalent to DosRequestMutexSem.
179 */
180
181APIRET semRequest(PFASTMTX pmtx)
182{
183 ULONG threadid = GetTID();
184
185 if (!pmtx)
186 return ERROR_INVALID_PARAMETER;
187
188 // create pmtx sect just in time...
189 if (!pmtx->hmtxLock)
190 semCreate(pmtx, NULL);
191
192 // do an atomic increase of the lockcounter and see if it is > 0
193 // (i.e. it is already posessed)
194 if (lockIncrement(&pmtx->LockCount))
195 {
196 // semaphore was already requested:
197
198testenter:
199 // if the same thread is requesting it again, memorize it
200 if (pmtx->OwningThread == threadid)
201 {
202 pmtx->RecursionCount++;
203 return NO_ERROR;
204 }
205
206 // current owner is different thread:
207
208 // do an atomic operation where we compare the owning thread id with 0
209 // and if this is true, exchange it with the id of the current thread
210 if (lockCompareExchange((PLONG)&pmtx->OwningThread, threadid, 0))
211 {
212 // the compare did not return equal, i.e. the pmtx sect is in use
213
214 ULONG cPosts;
215 APIRET rc;
216
217 /* Now wait for it */
218 if (rc = DosWaitEventSem(pmtx->hmtxLock, SEM_INDEFINITE_WAIT))
219 return rc;
220
221 DosResetEventSem(pmtx->hmtxLock, &cPosts);
222
223 // multiple waiters could be running now. Repeat the logic so that
224 // only one actually can get the critical section
225 goto testenter;
226 }
227 }
228
229 pmtx->OwningThread = GetTID();
230 pmtx->RecursionCount = 1;
231
232 return NO_ERROR;
233}
234
235/*
236 *@@ semAssert:
237 * returns TRUE if the current thread currently owns
238 * the mutex.
239 *
240 */
241
242BOOL semAssert(PFASTMTX pmtx)
243{
244 return ( (pmtx)
245 && (pmtx->OwningThread)
246 && (pmtx->OwningThread == GetTID())
247 );
248}
249
250/*
251 *@@ semTry:
252 *
253 */
254
255BOOL semTry(PFASTMTX pmtx)
256{
257 if (lockIncrement(&pmtx->LockCount))
258 {
259 if (pmtx->OwningThread == GetTID())
260 {
261 pmtx->RecursionCount++;
262 return TRUE;
263 }
264
265 lockDecrement(&pmtx->LockCount);
266
267 return FALSE;
268 }
269
270 pmtx->OwningThread = GetTID();
271 pmtx->RecursionCount = 1;
272
273 return TRUE;
274}
275
276/*
277 *@@ semRelease:
278 * the equivalent of DosReleaseMutexSem.
279 */
280
281APIRET semRelease(PFASTMTX pmtx)
282{
283 if (!pmtx)
284 return ERROR_INVALID_PARAMETER;
285
286 if (pmtx->OwningThread != GetTID())
287 return ERROR_NOT_OWNER;
288
289 if (--pmtx->RecursionCount)
290 {
291 lockDecrement(&pmtx->LockCount );
292 return NO_ERROR;
293 }
294
295 pmtx->OwningThread = 0;
296
297 if (lockDecrement(&pmtx->LockCount) >= 0)
298 // someone is waiting
299 DosPostEventSem(pmtx->hmtxLock);
300
301 return NO_ERROR;
302}
303
Note: See TracBrowser for help on using the repository browser.