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

Last change on this file since 21388 was 21302, checked in by ydario, 16 years ago

Kernel32 updates.

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
241/***********************************************************************
242 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
243 */
244void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
245{
246 dprintf(("InitializeCriticalSection %x", crit));
247
248 InitializeDebugInfo (crit);
249
250 crit->LockCount = -1;
251 crit->RecursionCount = 0;
252 crit->OwningThread = 0;
253 crit->LockSemaphore = 0;
254 crit->Reserved = 0;
255}
256
257/***********************************************************************
258 * InitializeCriticalSectionAndSpinCount (NTDLL.@)
259 * The InitializeCriticalSectionAndSpinCount (KERNEL32) function is
260 * available on NT4SP3 or later, and Win98 or later.
261 * I am assuming that this is the correct definition given the MSDN
262 * docs for the kernel32 functions.
263 */
264BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
265{
266 if (spincount) dprintf(("critsection=%p: spincount=%ld not supported\n", crit, spincount));
267 InitializeCriticalSection( crit );
268 crit->Reserved = spincount;
269 return TRUE;
270}
271
272/***********************************************************************
273 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
274 */
275void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
276{
277 dprintf(("DeleteCriticalSection %x", crit));
278
279 DeleteDebugInfo (crit);
280
281 if (crit->RecursionCount) /* Should not happen */
282 dprintf(("Deleting owned critical section (%p)\n", crit ));
283
284 crit->LockCount = -1;
285 crit->RecursionCount = 0;
286 crit->OwningThread = 0;
287 if (crit->LockSemaphore) CloseHandle( crit->LockSemaphore );
288 crit->LockSemaphore = 0;
289 crit->Reserved = 0;
290}
291
292
293/***********************************************************************
294 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
295 */
296void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
297{
298 dprintf2(("EnterCriticalSection %x", crit));
299
300#if 0
301 /* bird: this is bullcrap, memset(&MyCritSect, 0, sizeof(MyCritSect)) doesn't work in w2k (at least not here).
302 * besides this isn't safe. The leave code first sets owner=0 then decrements the lock, heavens knows what
303 * will happen if the thread is preemted there...
304 */
305 // check for uninitialized critical section created with memset (, 0, )
306 if (crit->LockCount != -1 && crit->OwningThread == 0)
307 {
308 dprintf(("Uninitialized section!!!"));
309 __interrupt(3);
310 InitializeCriticalSection (crit);
311 }
312#endif
313
314 DebugEnterCritSect (crit);
315
316 if (InterlockedIncrement (&crit->LockCount))
317 {
318 if (crit->OwningThread == ODIN_GetCurrentThreadId())
319 {
320 crit->RecursionCount++;
321 return;
322 }
323
324 /* Now wait for it */
325 for (;;)
326 {
327 HANDLE sem = get_semaphore (crit);
328 DWORD res = WaitForSingleObject (sem, 5000L);
329
330 if (res == WAIT_TIMEOUT)
331 {
332 dprintf(("Critical section %p wait timed out, retrying (60 sec)\n", crit));
333 res = WaitForSingleObject (sem, 60000L);
334 if (res == WAIT_TIMEOUT && TRACE_ON(relay))
335 {
336 dprintf(("Critical section %p wait timed out, retrying (5 min)\n", crit));
337 res = WaitForSingleObject (sem, 300000L);
338 }
339 }
340
341 if (res == STATUS_WAIT_0) break;
342
343#if 0
344 EXCEPTION_RECORD rec;
345
346 rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
347 rec.ExceptionFlags = 0;
348 rec.ExceptionRecord = NULL;
349 rec.ExceptionAddress = RaiseException; /* sic */
350 rec.NumberParameters = 1;
351 rec.ExceptionInformation[0] = (DWORD)crit;
352 RtlRaiseException( &rec );
353#endif
354 dprintf(("ERROR: EnterCritSection: WaitForSingleObject returned %d -> RaiseException", res));
355 RaiseException(EXCEPTION_CRITICAL_SECTION_WAIT, 0, 1, (DWORD *)&crit);
356 }
357 }
358
359 crit->OwningThread = ODIN_GetCurrentThreadId();
360 crit->RecursionCount = 1;
361}
362
363
364/***********************************************************************
365 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
366 */
367BOOL WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
368{
369 BOOL ret = FALSE;
370
371 dprintf2(("TryEnterCriticalSection %x", crit));
372
373 if (InterlockedCompareExchange (&crit->LockCount, 0, -1) == -1)
374 {
375 // LockCount was successfully changed from -1 to 0 and we own the section now
376 crit->OwningThread = ODIN_GetCurrentThreadId();
377 crit->RecursionCount = 1;
378 ret = TRUE;
379 }
380 else
381 {
382 if (crit->OwningThread == ODIN_GetCurrentThreadId())
383 {
384 InterlockedIncrement (&crit->LockCount);
385 crit->RecursionCount++;
386 ret = TRUE;
387 }
388 }
389
390 if (ret) DebugEnterCritSect (crit);
391
392 return ret;
393}
394
395
396/***********************************************************************
397 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
398 */
399void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
400{
401 dprintf2(("LeaveCriticalSection %x", crit));
402
403 DebugLeaveCritSect (crit);
404
405 /*
406 * Wine and Windows don't check if the caller is the owner.
407 * We leave this check in for debugging since odin32 may use this
408 * internally and it's good to know if we mess up.
409 */
410#ifdef DEBUG
411 if (crit->OwningThread != ODIN_GetCurrentThreadId())
412 {
413 dprintf(("LeaveCriticalSection: Not owner!! OwningThread=%d CurThread=%d\n", crit->OwningThread, ODIN_GetCurrentThreadId()));
414 DebugInt3();
415 return;
416 }
417#endif
418
419 if (--crit->RecursionCount)
420 {
421 InterlockedDecrement(&crit->LockCount);
422 return;
423 }
424
425 crit->OwningThread = 0;
426
427 if (InterlockedDecrement( &crit->LockCount ) >= 0)
428 {
429 /* Someone is waiting */
430 HANDLE sem = get_semaphore (crit);
431 ReleaseSemaphore (sem, 1, NULL);
432 }
433}
434
435
436/***********************************************************************
437 * MakeCriticalSectionGlobal (KERNEL32.515)
438 */
439void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
440{
441 dprintf(("MakeCriticalSectionGlobal %x", crit));
442
443 HANDLE sem = get_semaphore(crit);
444
445 crit->LockSemaphore = ConvertToGlobalHandle (sem);
446}
447
448
449/***********************************************************************
450 * ReinitializeCriticalSection (KERNEL32.581)
451 */
452void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
453{
454 dprintf(("ReinitializeCriticalSection %x", crit));
455
456 if (!crit->LockSemaphore)
457 {
458 InitializeCriticalSection (crit);
459 }
460}
461
462
463/***********************************************************************
464 * UninitializeCriticalSection (KERNEL32.703)
465 */
466void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
467{
468 dprintf(("UninitializeCriticalSection %x", crit));
469 DeleteCriticalSection (crit);
470}
471
Note: See TracBrowser for help on using the repository browser.