VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/critsect-generic.cpp@ 25046

Last change on this file since 25046 was 23718, checked in by vboxsync, 15 years ago

critsect-generic.cpp: Don't use AssertMsgFailed on nested entry since the logger may end up here if we assert while formatting the message for a previous assertion (happens when you get a format type wrong).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1/* $Id: critsect-generic.cpp 23718 2009-10-13 12:36:13Z vboxsync $ */
2/** @file
3 * IPRT - Critical Section, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/critsect.h>
36#include "internal/iprt.h"
37
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include <iprt/err.h>
43#include "internal/thread.h"
44#include "internal/strict.h"
45
46
47/* in strict mode we're redefining this, so undefine it now for the implementation. */
48#undef RTCritSectEnter
49#undef RTCritSectTryEnter
50#undef RTCritSectEnterMultiple
51
52
53/**
54 * Initialize a critical section.
55 */
56RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
57{
58 return RTCritSectInitEx(pCritSect, 0);
59}
60RT_EXPORT_SYMBOL(RTCritSectInit);
61
62
63/**
64 * Initialize a critical section.
65 *
66 * @returns iprt status code.
67 * @param pCritSect Pointer to the critical section structure.
68 * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS \#defines.
69 */
70RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags)
71{
72 /*
73 * Initialize the structure and
74 */
75 pCritSect->u32Magic = RTCRITSECT_MAGIC;
76 pCritSect->fFlags = fFlags;
77 pCritSect->cNestings = 0;
78 pCritSect->cLockers = -1;
79 pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
80 pCritSect->Strict.ThreadOwner = NIL_RTTHREAD;
81 pCritSect->Strict.pszEnterFile = NULL;
82 pCritSect->Strict.u32EnterLine = 0;
83 pCritSect->Strict.uEnterId = 0;
84 int rc = RTSemEventCreate(&pCritSect->EventSem);
85 if (RT_SUCCESS(rc))
86 return VINF_SUCCESS;
87
88 AssertRC(rc);
89 pCritSect->EventSem = NULL;
90 pCritSect->u32Magic = (uint32_t)rc;
91 return rc;
92}
93RT_EXPORT_SYMBOL(RTCritSectInitEx);
94
95
96/**
97 * Enter multiple critical sections.
98 *
99 * This function will enter ALL the specified critical sections before returning.
100 *
101 * @returns VINF_SUCCESS on success.
102 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
103 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
104 * @param cCritSects Number of critical sections in the array.
105 * @param papCritSects Array of critical section pointers.
106 *
107 * @remark Please note that this function will not necessarily come out favourable in a
108 * fight with other threads which are using the normal RTCritSectEnter() function.
109 * Therefore, avoid having to enter multiple critical sections!
110 */
111RTDECL(int) RTCritSectEnterMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
112#ifdef RTCRITSECT_STRICT
113{
114 return RTCritSectEnterMultipleDebug(cCritSects, papCritSects, __FILE__, __LINE__, 0);
115}
116RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
117#endif /* RTCRITSECT_STRICT */
118{
119 Assert(cCritSects > 0);
120 Assert(VALID_PTR(papCritSects));
121
122 /*
123 * Try get them all.
124 */
125 int rc = VERR_INVALID_PARAMETER;
126 unsigned i;
127 for (i = 0; i < cCritSects; i++)
128 {
129#ifdef RTCRITSECT_STRICT
130 rc = RTCritSectTryEnterDebug(papCritSects[i], pszFile, uLine, uId);
131#else
132 rc = RTCritSectTryEnter(papCritSects[i]);
133#endif
134 if (RT_FAILURE(rc))
135 break;
136 }
137 if (RT_SUCCESS(rc))
138 return rc;
139
140 /*
141 * The retry loop.
142 */
143 for (unsigned cTries = 0; ; cTries++)
144 {
145 /*
146 * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
147 */
148 unsigned j = i;
149 while (j-- > 0)
150 {
151 int rc2 = RTCritSectLeave(papCritSects[j]);
152 AssertRC(rc2);
153 }
154 if (rc != VERR_SEM_BUSY)
155 return rc;
156
157 /*
158 * Try prevent any theoretical synchronous races with other threads.
159 */
160 Assert(cTries < 1000000);
161 if (cTries > 10000)
162 RTThreadSleep(cTries % 3);
163
164 /*
165 * Wait on the one we failed to get.
166 */
167#ifdef RTCRITSECT_STRICT
168 rc = RTCritSectEnterDebug(papCritSects[i], pszFile, uLine, uId);
169#else
170 rc = RTCritSectEnter(papCritSects[i]);
171#endif
172 if (RT_FAILURE(rc))
173 return rc;
174
175 /*
176 * Try take the others.
177 */
178 for (j = 0; j < cCritSects; j++)
179 {
180 if (j != i)
181 {
182#ifdef RTCRITSECT_STRICT
183 rc = RTCritSectTryEnterDebug(papCritSects[j], pszFile, uLine, uId);
184#else
185 rc = RTCritSectTryEnter(papCritSects[j]);
186#endif
187 if (RT_FAILURE(rc))
188 break;
189 }
190 }
191 if (RT_SUCCESS(rc))
192 return rc;
193
194 /*
195 * We failed.
196 */
197 if (i > j)
198 {
199 int rc2 = RTCritSectLeave(papCritSects[i]);
200 AssertRC(rc2);
201 }
202 i = j;
203 }
204}
205RT_EXPORT_SYMBOL(RTCritSectEnterMultiple);
206
207
208/**
209 * Try enter a critical section.
210 *
211 * @returns VINF_SUCCESS on success.
212 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
213 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
214 * @param pCritSect The critical section.
215 */
216RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
217#ifdef RTCRITSECT_STRICT
218{
219 return RTCritSectTryEnterDebug(pCritSect, __FILE__, __LINE__, 0);
220}
221RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
222#endif /* RTCRITSECT_STRICT */
223{
224 Assert(pCritSect);
225 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
226 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
227#ifdef RTCRITSECT_STRICT
228 RTTHREAD ThreadSelf = RTThreadSelf();
229 if (ThreadSelf == NIL_RTTHREAD)
230 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
231#endif
232
233 /*
234 * Try take the lock. (cLockers is -1 if it's free)
235 */
236 if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
237 {
238 /*
239 * Somebody is owning it (or will be soon). Perhaps it's us?
240 */
241 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
242 {
243 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
244 {
245 ASMAtomicIncS32(&pCritSect->cLockers);
246 pCritSect->cNestings++;
247 return VINF_SUCCESS;
248 }
249 AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
250 return VERR_SEM_NESTED;
251 }
252 return VERR_SEM_BUSY;
253 }
254
255 /*
256 * First time
257 */
258 pCritSect->cNestings = 1;
259 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
260#ifdef RTCRITSECT_STRICT
261 pCritSect->Strict.pszEnterFile = pszFile;
262 pCritSect->Strict.u32EnterLine = uLine;
263 pCritSect->Strict.uEnterId = uId;
264 ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, ThreadSelf);
265#endif
266
267 return VINF_SUCCESS;
268}
269RT_EXPORT_SYMBOL(RTCritSectTryEnter);
270
271
272/**
273 * Enter a critical section.
274 *
275 * @returns VINF_SUCCESS on success.
276 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
277 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
278 * @param pCritSect The critical section.
279 */
280RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect)
281#ifdef RTCRITSECT_STRICT
282{
283 return RTCritSectEnterDebug(pCritSect, __FILE__, __LINE__, 0);
284}
285RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
286#endif /* RTCRITSECT_STRICT */
287{
288 Assert(pCritSect);
289 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
290 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
291#ifdef RTCRITSECT_STRICT
292 RTTHREAD ThreadSelf = RTThreadSelf();
293 if (ThreadSelf == NIL_RTTHREAD)
294 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
295#endif
296
297 /** If the critical section has already been destroyed, then inform the caller. */
298 if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
299 return VERR_SEM_DESTROYED;
300
301 /*
302 * Increment the waiter counter.
303 * This becomes 0 when the section is free.
304 */
305 if (ASMAtomicIncS32(&pCritSect->cLockers) > 0)
306 {
307 /*
308 * Nested?
309 */
310 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
311 {
312 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
313 {
314 pCritSect->cNestings++;
315 return VINF_SUCCESS;
316 }
317
318 AssertBreakpoint(); /* don't do normal assertion here, the logger uses this code too. */
319 ASMAtomicDecS32(&pCritSect->cLockers);
320 return VERR_SEM_NESTED;
321 }
322
323 for (;;)
324 {
325#ifdef RTCRITSECT_STRICT
326 RTThreadBlocking(ThreadSelf, RTTHREADSTATE_CRITSECT, (uintptr_t)pCritSect, pszFile, uLine, uId);
327#endif
328 int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
329#ifdef RTCRITSECT_STRICT
330 RTThreadUnblocked(ThreadSelf, RTTHREADSTATE_CRITSECT);
331#endif
332 if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
333 return VERR_SEM_DESTROYED;
334 if (rc == VINF_SUCCESS)
335 break;
336 AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
337 }
338 AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
339 }
340
341 /*
342 * First time
343 */
344 pCritSect->cNestings = 1;
345 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
346#ifdef RTCRITSECT_STRICT
347 pCritSect->Strict.pszEnterFile = pszFile;
348 pCritSect->Strict.u32EnterLine = uLine;
349 pCritSect->Strict.uEnterId = uId;
350 ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, ThreadSelf);
351 RTThreadWriteLockInc(ThreadSelf);
352#endif
353
354 return VINF_SUCCESS;
355}
356RT_EXPORT_SYMBOL(RTCritSectEnter);
357
358
359/**
360 * Leave a critical section.
361 *
362 * @returns VINF_SUCCESS.
363 * @param pCritSect The critical section.
364 */
365RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect)
366{
367 /*
368 * Assert ownership and so on.
369 */
370 Assert(pCritSect);
371 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
372 Assert(pCritSect->cNestings > 0);
373 Assert(pCritSect->cLockers >= 0);
374 Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
375
376 /*
377 * Decrement nestings, if <= 0 when we'll release the critsec.
378 */
379 pCritSect->cNestings--;
380 if (pCritSect->cNestings > 0)
381 ASMAtomicDecS32(&pCritSect->cLockers);
382 else
383 {
384 /*
385 * Set owner to zero.
386 * Decrement waiters, if >= 0 then we have to wake one of them up.
387 */
388#ifdef RTCRITSECT_STRICT
389 if (pCritSect->Strict.ThreadOwner != NIL_RTTHREAD) /* May happen for PDMCritSects when entering GC/R0. */
390 RTThreadWriteLockDec(pCritSect->Strict.ThreadOwner);
391 ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, NIL_RTTHREAD);
392#endif
393 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
394 if (ASMAtomicDecS32(&pCritSect->cLockers) >= 0)
395 {
396 int rc = RTSemEventSignal(pCritSect->EventSem);
397 AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
398 }
399 }
400 return VINF_SUCCESS;
401}
402RT_EXPORT_SYMBOL(RTCritSectLeave);
403
404
405/**
406 * Leave multiple critical sections.
407 *
408 * @returns VINF_SUCCESS.
409 * @param cCritSects Number of critical sections in the array.
410 * @param papCritSects Array of critical section pointers.
411 */
412RTDECL(int) RTCritSectLeaveMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
413{
414 int rc = VINF_SUCCESS;
415 for (unsigned i = 0; i < cCritSects; i++)
416 {
417 int rc2 = RTCritSectLeave(papCritSects[i]);
418 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
419 rc = rc2;
420 }
421 return rc;
422}
423RT_EXPORT_SYMBOL(RTCritSectLeaveMultiple);
424
425
426#ifndef RTCRITSECT_STRICT
427RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
428{
429 return RTCritSectEnter(pCritSect);
430}
431
432RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
433{
434 return RTCritSectTryEnter(pCritSect);
435}
436
437RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
438{
439 return RTCritSectEnterMultiple(cCritSects, papCritSects);
440}
441#endif /* RT_STRICT */
442RT_EXPORT_SYMBOL(RTCritSectEnterDebug);
443RT_EXPORT_SYMBOL(RTCritSectTryEnterDebug);
444RT_EXPORT_SYMBOL(RTCritSectEnterMultipleDebug);
445
446
447/**
448 * Deletes a critical section.
449 *
450 * @returns VINF_SUCCESS.
451 * @param pCritSect The critical section.
452 */
453RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
454{
455 /*
456 * Assert free waiters and so on.
457 */
458 Assert(pCritSect);
459 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
460 Assert(pCritSect->cNestings == 0);
461 Assert(pCritSect->cLockers == -1);
462 Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
463
464 /*
465 * Invalidate the structure and free the mutex.
466 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
467 */
468 ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
469 pCritSect->fFlags = 0;
470 pCritSect->cNestings = 0;
471 pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
472 RTSEMEVENT EventSem = pCritSect->EventSem;
473 pCritSect->EventSem = NIL_RTSEMEVENT;
474 while (pCritSect->cLockers-- >= 0)
475 RTSemEventSignal(EventSem);
476 ASMAtomicWriteS32(&pCritSect->cLockers, -1);
477 int rc = RTSemEventDestroy(EventSem);
478 AssertRC(rc);
479
480 return rc;
481}
482RT_EXPORT_SYMBOL(RTCritSectDelete);
483
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette