VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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