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

Last change on this file since 22021 was 22021, checked in by dmik, 13 years ago

kernel32: Fix annoying debug msg related to CRITICAL_SECTION.

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