source: branches/branch-1-0/src/helpers/sem.c

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

Misc fixes.

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