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

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

Updates

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