VirtualBox

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

Last change on this file since 25722 was 25704, checked in by vboxsync, 15 years ago

iprt,pdmcritsect: More flexible lock naming, added RTCritSectSetSubClass and made some RTCritSectInitEx.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette