VirtualBox

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

Last change on this file since 27653 was 25831, checked in by vboxsync, 15 years ago

iprt/lockvalidation: give better names to anonymous locks

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