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

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

Minor updates for critical section functions

File size: 6.5 KB
Line 
1/* $Id: critsect.cpp,v 1.6 2002-10-07 16:28:13 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, PSZ pszSemName)
75{
76 APIRET rc;
77
78 // initialize lock count with special value -1, meaning noone posesses it
79 crit->LockCount = -1;
80 crit->RecursionCount = 0;
81 crit->OwningThread = 0;
82
83 rc = DosCreateEventSem(pszSemName, &crit->hmtxLock, (pszSemName) ? DC_SEM_SHARED : 0, 0);
84 if(rc != NO_ERROR) {
85 DebugInt3();
86 crit->hmtxLock = 0;
87 return rc;
88 }
89 crit->Reserved = GetCurrentProcessId();
90 return NO_ERROR;
91}
92
93
94/***********************************************************************
95 * DosAccessCriticalSection
96 */
97ULONG WIN32API DosAccessCriticalSection(CRITICAL_SECTION_OS2 *, PSZ pszSemName)
98{
99 HMTX hmtxLock = 0;
100 APIRET rc;
101
102 if(pszSemName == NULL) {
103 DebugInt3();
104 return ERROR_INVALID_PARAMETER;
105 }
106
107 rc = DosOpenEventSem(pszSemName, &hmtxLock);
108 if(rc != NO_ERROR) {
109 DebugInt3();
110 return rc;
111 }
112 return NO_ERROR;
113}
114/***********************************************************************
115 * DosDeleteCriticalSection
116 */
117ULONG WIN32API DosDeleteCriticalSection( CRITICAL_SECTION_OS2 *crit )
118{
119 if (crit->hmtxLock)
120 {
121 if (crit->RecursionCount) /* Should not happen */
122 {
123 DebugInt3();
124 }
125 crit->LockCount = -1;
126 crit->RecursionCount = 0;
127 crit->OwningThread = 0;
128 DosCloseEventSem(crit->hmtxLock);
129 crit->hmtxLock = 0;
130 crit->Reserved = (DWORD)-1;
131 }
132 return NO_ERROR;
133}
134
135
136/***********************************************************************
137 * DosEnterCriticalSection
138 */
139ULONG WIN32API DosEnterCriticalSection( CRITICAL_SECTION_OS2 *crit, ULONG ulTimeout )
140{
141 DWORD res;
142 DWORD threadid = GetCurrentThreadId();
143
144 // create crit sect just in time...
145 if (!crit->hmtxLock)
146 {
147 DosInitializeCriticalSection(crit, NULL);
148 }
149 // do an atomic increase of the lockcounter and see if it is > 0
150 // (i.e. it is already posessed)
151 if (DosInterlockedIncrement(&crit->LockCount))
152 {
153testenter:
154 // if the same thread is requesting it again, memorize it
155 if (crit->OwningThread == threadid)
156 {
157 crit->RecursionCount++;
158 return NO_ERROR;
159 }
160 // do an atomic operation where we compare the owning thread id with 0
161 // and if this is true, exchange it with the id of the current thread.
162 if(DosInterlockedCompareExchange((PLONG)&crit->OwningThread, threadid, 0))
163 {
164 // the compare did not return equal, i.e. the crit sect is in use
165
166 ULONG ulnrposts;
167
168 /* Now wait for it */
169 APIRET rc = DosWaitEventSem(crit->hmtxLock, ulTimeout);
170 if(rc != NO_ERROR) {
171 DebugInt3();
172 return rc;
173 }
174 DosResetEventSem(crit->hmtxLock, &ulnrposts);
175 // multiple waiters could be running now. Repeat the logic so that
176 // only one actually can get the critical section
177 goto testenter;
178 }
179 }
180 crit->OwningThread = GetCurrentThreadId();
181 crit->RecursionCount = 1;
182 return NO_ERROR;
183}
184
185
186/***********************************************************************
187 * DosTryEnterCriticalSection
188 */
189BOOL WIN32API DosTryEnterCriticalSection( CRITICAL_SECTION_OS2 *crit )
190{
191 if (DosInterlockedIncrement( &crit->LockCount ))
192 {
193 if (crit->OwningThread == GetCurrentThreadId())
194 {
195 crit->RecursionCount++;
196 return TRUE;
197 }
198 DosInterlockedDecrement( &crit->LockCount );
199 return FALSE;
200 }
201 crit->OwningThread = GetCurrentThreadId();
202 crit->RecursionCount = 1;
203 return TRUE;
204}
205
206
207/***********************************************************************
208 * DosLeaveCriticalSection
209 */
210ULONG WIN32API DosLeaveCriticalSection( CRITICAL_SECTION_OS2 *crit )
211{
212 if (crit->OwningThread != GetCurrentThreadId()) {
213 DebugInt3();
214 return ERROR_INVALID_PARAMETER;
215 }
216
217 if (--crit->RecursionCount)
218 {
219 DosInterlockedDecrement( &crit->LockCount );
220 return NO_ERROR;
221 }
222 crit->OwningThread = 0;
223 if (DosInterlockedDecrement( &crit->LockCount ) >= 0)
224 {
225 /* Someone is waiting */
226 DosPostEventSem(crit->hmtxLock);
227 }
228 return NO_ERROR;
229}
Note: See TracBrowser for help on using the repository browser.