VirtualBox

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

Last change on this file since 55998 was 51940, checked in by vboxsync, 10 years ago

GMMR0: Switched from fast mutex to critical section for the giant GMMR0 lock to avoid running into unnecessary trouble with the windows driver verifier. Required making the critical section code compile and link in the ring-0 environment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.4 KB
Line 
1/* $Id: critsect-generic.cpp 51940 2014-07-08 17:45:51Z vboxsync $ */
2/** @file
3 * IPRT - Critical Section, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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