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

Last change on this file since 9336 was 9336, checked in by sandervl, 23 years ago

Updates for shared critical sections

File size: 6.8 KB
Line 
1/* $Id: critsect.cpp,v 1.7 2002-10-08 09:49:06 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_DOSPROCESS
9#define INCL_DOSERRORS
10#define INCL_DOSSEMAPHORES
11#include <os2wrap.h>
12#include <win32type.h>
13#include <win32api.h>
14
15#include <assert.h>
16#include <stdio.h>
17
18#include <odincrt.h>
19
20#ifdef DEBUG
21#define DebugInt3() _interrupt(3)
22#else
23#define DebugInt3()
24#endif
25
26//******************************************************************************
27// This is an OS/2 implementation of what Win32 treats as "critical sections"
28// It is an implementation that is highly optimized for the case where there is
29// only one thread trying to access the critical section, i.e. it is available
30// most of the time. Therefore we can use these critical sections for all our
31// serialization and not lose any performance when concurrent access is unlikely.
32//
33// In case there is multiple access, we use the OS/2 kernel even semaphores.
34//******************************************************************************
35
36
37// encode PID and TID into one 32bit value
38#define MAKE_THREADID(processid, threadid) ((processid << 16) | threadid)
39
40//******************************************************************************
41//******************************************************************************
42inline ULONG GetCurrentThreadId()
43{
44 PTIB ptib;
45 PPIB ppib;
46 APIRET rc;
47
48 rc = DosGetInfoBlocks(&ptib, &ppib);
49 if(rc == NO_ERROR) {
50 return MAKE_THREADID(ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid);
51 }
52 DebugInt3();
53 return 0;
54}
55//******************************************************************************
56//******************************************************************************
57inline ULONG GetCurrentProcessId()
58{
59 PTIB ptib;
60 PPIB ppib;
61 APIRET rc;
62
63 rc = DosGetInfoBlocks(&ptib, &ppib);
64 if(rc == NO_ERROR) {
65 return ppib->pib_ulpid;
66 }
67 DebugInt3();
68 return 0;
69}
70
71/***********************************************************************
72 * DosInitializeCriticalSection
73 */
74ULONG WIN32API DosInitializeCriticalSection(CRITICAL_SECTION_OS2 *crit,
75 PSZ pszSemName, BOOL fShared)
76{
77 APIRET rc;
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 rc = DosCreateEventSem(pszSemName, &crit->hmtxLock, (pszSemName || fShared) ? DC_SEM_SHARED : 0, 0);
85 if(rc != NO_ERROR) {
86 DebugInt3();
87 crit->hmtxLock = 0;
88 return rc;
89 }
90 crit->CreationCount = 1;
91 crit->Reserved = GetCurrentProcessId();
92 return NO_ERROR;
93}
94
95
96/***********************************************************************
97 * DosAccessCriticalSection
98 */
99ULONG WIN32API DosAccessCriticalSection(CRITICAL_SECTION_OS2 *crit, PSZ pszSemName)
100{
101 HMTX hmtxLock = 0;
102 APIRET rc;
103
104 if(pszSemName == NULL && crit->hmtxLock == 0) {
105 DebugInt3();
106 return ERROR_INVALID_PARAMETER;
107 }
108 if(pszSemName == NULL) {
109 hmtxLock = crit->hmtxLock;
110 }
111
112 rc = DosOpenEventSem(pszSemName, &hmtxLock);
113 if(rc != NO_ERROR) {
114 DebugInt3();
115 return rc;
116 }
117 DosInterlockedIncrement(&crit->CreationCount);
118 return NO_ERROR;
119}
120/***********************************************************************
121 * DosDeleteCriticalSection
122 */
123ULONG WIN32API DosDeleteCriticalSection( CRITICAL_SECTION_OS2 *crit )
124{
125 if (crit->hmtxLock)
126 {
127 if (crit->RecursionCount) /* Should not happen */
128 {
129 DebugInt3();
130 }
131 DosCloseEventSem(crit->hmtxLock);
132 if(DosInterlockedDecrement(&crit->CreationCount) == 0)
133 {
134 crit->LockCount = -1;
135 crit->RecursionCount = 0;
136 crit->OwningThread = 0;
137 crit->hmtxLock = 0;
138 crit->Reserved = (DWORD)-1;
139 }
140 }
141 return NO_ERROR;
142}
143
144
145/***********************************************************************
146 * DosEnterCriticalSection
147 */
148ULONG WIN32API DosEnterCriticalSection( CRITICAL_SECTION_OS2 *crit, ULONG ulTimeout )
149{
150 DWORD res;
151 DWORD threadid = GetCurrentThreadId();
152
153 // create crit sect just in time...
154 if (!crit->hmtxLock)
155 {
156 DosInitializeCriticalSection(crit, NULL);
157 }
158 // do an atomic increase of the lockcounter and see if it is > 0
159 // (i.e. it is already posessed)
160 if (DosInterlockedIncrement(&crit->LockCount))
161 {
162testenter:
163 // if the same thread is requesting it again, memorize it
164 if (crit->OwningThread == threadid)
165 {
166 crit->RecursionCount++;
167 return NO_ERROR;
168 }
169 // do an atomic operation where we compare the owning thread id with 0
170 // and if this is true, exchange it with the id of the current thread.
171 if(DosInterlockedCompareExchange((PLONG)&crit->OwningThread, threadid, 0))
172 {
173 // the compare did not return equal, i.e. the crit sect is in use
174
175 ULONG ulnrposts;
176
177 /* Now wait for it */
178 APIRET rc = DosWaitEventSem(crit->hmtxLock, ulTimeout);
179 if(rc != NO_ERROR) {
180 DebugInt3();
181 return rc;
182 }
183 DosResetEventSem(crit->hmtxLock, &ulnrposts);
184 // multiple waiters could be running now. Repeat the logic so that
185 // only one actually can get the critical section
186 goto testenter;
187 }
188 }
189 crit->OwningThread = GetCurrentThreadId();
190 crit->RecursionCount = 1;
191 return NO_ERROR;
192}
193
194
195/***********************************************************************
196 * DosTryEnterCriticalSection
197 */
198BOOL WIN32API DosTryEnterCriticalSection( CRITICAL_SECTION_OS2 *crit )
199{
200 if (DosInterlockedIncrement( &crit->LockCount ))
201 {
202 if (crit->OwningThread == GetCurrentThreadId())
203 {
204 crit->RecursionCount++;
205 return TRUE;
206 }
207 DosInterlockedDecrement( &crit->LockCount );
208 return FALSE;
209 }
210 crit->OwningThread = GetCurrentThreadId();
211 crit->RecursionCount = 1;
212 return TRUE;
213}
214
215
216/***********************************************************************
217 * DosLeaveCriticalSection
218 */
219ULONG WIN32API DosLeaveCriticalSection( CRITICAL_SECTION_OS2 *crit )
220{
221 if (crit->OwningThread != GetCurrentThreadId()) {
222 DebugInt3();
223 return ERROR_INVALID_PARAMETER;
224 }
225
226 if (--crit->RecursionCount)
227 {
228 DosInterlockedDecrement( &crit->LockCount );
229 return NO_ERROR;
230 }
231 crit->OwningThread = 0;
232 if (DosInterlockedDecrement( &crit->LockCount ) >= 0)
233 {
234 /* Someone is waiting */
235 DosPostEventSem(crit->hmtxLock);
236 }
237 return NO_ERROR;
238}
Note: See TracBrowser for help on using the repository browser.