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

Last change on this file since 22010 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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