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

Last change on this file since 8902 was 8902, checked in by achimha, 23 years ago

documentation

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