source: trunk/src/kernel32/critsection.cpp@ 22015

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

Merge branch gcc-kmk to trunk.

File size: 11.6 KB
Line 
1/* $Id: critsection.cpp,v 1.10 2003-08-01 16:25:47 sandervl Exp $ */
2/*
3 * Win32 critical sections
4 *
5 *
6 *
7 * Copyright 1998 Alexandre Julliard (991031 Port)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13#include <os2win.h>
14#include <assert.h>
15#include <stdio.h>
16#include <dbglog.h>
17#include <debugtools.h>
18#include <odinwrap.h>
19#include <wprocess.h>
20
21#define DBG_LOCALLOG DBG_critsection
22#include "dbglocal.h"
23
24DECLARE_DEBUG_CHANNEL(relay)
25
26#ifdef DEBUG
27
28#include "heapshared.h"
29#include <vmutex.h>
30
31typedef struct _CritSectDebug
32{
33 struct _CritSectDebug *next;
34 struct _CritSectDebug *prev;
35 CRITICAL_SECTION *ThisSect;
36 HANDLE CreatingThread;
37 LONG EnteredCount;
38} CritSectDebug;
39
40CritSectDebug *csfirst = NULL;
41CritSectDebug *cslast = NULL;
42ULONG ulCritSectCount = 0;
43
44VMutex csmutex;
45
46void printCriticalSectionStatistic (void)
47{
48 ULONG leakedSectionsCount = 0;
49 CritSectDebug *iter = csfirst;
50
51 while (iter)
52 {
53 dprintf(("%d: Section %p, created by thread %8.8X, entered %d\n", leakedSectionsCount, iter->ThisSect, iter->CreatingThread, iter->EnteredCount));
54 leakedSectionsCount++;
55
56 CritSectDebug *next = iter->next;
57 _sfree(iter);
58 iter = next;
59 }
60
61 dprintf(("Total leaked sections %d, section count is %d\n", leakedSectionsCount, ulCritSectCount));
62}
63
64CritSectDebug *checkCritSectDebug (void *DebugInfo)
65{
66 CritSectDebug *iter = csfirst;
67
68 while (iter)
69 {
70 if (iter == DebugInfo)
71 {
72 break;
73 }
74
75 iter = iter->next;
76 }
77
78 if (!iter)
79 {
80 dprintf(("DebugInfo is not in our list: %p!!!\n", DebugInfo));
81 }
82
83 return iter;
84}
85
86void InitializeDebugInfo (CRITICAL_SECTION *crit)
87{
88 csmutex.enter();
89 if (checkCritSectDebug (crit->DebugInfo) != NULL)
90 {
91 dprintf(("InitializeDebugInfo already initialized: DebugInfo %p", crit->DebugInfo));
92 }
93 else
94 {
95 CritSectDebug *pdbg = (CritSectDebug *)_smalloc(sizeof (CritSectDebug));
96 if (!pdbg)
97 {
98 dprintf(("InitializeDebugInfo failed to allocate debug info!!!"));
99 }
100 else
101 {
102 dprintf(("InitializeDebugInfo DebugInfo: %p", pdbg));
103 pdbg->ThisSect = crit;
104 pdbg->CreatingThread = ODIN_GetCurrentThreadId();
105 pdbg->EnteredCount = 0;
106
107 pdbg->next = NULL;
108 pdbg->prev = cslast;
109 if (cslast)
110 {
111 cslast->next = pdbg;
112 }
113
114 cslast = pdbg;
115
116 if (!csfirst)
117 {
118 csfirst = pdbg;
119 }
120 }
121
122 crit->DebugInfo = pdbg;
123
124 ulCritSectCount++;
125 }
126
127 csmutex.leave();
128}
129
130void DeleteDebugInfo (CRITICAL_SECTION *crit)
131{
132 csmutex.enter();
133
134 CritSectDebug *pdbg = checkCritSectDebug (crit->DebugInfo);
135
136 if (pdbg)
137 {
138 dprintf(("Deleting critical section with DebugInfo == %p\n", pdbg));
139
140 if (pdbg->next)
141 {
142 pdbg->next->prev = pdbg->prev;
143 }
144 else
145 {
146 cslast = pdbg->prev;
147 }
148
149 if (pdbg->prev)
150 {
151 pdbg->prev->next = pdbg->next;
152 }
153 else
154 {
155 csfirst = pdbg->next;
156 }
157
158 _sfree (pdbg);
159
160 ulCritSectCount--;
161
162 crit->DebugInfo = NULL;
163 }
164
165 csmutex.leave();
166}
167
168void DebugEnterCritSect (CRITICAL_SECTION *crit)
169{
170 csmutex.enter();
171
172 CritSectDebug *pdbg = checkCritSectDebug (crit->DebugInfo);
173
174 if (!pdbg)
175 {
176 InitializeDebugInfo (crit);
177 pdbg = checkCritSectDebug (crit->DebugInfo);
178 }
179
180 if (pdbg)
181 {
182 pdbg->EnteredCount++;
183 }
184
185 csmutex.leave();
186}
187
188void DebugLeaveCritSect (CRITICAL_SECTION *crit)
189{
190 csmutex.enter();
191
192 CritSectDebug *pdbg = checkCritSectDebug (crit->DebugInfo);
193
194 if (pdbg)
195 {
196 pdbg->EnteredCount--;
197 }
198
199 csmutex.leave();
200}
201#else
202#define InitializeDebugInfo(a)
203#define DeleteDebugInfo(a)
204#define DebugEnterCritSect(a)
205#define DebugLeaveCritSect(a)
206#endif
207
208
209
210/***********************************************************************
211 * get_semaphore (allocate semaphore only when needed)
212 * Assign the semaphore atomically
213 */
214static inline HANDLE get_semaphore (CRITICAL_SECTION *crit)
215{
216 HANDLE ret = crit->LockSemaphore;
217
218 if (!ret)
219 {
220 HANDLE sem = CreateSemaphoreA (NULL, 0, 1, NULL);
221
222 if (sem)
223 {
224 ret = InterlockedCompareExchange ((PLONG)&crit->LockSemaphore, sem, NULL);
225
226 if (ret)
227 {
228 // semaphore already assigned
229 CloseHandle (sem);
230 }
231 else
232 {
233 ret = sem;
234 }
235 }
236 }
237
238 return ret;
239}
240
241extern "C" {
242
243/***********************************************************************
244 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
245 */
246void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
247{
248 dprintf(("InitializeCriticalSection %x", crit));
249
250 InitializeDebugInfo (crit);
251
252 crit->LockCount = -1;
253 crit->RecursionCount = 0;
254 crit->OwningThread = 0;
255 crit->LockSemaphore = 0;
256 crit->Reserved = 0;
257}
258
259/***********************************************************************
260 * InitializeCriticalSectionAndSpinCount (NTDLL.@)
261 * The InitializeCriticalSectionAndSpinCount (KERNEL32) function is
262 * available on NT4SP3 or later, and Win98 or later.
263 * I am assuming that this is the correct definition given the MSDN
264 * docs for the kernel32 functions.
265 */
266BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
267{
268 if (spincount) dprintf(("critsection=%p: spincount=%ld not supported\n", crit, spincount));
269 InitializeCriticalSection( crit );
270 crit->Reserved = spincount;
271 return TRUE;
272}
273
274/***********************************************************************
275 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
276 */
277void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
278{
279 dprintf(("DeleteCriticalSection %x", crit));
280
281 DeleteDebugInfo (crit);
282
283 if (crit->RecursionCount) /* Should not happen */
284 dprintf(("Deleting owned critical section (%p)\n", crit ));
285
286 crit->LockCount = -1;
287 crit->RecursionCount = 0;
288 crit->OwningThread = 0;
289 if (crit->LockSemaphore) CloseHandle( crit->LockSemaphore );
290 crit->LockSemaphore = 0;
291 crit->Reserved = 0;
292}
293
294
295/***********************************************************************
296 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
297 */
298void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
299{
300 dprintf2(("EnterCriticalSection %x", crit));
301
302#if 0
303 /* bird: this is bullcrap, memset(&MyCritSect, 0, sizeof(MyCritSect)) doesn't work in w2k (at least not here).
304 * besides this isn't safe. The leave code first sets owner=0 then decrements the lock, heavens knows what
305 * will happen if the thread is preemted there...
306 */
307 // check for uninitialized critical section created with memset (, 0, )
308 if (crit->LockCount != -1 && crit->OwningThread == 0)
309 {
310 dprintf(("Uninitialized section!!!"));
311 __interrupt(3);
312 InitializeCriticalSection (crit);
313 }
314#endif
315
316 DebugEnterCritSect (crit);
317
318 if (InterlockedIncrement (&crit->LockCount))
319 {
320 if (crit->OwningThread == ODIN_GetCurrentThreadId())
321 {
322 crit->RecursionCount++;
323 return;
324 }
325
326 /* Now wait for it */
327 for (;;)
328 {
329 HANDLE sem = get_semaphore (crit);
330 DWORD res = WaitForSingleObject (sem, 5000L);
331
332 if (res == WAIT_TIMEOUT)
333 {
334 dprintf(("Critical section %p wait timed out, retrying (60 sec)\n", crit));
335 res = WaitForSingleObject (sem, 60000L);
336 if (res == WAIT_TIMEOUT && TRACE_ON(relay))
337 {
338 dprintf(("Critical section %p wait timed out, retrying (5 min)\n", crit));
339 res = WaitForSingleObject (sem, 300000L);
340 }
341 }
342
343 if (res == STATUS_WAIT_0) break;
344
345#if 0
346 EXCEPTION_RECORD rec;
347
348 rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
349 rec.ExceptionFlags = 0;
350 rec.ExceptionRecord = NULL;
351 rec.ExceptionAddress = RaiseException; /* sic */
352 rec.NumberParameters = 1;
353 rec.ExceptionInformation[0] = (DWORD)crit;
354 RtlRaiseException( &rec );
355#endif
356 dprintf(("ERROR: EnterCritSection: WaitForSingleObject returned %d -> RaiseException", res));
357 RaiseException(EXCEPTION_CRITICAL_SECTION_WAIT, 0, 1, (DWORD *)&crit);
358 }
359 }
360
361 crit->OwningThread = ODIN_GetCurrentThreadId();
362 crit->RecursionCount = 1;
363}
364
365
366/***********************************************************************
367 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
368 */
369BOOL WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
370{
371 BOOL ret = FALSE;
372
373 dprintf2(("TryEnterCriticalSection %x", crit));
374
375 if (InterlockedCompareExchange (&crit->LockCount, 0, -1) == -1)
376 {
377 // LockCount was successfully changed from -1 to 0 and we own the section now
378 crit->OwningThread = ODIN_GetCurrentThreadId();
379 crit->RecursionCount = 1;
380 ret = TRUE;
381 }
382 else
383 {
384 if (crit->OwningThread == ODIN_GetCurrentThreadId())
385 {
386 InterlockedIncrement (&crit->LockCount);
387 crit->RecursionCount++;
388 ret = TRUE;
389 }
390 }
391
392 if (ret) DebugEnterCritSect (crit);
393
394 return ret;
395}
396
397
398/***********************************************************************
399 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
400 */
401void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
402{
403 dprintf2(("LeaveCriticalSection %x", crit));
404
405 DebugLeaveCritSect (crit);
406
407 /*
408 * Wine and Windows don't check if the caller is the owner.
409 * We leave this check in for debugging since odin32 may use this
410 * internally and it's good to know if we mess up.
411 */
412#ifdef DEBUG
413 if (crit->OwningThread != ODIN_GetCurrentThreadId())
414 {
415 dprintf(("LeaveCriticalSection: Not owner!! OwningThread=%d CurThread=%d\n", crit->OwningThread, ODIN_GetCurrentThreadId()));
416 DebugInt3();
417 return;
418 }
419#endif
420
421 if (--crit->RecursionCount)
422 {
423 InterlockedDecrement(&crit->LockCount);
424 return;
425 }
426
427 crit->OwningThread = 0;
428
429 if (InterlockedDecrement( &crit->LockCount ) >= 0)
430 {
431 /* Someone is waiting */
432 HANDLE sem = get_semaphore (crit);
433 ReleaseSemaphore (sem, 1, NULL);
434 }
435}
436
437
438/***********************************************************************
439 * MakeCriticalSectionGlobal (KERNEL32.515)
440 */
441void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
442{
443 dprintf(("MakeCriticalSectionGlobal %x", crit));
444
445 HANDLE sem = get_semaphore(crit);
446
447 crit->LockSemaphore = ConvertToGlobalHandle (sem);
448}
449
450
451/***********************************************************************
452 * ReinitializeCriticalSection (KERNEL32.581)
453 */
454void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
455{
456 dprintf(("ReinitializeCriticalSection %x", crit));
457
458 if (!crit->LockSemaphore)
459 {
460 InitializeCriticalSection (crit);
461 }
462}
463
464
465/***********************************************************************
466 * UninitializeCriticalSection (KERNEL32.703)
467 */
468void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
469{
470 dprintf(("UninitializeCriticalSection %x", crit));
471 DeleteCriticalSection (crit);
472}
473
474} // extern "C"
475
Note: See TracBrowser for help on using the repository browser.