source: trunk/src/odincrt/critsect.cpp

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

Merge branch gcc-kmk to trunk.

File size: 6.9 KB
RevLine 
[10580]1/* $Id: critsect.cpp,v 1.12 2004-04-14 08:45:45 sandervl Exp $ */
[8201]2/*
[8902]3 * Critical sections in the Win32 sense
[10185]4 *
[8902]5 * Copyright 2002 Sander van Leeuwen <sandervl@innotek.de>
[8201]6 *
7 */
8#define INCL_DOSPROCESS
9#define INCL_DOSERRORS
10#define INCL_DOSSEMAPHORES
[10580]11#include <os2wrap.h>
12#include <win32type.h>
13#include <win32api.h>
14#include <FastInfoBlocks.h>
[10533]15
[10580]16#include <assert.h>
17#include <stdio.h>
[10533]18
19#include <odincrt.h>
[8201]20
[10580]21
[10186]22#undef fibGetPid
23
[10533]24#undef dprintf
25#undef DebugInt3
[8201]26
[10533]27#define dprintf(a)
[8201]28#define DebugInt3()
29
[10580]30
31ULONG WIN32API DosValidateCriticalSection (CRITICAL_SECTION_OS2 *crit)
32{
33 if (crit->hevLock != NULLHANDLE)
34 {
35 return NO_ERROR;
36 }
[21916]37
[10580]38 return ERROR_INVALID_PARAMETER;
39}
40
[8902]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//
[9756]48// In case there is multiple access, we use the OS/2 kernel event semaphores.
[8902]49//******************************************************************************
50
51
52// encode PID and TID into one 32bit value
[8201]53#define MAKE_THREADID(processid, threadid) ((processid << 16) | threadid)
54
55//******************************************************************************
56//******************************************************************************
57inline ULONG GetCurrentThreadId()
58{
[10185]59#ifdef fibGetPid
60 return MAKE_THREADID(fibGetPid(), fibGetTid());
61#else
[8201]62 PTIB ptib;
63 PPIB ppib;
64 APIRET rc;
[10185]65
[8201]66 rc = DosGetInfoBlocks(&ptib, &ppib);
67 if(rc == NO_ERROR) {
[9756]68#ifdef DEBUG
69 if(MAKE_THREADID(ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid) == 0) {
70 DebugInt3();
71 }
72#endif
[8201]73 return MAKE_THREADID(ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid);
74 }
75 DebugInt3();
76 return 0;
[10185]77#endif
[8201]78}
79//******************************************************************************
80//******************************************************************************
[10580]81inline ULONG GetCurrentProcessId()
[8201]82{
[10580]83#ifdef fibGetPid
84 return fibGetPid();
85#else
86 PTIB ptib;
87 PPIB ppib;
[8201]88 APIRET rc;
[10185]89
[10580]90 rc = DosGetInfoBlocks(&ptib, &ppib);
91 if(rc == NO_ERROR) {
92 return ppib->pib_ulpid;
[8201]93 }
[10580]94 DebugInt3();
95 return 0;
96#endif
97}
98
99/***********************************************************************
100 * DosInitializeCriticalSection
101 */
102ULONG WIN32API DosInitializeCriticalSection(CRITICAL_SECTION_OS2 *crit,
[21916]103 PCSZ pszSemName, BOOL fShared)
[10580]104{
105 APIRET rc;
106
[8902]107 // initialize lock count with special value -1, meaning noone posesses it
[8201]108 crit->LockCount = -1;
109 crit->RecursionCount = 0;
110 crit->OwningThread = 0;
111
[10580]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 }
[9336]118 crit->CreationCount = 1;
[10580]119 crit->Reserved = GetCurrentProcessId();
[9331]120 return NO_ERROR;
[8201]121}
122
123
[10580]124/***********************************************************************
125 * DosAccessCriticalSection
126 */
[21916]127ULONG WIN32API DosAccessCriticalSection(CRITICAL_SECTION_OS2 *crit, PCSZ pszSemName)
[8201]128{
[10533]129 APIRET rc = NO_ERROR;
[21916]130
131 // Increment creation counter to prevent the section to be destroyed while
[10533]132 // we are checking it. Assume that an unitialized section has the counter == 0
133 DosInterlockedIncrement(&crit->CreationCount);
[21916]134
[10533]135 if (DosValidateCriticalSection (crit) == NO_ERROR)
136 {
137 // the section already initialized, use it
138 HEV hevLock = NULLHANDLE;
[21916]139
[10533]140 if (pszSemName == NULL)
141 {
142 hevLock = crit->hevLock;
143 }
[8201]144
[10533]145 rc = DosOpenEventSem(pszSemName, &hevLock);
146
147 if (rc != NO_ERROR)
148 {
149 DosInterlockedDecrement(&crit->CreationCount);
150 DebugInt3();
151 }
[8201]152 }
[10533]153 else
154 {
155 rc = DosInitializeCriticalSection (crit, pszSemName, TRUE);
[9336]156 }
[21916]157
[9331]158 return NO_ERROR;
[8201]159}
[10580]160/***********************************************************************
161 * DosDeleteCriticalSection
162 */
[9331]163ULONG WIN32API DosDeleteCriticalSection( CRITICAL_SECTION_OS2 *crit )
[8201]164{
[10580]165 if (crit->hevLock)
[8201]166 {
[10580]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);
[9336]176 if(DosInterlockedDecrement(&crit->CreationCount) == 0)
177 {
178 crit->LockCount = -1;
179 crit->RecursionCount = 0;
180 crit->OwningThread = 0;
[10580]181 crit->hevLock = 0;
182 crit->Reserved = (DWORD)-1;
[9336]183 }
[8201]184 }
[9331]185 return NO_ERROR;
[8201]186}
187
188
[10580]189/***********************************************************************
190 * DosEnterCriticalSection
191 */
[9331]192ULONG WIN32API DosEnterCriticalSection( CRITICAL_SECTION_OS2 *crit, ULONG ulTimeout )
[8201]193{
[10580]194 DWORD res;
195 DWORD threadid = GetCurrentThreadId();
196
197 // create crit sect just in time...
[10533]198 if (!crit->hevLock)
[8201]199 {
[10580]200 DosInitializeCriticalSection(crit, NULL);
[8201]201 }
[10580]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 }
[8201]208
[10580]209 // do an atomic increase of the lockcounter
210 DosInterlockedIncrement(&crit->LockCount);
[8201]211
[10580]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))
[8201]216 {
[10580]217 // the crit sect is in use
218 ULONG ulnrposts;
[9756]219
[10580]220 // now wait for it
221 APIRET rc = DosWaitEventSem(crit->hevLock, ulTimeout);
222 if(rc != NO_ERROR) {
223 DebugInt3();
[9756]224 return rc;
[8201]225 }
[10580]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;
[8201]230 }
231 crit->RecursionCount = 1;
[9756]232 return NO_ERROR;
[8201]233}
234
235
[10580]236/***********************************************************************
237 * DosLeaveCriticalSection
238 */
[9331]239ULONG WIN32API DosLeaveCriticalSection( CRITICAL_SECTION_OS2 *crit )
[8201]240{
[9331]241 if (crit->OwningThread != GetCurrentThreadId()) {
[10580]242 DebugInt3();
[9331]243 return ERROR_INVALID_PARAMETER;
244 }
[10185]245
[8201]246 if (--crit->RecursionCount)
247 {
[10580]248 //just return
[9331]249 return NO_ERROR;
[8201]250 }
251 crit->OwningThread = 0;
252 if (DosInterlockedDecrement( &crit->LockCount ) >= 0)
253 {
[10580]254 /* Someone is waiting */
[10533]255 DosPostEventSem(crit->hevLock);
[8201]256 }
[9331]257 return NO_ERROR;
[8201]258}
Note: See TracBrowser for help on using the repository browser.