source: trunk/src/odincrt/critsect.cpp@ 10544

Last change on this file since 10544 was 10533, checked in by sandervl, 22 years ago

VP: Critical section update

File size: 7.2 KB
Line 
1/* $Id: critsect.cpp,v 1.11 2004-03-16 17:24:53 sandervl Exp $ */
2/*
3 * Critical sections in the Win32 sense
4 *
5 * Copyright 2002 Sander van Leeuwen <sandervl@innotek.de>
6 *
7 */
8#define INCL_DOS
9#define INCL_DOSPROCESS
10#define INCL_DOSERRORS
11#define INCL_DOSSEMAPHORES
12#include <os2.h>
13
14#include "dbglog.h"
15
16#include <odincrt.h>
17#include <FastInfoBlocks.h>
18
19#undef fibGetPid
20
21#undef dprintf
22#undef DebugInt3
23
24#define dprintf(a)
25#define DebugInt3()
26
27//******************************************************************************
28// This is an OS/2 implementation of what Win32 treats as "critical sections"
29// It is an implementation that is highly optimized for the case where there is
30// only one thread trying to access the critical section, i.e. it is available
31// most of the time. Therefore we can use these critical sections for all our
32// serialization and not lose any performance when concurrent access is unlikely.
33//
34// In case there is multiple access, we use the OS/2 kernel event semaphores.
35//******************************************************************************
36
37
38// encode PID and TID into one 32bit value
39#define MAKE_THREADID(processid, threadid) ((processid << 16) | threadid)
40
41//******************************************************************************
42//******************************************************************************
43inline ULONG GetCurrentThreadId()
44{
45#ifdef fibGetPid
46 return MAKE_THREADID(fibGetPid(), fibGetTid());
47#else
48 PTIB ptib;
49 PPIB ppib;
50 APIRET rc;
51
52 rc = DosGetInfoBlocks(&ptib, &ppib);
53 if(rc == NO_ERROR) {
54#ifdef DEBUG
55 if(MAKE_THREADID(ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid) == 0) {
56 DebugInt3();
57 }
58#endif
59 return MAKE_THREADID(ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid);
60 }
61 DebugInt3();
62 return 0;
63#endif
64}
65//******************************************************************************
66//******************************************************************************
67ULONG WIN32API DosInitializeCriticalSection(CRITICAL_SECTION_OS2 *crit, char *pszSemName, BOOL fShared)
68{
69 APIRET rc;
70
71 rc = DosCreateEventSem(pszSemName, &crit->hevLock, (pszSemName || fShared)? DC_SEM_SHARED: 0, 0);
72
73 if(rc != NO_ERROR)
74 {
75 crit->hevLock = 0;
76 return rc;
77 }
78
79 // initialize lock count with special value -1, meaning noone posesses it
80 crit->LockCount = -1;
81 crit->RecursionCount = 0;
82 crit->OwningThread = 0;
83
84 crit->CreationCount = 1;
85 crit->Reserved = 0;
86
87 return NO_ERROR;
88}
89
90ULONG WIN32API DosValidateCriticalSection (CRITICAL_SECTION_OS2 *crit)
91{
92 if (crit->hevLock != NULLHANDLE)
93 {
94 return NO_ERROR;
95 }
96
97 return ERROR_INVALID_PARAMETER;
98}
99
100// Initializes or opens a critical section
101ULONG WIN32API DosAccessCriticalSection(CRITICAL_SECTION_OS2 *crit, char *pszSemName)
102{
103 APIRET rc = NO_ERROR;
104
105 // Increment creation counter to prevent the section to be destroyed while
106 // we are checking it. Assume that an unitialized section has the counter == 0
107 DosInterlockedIncrement(&crit->CreationCount);
108
109 if (DosValidateCriticalSection (crit) == NO_ERROR)
110 {
111 // the section already initialized, use it
112 HEV hevLock = NULLHANDLE;
113
114 if (pszSemName == NULL)
115 {
116 hevLock = crit->hevLock;
117 }
118
119 rc = DosOpenEventSem(pszSemName, &hevLock);
120
121 if (rc != NO_ERROR)
122 {
123 DosInterlockedDecrement(&crit->CreationCount);
124 DebugInt3();
125 }
126 }
127 else
128 {
129 rc = DosInitializeCriticalSection (crit, pszSemName, TRUE);
130 }
131
132 return NO_ERROR;
133}
134
135ULONG WIN32API DosDeleteCriticalSection( CRITICAL_SECTION_OS2 *crit )
136{
137 if (DosValidateCriticalSection (crit))
138 {
139 DosCloseEventSem (crit->hevLock);
140
141 if(DosInterlockedDecrement(&crit->CreationCount) == 0)
142 {
143 crit->LockCount = -1;
144 crit->RecursionCount = 0;
145 crit->OwningThread = 0;
146 crit->hevLock = 0;
147 crit->Reserved = 0;
148 }
149 }
150 return NO_ERROR;
151}
152
153
154ULONG WIN32API DosEnterCriticalSection( CRITICAL_SECTION_OS2 *crit, ULONG ulTimeout )
155{
156 APIRET rc = NO_ERROR;
157
158 ULONG threadid = GetCurrentThreadId();
159
160 if (!crit->hevLock)
161 {
162 rc = DosInitializeCriticalSection (crit, NULL, FALSE);
163 if (rc != NO_ERROR)
164 {
165 return rc;
166 }
167 }
168
169 dprintf(("Entering the section: owner = %8.8X\n", crit->OwningThread));
170
171 // We want to acquire the section, count the entering
172 DosInterlockedIncrement (&crit->LockCount);
173
174 // try to acquire the section
175 for (;;)
176 {
177 // try to assign owning thread id atomically
178 if (DosInterlockedCompareExchange((PLONG)&crit->OwningThread, threadid, 0) == 0)
179 {
180 ULONG ulnrposts = 0;
181
182 dprintf(("Acquired the section: owner = %8.8X\n", crit->OwningThread));
183 DosResetEventSem (crit->hevLock, &ulnrposts);
184 break;
185 }
186
187 if (crit->OwningThread == threadid)
188 {
189 // This thread already owns the section
190 crit->RecursionCount++;
191 dprintf(("Recursion: %d\n", crit->RecursionCount));
192 return NO_ERROR;
193 }
194
195 // Arise any timing problems and let others to run
196 DosSleep (0);
197
198 dprintf(("Waiting on sem: owner = %8.8X\n", crit->OwningThread));
199 rc = DosWaitEventSem (crit->hevLock, ulTimeout);
200 dprintf(("Returned from wait: owner = %8.8X, rc = %d\n", crit->OwningThread, rc));
201
202 if (rc != NO_ERROR)
203 {
204 dprintf(("Returned from wait: FAILED!!!\n"));
205 // We fail, deregister itself
206 DosInterlockedDecrement (&crit->LockCount);
207 return rc;
208 }
209 }
210
211 // the section was successfully aquired
212 crit->RecursionCount = 1;
213
214 if (crit->Reserved != 0)
215 {
216 // the section already entered!!!!
217 DosBeep (2000, 200);
218 }
219
220 crit->Reserved = 1;
221
222 return NO_ERROR;
223}
224
225
226ULONG WIN32API DosLeaveCriticalSection( CRITICAL_SECTION_OS2 *crit )
227{
228 dprintf(("Leaving the section\n"));
229 if (crit->OwningThread != GetCurrentThreadId()) {
230 dprintf(("WRONG THREAD ID!!! owner is %8.8X\n", crit->OwningThread));
231 return ERROR_INVALID_PARAMETER;
232 }
233
234 if (--crit->RecursionCount)
235 {
236 dprintf(("Recursion exit: %d\n", crit->RecursionCount));
237 DosInterlockedDecrement( &crit->LockCount );
238 return NO_ERROR;
239 }
240
241 crit->Reserved = 0;
242 crit->OwningThread = 0;
243
244 dprintf(("Released the section\n"));
245
246 if (DosInterlockedDecrement( &crit->LockCount ) >= 0)
247 {
248 dprintf(("Posted the semaphore\n"));
249 DosPostEventSem(crit->hevLock);
250 }
251
252 return NO_ERROR;
253}
254
255
256/**
257 * Checks if the current thread is in the critical section or now.
258 *
259 * @returns NO_ERROR if in the critical section.
260 * @returns ERROR_NOT_OWNER if not in the critical section.
261 * @param pCrit Pointer to the critical section.
262 */
263ULONG WIN32API DosIsInCriticalSection( CRITICAL_SECTION_OS2 *pCrit )
264{
265 return (pCrit->hevLock && pCrit->OwningThread == GetCurrentThreadId() ? NO_ERROR : ERROR_NOT_OWNER);
266}
267
Note: See TracBrowser for help on using the repository browser.