VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.6 KB
Line 
1/* $Id: critsect-generic.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - Critical Section, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define RTCRITSECT_WITHOUT_REMAPPING
32#include <iprt/critsect.h>
33#include "internal/iprt.h"
34
35#include <iprt/semaphore.h>
36#include <iprt/thread.h>
37#include <iprt/assert.h>
38#include <iprt/asm.h>
39#include <iprt/err.h>
40#include "internal/thread.h"
41#include "internal/strict.h"
42
43
44RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
45{
46 return RTCritSectInitEx(pCritSect, 0, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTCritSect");
47}
48RT_EXPORT_SYMBOL(RTCritSectInit);
49
50
51RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags, RTLOCKVALCLASS hClass, uint32_t uSubClass,
52 const char *pszNameFmt, ...)
53{
54 AssertReturn(!(fFlags & ~(RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_BOOTSTRAP_HACK | RTCRITSECT_FLAGS_NOP)),
55 VERR_INVALID_PARAMETER);
56
57 /*
58 * Initialize the structure and
59 */
60 pCritSect->u32Magic = RTCRITSECT_MAGIC;
61#ifdef IN_RING0
62 pCritSect->fFlags = fFlags | RTCRITSECT_FLAGS_RING0;
63#else
64 pCritSect->fFlags = fFlags & ~RTCRITSECT_FLAGS_RING0;
65#endif
66 pCritSect->cNestings = 0;
67 pCritSect->cLockers = -1;
68 pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
69 pCritSect->pValidatorRec = NULL;
70 int rc = VINF_SUCCESS;
71#ifdef RTCRITSECT_STRICT
72 if (!(fFlags & (RTCRITSECT_FLAGS_BOOTSTRAP_HACK | RTCRITSECT_FLAGS_NOP)))
73 {
74 if (!pszNameFmt)
75 {
76 static uint32_t volatile s_iCritSectAnon = 0;
77 rc = RTLockValidatorRecExclCreate(&pCritSect->pValidatorRec, hClass, uSubClass, pCritSect,
78 !(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL),
79 "RTCritSect-%u", ASMAtomicIncU32(&s_iCritSectAnon) - 1);
80 }
81 else
82 {
83 va_list va;
84 va_start(va, pszNameFmt);
85 rc = RTLockValidatorRecExclCreateV(&pCritSect->pValidatorRec, hClass, uSubClass, pCritSect,
86 !(fFlags & RTCRITSECT_FLAGS_NO_LOCK_VAL), pszNameFmt, va);
87 va_end(va);
88 }
89 }
90#endif
91 if (RT_SUCCESS(rc))
92 {
93#ifdef IN_RING0
94 rc = RTSemEventCreate(&pCritSect->EventSem);
95
96#else
97 rc = RTSemEventCreateEx(&pCritSect->EventSem,
98 fFlags & RTCRITSECT_FLAGS_BOOTSTRAP_HACK
99 ? RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK
100 : RTSEMEVENT_FLAGS_NO_LOCK_VAL,
101 NIL_RTLOCKVALCLASS,
102 NULL);
103#endif
104 if (RT_SUCCESS(rc))
105 return VINF_SUCCESS;
106#ifdef RTCRITSECT_STRICT
107 RTLockValidatorRecExclDestroy(&pCritSect->pValidatorRec);
108#endif
109 }
110
111 AssertRC(rc);
112 pCritSect->EventSem = NULL;
113 pCritSect->u32Magic = (uint32_t)rc;
114 return rc;
115}
116RT_EXPORT_SYMBOL(RTCritSectInitEx);
117
118
119RTDECL(uint32_t) RTCritSectSetSubClass(PRTCRITSECT pCritSect, uint32_t uSubClass)
120{
121# ifdef RTCRITSECT_STRICT
122 AssertPtrReturn(pCritSect, RTLOCKVAL_SUB_CLASS_INVALID);
123 AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
124 AssertReturn(!(pCritSect->fFlags & RTCRITSECT_FLAGS_NOP), RTLOCKVAL_SUB_CLASS_INVALID);
125 return RTLockValidatorRecExclSetSubClass(pCritSect->pValidatorRec, uSubClass);
126# else
127 return RTLOCKVAL_SUB_CLASS_INVALID;
128# endif
129}
130
131
132DECL_FORCE_INLINE(int) rtCritSectTryEnter(PRTCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos)
133{
134 Assert(pCritSect);
135 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
136 /*AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, VERR_SEM_DESTROYED);*/
137#ifdef IN_RING0
138 Assert(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0);
139#else
140 Assert(!(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0));
141#endif
142
143 /*
144 * Return straight away if NOP.
145 */
146 if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
147 return VINF_SUCCESS;
148
149 /*
150 * Try take the lock. (cLockers is -1 if it's free)
151 */
152 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
153 if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
154 {
155 /*
156 * Somebody is owning it (or will be soon). Perhaps it's us?
157 */
158 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
159 {
160 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
161 {
162#ifdef RTCRITSECT_STRICT
163 int rc9 = RTLockValidatorRecExclRecursion(pCritSect->pValidatorRec, pSrcPos);
164 if (RT_FAILURE(rc9))
165 return rc9;
166#endif
167 ASMAtomicIncS32(&pCritSect->cLockers);
168 pCritSect->cNestings++;
169 return VINF_SUCCESS;
170 }
171 AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
172 return VERR_SEM_NESTED;
173 }
174 return VERR_SEM_BUSY;
175 }
176
177 /*
178 * First time
179 */
180 pCritSect->cNestings = 1;
181 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
182#ifdef RTCRITSECT_STRICT
183 RTLockValidatorRecExclSetOwner(pCritSect->pValidatorRec, NIL_RTTHREAD, pSrcPos, true);
184#endif
185
186 return VINF_SUCCESS;
187}
188
189
190RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
191{
192#ifndef RTCRTISECT_STRICT
193 return rtCritSectTryEnter(pCritSect, NULL);
194#else
195 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
196 return rtCritSectTryEnter(pCritSect, &SrcPos);
197#endif
198}
199RT_EXPORT_SYMBOL(RTCritSectTryEnter);
200
201
202RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
203{
204 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
205 return rtCritSectTryEnter(pCritSect, &SrcPos);
206}
207RT_EXPORT_SYMBOL(RTCritSectTryEnterDebug);
208
209
210DECL_FORCE_INLINE(int) rtCritSectEnter(PRTCRITSECT pCritSect, PCRTLOCKVALSRCPOS pSrcPos)
211{
212 AssertPtr(pCritSect);
213 AssertReturn(pCritSect->u32Magic == RTCRITSECT_MAGIC, VERR_SEM_DESTROYED);
214#ifdef IN_RING0
215 Assert(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0);
216#else
217 Assert(!(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0));
218#endif
219
220 /*
221 * Return straight away if NOP.
222 */
223 if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
224 return VINF_SUCCESS;
225
226 /*
227 * How is calling and is the order right?
228 */
229 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
230#ifdef RTCRITSECT_STRICT
231 RTTHREAD hThreadSelf = pCritSect->pValidatorRec
232 ? RTThreadSelfAutoAdopt()
233 : RTThreadSelf();
234 int rc9;
235 if (pCritSect->pValidatorRec) /* (bootstap) */
236 {
237 rc9 = RTLockValidatorRecExclCheckOrder(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, RT_INDEFINITE_WAIT);
238 if (RT_FAILURE(rc9))
239 return rc9;
240 }
241#endif
242
243 /*
244 * Increment the waiter counter.
245 * This becomes 0 when the section is free.
246 */
247 if (ASMAtomicIncS32(&pCritSect->cLockers) > 0)
248 {
249 /*
250 * Nested?
251 */
252 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
253 {
254 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
255 {
256#ifdef RTCRITSECT_STRICT
257 rc9 = RTLockValidatorRecExclRecursion(pCritSect->pValidatorRec, pSrcPos);
258 if (RT_FAILURE(rc9))
259 {
260 ASMAtomicDecS32(&pCritSect->cLockers);
261 return rc9;
262 }
263#endif
264 pCritSect->cNestings++;
265 return VINF_SUCCESS;
266 }
267
268 AssertBreakpoint(); /* don't do normal assertion here, the logger uses this code too. */
269 ASMAtomicDecS32(&pCritSect->cLockers);
270 return VERR_SEM_NESTED;
271 }
272
273 /*
274 * Wait for the current owner to release it.
275 */
276#ifndef RTCRITSECT_STRICT
277 RTTHREAD hThreadSelf = RTThreadSelf();
278#endif
279 for (;;)
280 {
281#ifdef RTCRITSECT_STRICT
282 rc9 = RTLockValidatorRecExclCheckBlocking(pCritSect->pValidatorRec, hThreadSelf, pSrcPos,
283 !(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING),
284 RT_INDEFINITE_WAIT, RTTHREADSTATE_CRITSECT, false);
285 if (RT_FAILURE(rc9))
286 {
287 ASMAtomicDecS32(&pCritSect->cLockers);
288 return rc9;
289 }
290#elif defined(IN_RING3)
291 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT, false);
292#endif
293 int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
294#ifdef IN_RING3
295 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
296#endif
297
298 if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
299 return VERR_SEM_DESTROYED;
300 if (rc == VINF_SUCCESS)
301 break;
302 AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
303 }
304 AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
305 }
306
307 /*
308 * First time
309 */
310 pCritSect->cNestings = 1;
311 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
312#ifdef RTCRITSECT_STRICT
313 RTLockValidatorRecExclSetOwner(pCritSect->pValidatorRec, hThreadSelf, pSrcPos, true);
314#endif
315
316 return VINF_SUCCESS;
317}
318
319
320RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect)
321{
322#ifndef RTCRITSECT_STRICT
323 return rtCritSectEnter(pCritSect, NULL);
324#else
325 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
326 return rtCritSectEnter(pCritSect, &SrcPos);
327#endif
328}
329RT_EXPORT_SYMBOL(RTCritSectEnter);
330
331
332RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
333{
334 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
335 return rtCritSectEnter(pCritSect, &SrcPos);
336}
337RT_EXPORT_SYMBOL(RTCritSectEnterDebug);
338
339
340RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect)
341{
342 /*
343 * Assert sanity and check for NOP.
344 */
345 Assert(pCritSect);
346 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
347#ifdef IN_RING0
348 Assert(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0);
349#else
350 Assert(!(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0));
351#endif
352 if (pCritSect->fFlags & RTCRITSECT_FLAGS_NOP)
353 return VINF_SUCCESS;
354
355 /*
356 * Assert ownership and so on.
357 */
358 Assert(pCritSect->cNestings > 0);
359 Assert(pCritSect->cLockers >= 0);
360 Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
361
362#ifdef RTCRITSECT_STRICT
363 int rc9 = RTLockValidatorRecExclReleaseOwner(pCritSect->pValidatorRec, pCritSect->cNestings == 1);
364 if (RT_FAILURE(rc9))
365 return rc9;
366#endif
367
368 /*
369 * Decrement nestings, if <= 0 when we'll release the critsec.
370 */
371 pCritSect->cNestings--;
372 if (pCritSect->cNestings > 0)
373 ASMAtomicDecS32(&pCritSect->cLockers);
374 else
375 {
376 /*
377 * Set owner to zero.
378 * Decrement waiters, if >= 0 then we have to wake one of them up.
379 */
380 ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
381 if (ASMAtomicDecS32(&pCritSect->cLockers) >= 0)
382 {
383 int rc = RTSemEventSignal(pCritSect->EventSem);
384 AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
385 }
386 }
387 return VINF_SUCCESS;
388}
389RT_EXPORT_SYMBOL(RTCritSectLeave);
390
391
392
393#ifdef IN_RING3
394
395static int rtCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects, PCRTLOCKVALSRCPOS pSrcPos)
396{
397 Assert(cCritSects > 0);
398 AssertPtr(papCritSects);
399
400 /*
401 * Try get them all.
402 */
403 int rc = VERR_INVALID_PARAMETER;
404 size_t i;
405 for (i = 0; i < cCritSects; i++)
406 {
407 rc = rtCritSectTryEnter(papCritSects[i], pSrcPos);
408 if (RT_FAILURE(rc))
409 break;
410 }
411 if (RT_SUCCESS(rc))
412 return rc;
413
414 /*
415 * The retry loop.
416 */
417 for (unsigned cTries = 0; ; cTries++)
418 {
419 /*
420 * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
421 */
422 size_t j = i;
423 while (j-- > 0)
424 {
425 int rc2 = RTCritSectLeave(papCritSects[j]);
426 AssertRC(rc2);
427 }
428 if (rc != VERR_SEM_BUSY)
429 return rc;
430
431 /*
432 * Try prevent any theoretical synchronous races with other threads.
433 */
434 Assert(cTries < 1000000);
435 if (cTries > 10000)
436 RTThreadSleep(cTries % 3);
437
438 /*
439 * Wait on the one we failed to get.
440 */
441 rc = rtCritSectEnter(papCritSects[i], pSrcPos);
442 if (RT_FAILURE(rc))
443 return rc;
444
445 /*
446 * Try take the others.
447 */
448 for (j = 0; j < cCritSects; j++)
449 {
450 if (j != i)
451 {
452 rc = rtCritSectTryEnter(papCritSects[j], pSrcPos);
453 if (RT_FAILURE(rc))
454 break;
455 }
456 }
457 if (RT_SUCCESS(rc))
458 return rc;
459
460 /*
461 * We failed.
462 */
463 if (i > j)
464 {
465 int rc2 = RTCritSectLeave(papCritSects[i]);
466 AssertRC(rc2);
467 }
468 i = j;
469 }
470}
471
472
473RTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
474{
475#ifndef RTCRITSECT_STRICT
476 return rtCritSectEnterMultiple(cCritSects, papCritSects, NULL);
477#else
478 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
479 return rtCritSectEnterMultiple(cCritSects, papCritSects, &SrcPos);
480#endif
481}
482RT_EXPORT_SYMBOL(RTCritSectEnterMultiple);
483
484
485RTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTHCUINTPTR uId, RT_SRC_POS_DECL)
486{
487 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
488 return rtCritSectEnterMultiple(cCritSects, papCritSects, &SrcPos);
489}
490RT_EXPORT_SYMBOL(RTCritSectEnterMultipleDebug);
491
492
493
494RTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
495{
496 int rc = VINF_SUCCESS;
497 for (size_t i = 0; i < cCritSects; i++)
498 {
499 int rc2 = RTCritSectLeave(papCritSects[i]);
500 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
501 rc = rc2;
502 }
503 return rc;
504}
505RT_EXPORT_SYMBOL(RTCritSectLeaveMultiple);
506
507#endif /* IN_RING3 */
508
509
510
511RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
512{
513 /*
514 * Assert free waiters and so on.
515 */
516 Assert(pCritSect);
517 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
518 Assert(pCritSect->cNestings == 0);
519 Assert(pCritSect->cLockers == -1);
520 Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
521#ifdef IN_RING0
522 Assert(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0);
523#else
524 Assert(!(pCritSect->fFlags & RTCRITSECT_FLAGS_RING0));
525#endif
526
527 /*
528 * Invalidate the structure and free the mutex.
529 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
530 */
531 ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
532 pCritSect->fFlags = 0;
533 pCritSect->cNestings = 0;
534 pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
535 RTSEMEVENT EventSem = pCritSect->EventSem;
536 pCritSect->EventSem = NIL_RTSEMEVENT;
537
538 while (pCritSect->cLockers-- >= 0)
539 RTSemEventSignal(EventSem);
540 ASMAtomicWriteS32(&pCritSect->cLockers, -1);
541 int rc = RTSemEventDestroy(EventSem);
542 AssertRC(rc);
543
544#ifdef RTCRITSECT_STRICT
545 RTLockValidatorRecExclDestroy(&pCritSect->pValidatorRec);
546#endif
547
548 return rc;
549}
550RT_EXPORT_SYMBOL(RTCritSectDelete);
551
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