VirtualBox

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

Last change on this file since 25524 was 25491, checked in by vboxsync, 15 years ago

IPRT,PDMCritSect: Fixing critsect regression; contains under construction rw deadlock detection code.

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