1
/* $Id: critsect-generic.cpp $ */
3
* IPRT - Critical Section, Generic.
7
* Copyright (C) 2006-2011 Oracle Corporation
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.
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.
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.
28
/*******************************************************************************
30
*******************************************************************************/
31
#define RTCRITSECT_WITHOUT_REMAPPING
32
#include <iprt/critsect.h>
33
#include "internal/iprt.h"
35
#include <iprt/semaphore.h>
36
#include <iprt/thread.h>
37
#include <iprt/assert.h>
40
#include "internal/thread.h"
41
#include "internal/strict.h"
44
RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
46
return RTCritSectInitEx(pCritSect, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTCritSect");
48
RT_EXPORT_SYMBOL(RTCritSectInit);
51
RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass,
52
const char *pszNameFmt, ...)
54
AssertReturn(!(fFlags & ~(RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK | RTCRITSECT_FLAGS_NOP)),
55
VERR_INVALID_PARAMETER);
58
* Initialize the structure and
60
pCritSect->u32Magic = RTCRITSECT_MAGIC;
61
pCritSect->fFlags = fFlags;
62
pCritSect->cNestings = 0;
63
pCritSect->cLockers = -1;
64
pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
65
pCritSect->pValidatorRec = NULL;
66
int rc = VINF_SUCCESS;
67
#ifdef RTCRITSECT_STRICT
68
if (!(fFlags & (RTCRITSECT_FLAGS_BOOTSTRAP_HACK | RTCRITSECT_FLAGS_NOP)))
72
static uint32_t volatile s_iCritSectAnon = 0;
73
rc = RTLockValidatorRecExclCreate(&pCritSect->pValidatorRec, hClass, uSubClass, pCritSect,
74
!(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL),
75
"RTCritSect-%u", ASMAtomicIncU32(&s_iCritSectAnon) - 1);
80
va_start(va, pszNameFmt);
81
rc = RTLockValidatorRecExclCreateV(&pCritSect->pValidatorRec, hClass, uSubClass, pCritSect,
82
!(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL), pszNameFmt, va);
89
rc = RTSemEventCreateEx(&pCritSect->EventSem,
90
fFlags & RTCRITSECT_FLAGS_BOOTSTRAP_HACK
91
? RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK
92
: RTSEMEVENT_FLAGS_NO_LOCK_VAL,
97
RTLockValidatorRecExclDestroy(&pCritSect->pValidatorRec);
101
pCritSect->EventSem = NULL;
102
pCritSect->u32Magic = (uint32_t)rc;
105
RT_EXPORT_SYMBOL(RTCritSectInitEx);
108
RTDECL(uint32_t) RTCritSectSetSubClass(PRTCRITSECT pCritSect, uint32_t uSubClass)
110
#ifdef RTCRITSECT_STRICT
111
AssertPtrReturn(pCritSect, RTLOCKVAL_SUB_CLASS_INVALID);
112
AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
113
AssertReturn(!(pCritSect->fFlags & RTCRITSECT_FLAGS_NOP), RTLOCKVAL_SUB_CLASS_INVALID);
114
return RTLockValidatorRecExclSetSubClass(pCritSect->pValidatorRec, uSubClass);
116
return RTLOCKVAL_SUB_CLASS_INVALID;
121
DECL_FORCE_INLINE(int) rtCritSectTryEnter(PRTCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos)
124
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
125
/*AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, VERR_SEM_DESTROYED);*/
128
* Return straight away if NOP.
130
if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
134
* Try take the lock. (cLockers is -1 if it's free)
136
RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
137
if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
140
* Somebody is owning it (or will be soon). Perhaps it's us?
142
if (pCritSect->NativeThreadOwner == NativeThreadSelf)
144
if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
146
#ifdef RTCRITSECT_STRICT
147
int rc9 = RTLockValidatorRecExclRecursion(pCritSect->pValidatorRec, pSrcPos);
151
ASMAtomicIncS32(&pCritSect->cLockers);
152
pCritSect->cNestings++;
155
AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
156
return VERR_SEM_NESTED;
158
return VERR_SEM_BUSY;
164
pCritSect->cNestings = 1;
165
ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
166
#ifdef RTCRITSECT_STRICT
167
RTLockValidatorRecExclSetOwner(pCritSect->pValidatorRec, NIL_RTTHREAD, pSrcPos, true);
174
RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
176
#ifndef RTCRTISECT_STRICT
177
return rtCritSectTryEnter(pCritSect, NULL);
179
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
180
return rtCritSectTryEnter(pCritSect, &SrcPos);
183
RT_EXPORT_SYMBOL(RTCritSectTryEnter);
186
RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
188
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
189
return rtCritSectTryEnter(pCritSect, &SrcPos);
191
RT_EXPORT_SYMBOL(RTCritSectTryEnterDebug);
194
DECL_FORCE_INLINE(int) rtCritSectEnter(PRTCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos)
196
AssertPtr(pCritSect);
197
AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, VERR_SEM_DESTROYED);
200
* Return straight away if NOP.
202
if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
206
* How is calling and is the order right?
208
RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
209
#ifdef RTCRITSECT_STRICT
210
RTTHREAD hThreadSelf = pCritSect->pValidatorRec
211
? RTThreadSelfAutoAdopt()
214
if (pCritSect->pValidatorRec) /* (bootstap) */
216
rc9 = RTLockValidatorRecExclCheckOrder(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
223
* Increment the waiter counter.
224
* This becomes 0 when the section is free.
226
if (ASMAtomicIncS32(&pCritSect->cLockers) > 0)
231
if (pCritSect->NativeThreadOwner == NativeThreadSelf)
233
if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
235
#ifdef RTCRITSECT_STRICT
236
rc9 = RTLockValidatorRecExclRecursion(pCritSect->pValidatorRec, pSrcPos);
239
ASMAtomicDecS32(&pCritSect->cLockers);
243
pCritSect->cNestings++;
247
AssertBreakpoint(); /* don't do normal assertion here, the logger uses this code too. */
248
ASMAtomicDecS32(&pCritSect->cLockers);
249
return VERR_SEM_NESTED;
253
* Wait for the current owner to release it.
255
#ifndef RTCRITSECT_STRICT
256
RTTHREAD hThreadSelf = RTThreadSelf();
260
#ifdef RTCRITSECT_STRICT
261
rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->pValidatorRec, hThreadSelf, pSrcPos,
262
!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING),
263
RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, false);
266
ASMAtomicDecS32(&pCritSect->cLockers);
270
RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, false);
272
int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
273
RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
275
if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
276
return VERR_SEM_DESTROYED;
277
if (rc == VINF_SUCCESS)
279
AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
281
AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
287
pCritSect->cNestings = 1;
288
ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
289
#ifdef RTCRITSECT_STRICT
290
RTLockValidatorRecExclSetOwner(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, true);
297
RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect)
299
#ifndef RTCRITSECT_STRICT
300
return rtCritSectEnter(pCritSect, NULL);
302
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
303
return rtCritSectEnter(pCritSect, &SrcPos);
306
RT_EXPORT_SYMBOL(RTCritSectEnter);
309
RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
311
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
312
return rtCritSectEnter(pCritSect, &SrcPos);
314
RT_EXPORT_SYMBOL(RTCritSectEnterDebug);
317
RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect)
320
* Assert sanity and check for NOP.
323
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
324
if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
328
* Assert ownership and so on.
330
Assert(pCritSect->cNestings > 0);
331
Assert(pCritSect->cLockers >= 0);
332
Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
334
#ifdef RTCRITSECT_STRICT
335
int rc9 = RTLockValidatorRecExclReleaseOwner(pCritSect->pValidatorRec, pCritSect->cNestings == 1);
341
* Decrement nestings, if <= 0 when we'll release the critsec.
343
pCritSect->cNestings--;
344
if (pCritSect->cNestings > 0)
345
ASMAtomicDecS32(&pCritSect->cLockers);
350
* Decrement waiters, if >= 0 then we have to wake one of them up.
352
ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
353
if (ASMAtomicDecS32(&pCritSect->cLockers) >= 0)
355
int rc = RTSemEventSignal(pCritSect->EventSem);
356
AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
361
RT_EXPORT_SYMBOL(RTCritSectLeave);
367
static int rtCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects, PCRTLOCKVALSRCPOS pSrcPos)
369
Assert(cCritSects > 0);
370
AssertPtr(papCritSects);
375
int rc = VERR_INVALID_PARAMETER;
377
for (i = 0; i < cCritSects; i++)
379
rc = rtCritSectTryEnter(papCritSects[i], pSrcPos);
389
for (unsigned cTries = 0; ; cTries++)
392
* We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
397
int rc2 = RTCritSectLeave(papCritSects[j]);
400
if (rc != VERR_SEM_BUSY)
404
* Try prevent any theoretical synchronous races with other threads.
406
Assert(cTries < 1000000);
408
RTThreadSleep(cTries % 3);
411
* Wait on the one we failed to get.
413
rc = rtCritSectEnter(papCritSects[i], pSrcPos);
418
* Try take the others.
420
for (j = 0; j < cCritSects; j++)
424
rc = rtCritSectTryEnter(papCritSects[j], pSrcPos);
437
int rc2 = RTCritSectLeave(papCritSects[i]);
445
RTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
447
#ifndef RTCRITSECT_STRICT
448
return rtCritSectEnterMultiple(cCritSects, papCritSects, NULL);
450
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
451
return rtCritSectEnterMultiple(cCritSects, papCritSects, &SrcPos);
454
RT_EXPORT_SYMBOL(RTCritSectEnterMultiple);
457
RTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTUINTPTR uId, RT_SRC_POS_DECL)
459
RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
460
return rtCritSectEnterMultiple(cCritSects, papCritSects, &SrcPos);
462
RT_EXPORT_SYMBOL(RTCritSectEnterMultipleDebug);
466
RTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
468
int rc = VINF_SUCCESS;
469
for (size_t i = 0; i < cCritSects; i++)
471
int rc2 = RTCritSectLeave(papCritSects[i]);
472
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
477
RT_EXPORT_SYMBOL(RTCritSectLeaveMultiple);
480
RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
483
* Assert free waiters and so on.
486
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
487
Assert(pCritSect->cNestings == 0);
488
Assert(pCritSect->cLockers == -1);
489
Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
492
* Invalidate the structure and free the mutex.
493
* In case someone is waiting we'll signal the semaphore cLockers + 1 times.
495
ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
496
pCritSect->fFlags = 0;
497
pCritSect->cNestings = 0;
498
pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
499
RTSEMEVENT EventSem = pCritSect->EventSem;
500
pCritSect->EventSem = NIL_RTSEMEVENT;
502
while (pCritSect->cLockers-- >= 0)
503
RTSemEventSignal(EventSem);
504
ASMAtomicWriteS32(&pCritSect->cLockers, -1);
505
int rc = RTSemEventDestroy(EventSem);
508
RTLockValidatorRecExclDestroy(&pCritSect->pValidatorRec);
512
RT_EXPORT_SYMBOL(RTCritSectDelete);