VirtualBox

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

Last change on this file since 8256 was 8245, checked in by vboxsync, 17 years ago

rebranding: IPRT files again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.4 KB
Line 
1/* $Id: critsect-generic.cpp 8245 2008-04-21 17:24:28Z vboxsync $ */
2/** @file
3 * IPRT - Critical Section, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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* Header Files *
33*******************************************************************************/
34#include <iprt/critsect.h>
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
42/** @def RTCRITSECT_STRICT
43 * Define this to enable deadlock detection.
44 *
45 * @remark This won't work safely on L4 since we have to traverse the AVL tree
46 * in order to get the RT thread structure there and this tree is
47 * protected by a critsect atm.
48 */
49#if !defined(RTCRITSECT_STRICT) && defined(RT_STRICT) && !defined(RT_OS_L4)
50# define RTCRITSECT_STRICT
51#endif
52
53/* in strict mode we're redefining this, so undefine it now for the implementation. */
54#undef RTCritSectEnter
55#undef RTCritSectTryEnter
56#undef RTCritSectEnterMultiple
57
58
59/**
60 * Initialize a critical section.
61 */
62RTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
63{
64 return RTCritSectInitEx(pCritSect, 0);
65}
66
67
68/**
69 * Initialize a critical section.
70 *
71 * @returns iprt status code.
72 * @param pCritSect Pointer to the critical section structure.
73 * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS \#defines.
74 */
75RTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags)
76{
77 /*
78 * Initialize the structure and
79 */
80 pCritSect->u32Magic = RTCRITSECT_MAGIC;
81 pCritSect->fFlags = fFlags;
82 pCritSect->cNestings = 0;
83 pCritSect->cLockers = -1;
84 pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
85 pCritSect->Strict.ThreadOwner = NIL_RTTHREAD;
86 pCritSect->Strict.pszEnterFile = NULL;
87 pCritSect->Strict.u32EnterLine = 0;
88 pCritSect->Strict.uEnterId = 0;
89 int rc = RTSemEventCreate(&pCritSect->EventSem);
90 if (RT_SUCCESS(rc))
91 return VINF_SUCCESS;
92
93 AssertRC(rc);
94 pCritSect->EventSem = NULL;
95 pCritSect->u32Magic = (uint32_t)rc;
96 return rc;
97}
98
99
100/**
101 * Enter multiple critical sections.
102 *
103 * This function will enter ALL the specified critical sections before returning.
104 *
105 * @returns VINF_SUCCESS on success.
106 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
107 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
108 * @param cCritSects Number of critical sections in the array.
109 * @param papCritSects Array of critical section pointers.
110 *
111 * @remark Please note that this function will not necessarily come out favourable in a
112 * fight with other threads which are using the normal RTCritSectEnter() function.
113 * Therefore, avoid having to enter multiple critical sections!
114 */
115RTDECL(int) RTCritSectEnterMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
116#ifdef RTCRITSECT_STRICT
117{
118 return RTCritSectEnterMultipleDebug(cCritSects, papCritSects, __FILE__, __LINE__, 0);
119}
120RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
121#endif /* RTCRITSECT_STRICT */
122{
123 Assert(cCritSects > 0);
124 Assert(VALID_PTR(papCritSects));
125
126 /*
127 * Try get them all.
128 */
129 int rc = VERR_INVALID_PARAMETER;
130 unsigned i;
131 for (i = 0; i < cCritSects; i++)
132 {
133#ifdef RTCRITSECT_STRICT
134 rc = RTCritSectTryEnterDebug(papCritSects[i], pszFile, uLine, uId);
135#else
136 rc = RTCritSectTryEnter(papCritSects[i]);
137#endif
138 if (RT_FAILURE(rc))
139 break;
140 }
141 if (RT_SUCCESS(rc))
142 return rc;
143
144 /*
145 * The retry loop.
146 */
147 for (unsigned cTries = 0; ; cTries++)
148 {
149 /*
150 * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
151 */
152 unsigned j = i;
153 while (j-- > 0)
154 {
155 int rc2 = RTCritSectLeave(papCritSects[j]);
156 AssertRC(rc2);
157 }
158 if (rc != VERR_SEM_BUSY)
159 return rc;
160
161 /*
162 * Try prevent any theoretical synchronous races with other threads.
163 */
164 Assert(cTries < 1000000);
165 if (cTries > 10000)
166 RTThreadSleep(cTries % 3);
167
168 /*
169 * Wait on the one we failed to get.
170 */
171#ifdef RTCRITSECT_STRICT
172 rc = RTCritSectEnterDebug(papCritSects[i], pszFile, uLine, uId);
173#else
174 rc = RTCritSectEnter(papCritSects[i]);
175#endif
176 if (RT_FAILURE(rc))
177 return rc;
178
179 /*
180 * Try take the others.
181 */
182 for (j = 0; j < cCritSects; j++)
183 {
184 if (j != i)
185 {
186#ifdef RTCRITSECT_STRICT
187 rc = RTCritSectTryEnterDebug(papCritSects[j], pszFile, uLine, uId);
188#else
189 rc = RTCritSectTryEnter(papCritSects[j]);
190#endif
191 if (RT_FAILURE(rc))
192 break;
193 }
194 }
195 if (RT_SUCCESS(rc))
196 return rc;
197
198 /*
199 * We failed.
200 */
201 if (i > j)
202 {
203 int rc2 = RTCritSectLeave(papCritSects[i]);
204 AssertRC(rc2);
205 }
206 i = j;
207 }
208}
209
210
211/**
212 * Try enter a critical section.
213 *
214 * @returns VINF_SUCCESS on success.
215 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
216 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
217 * @param pCritSect The critical section.
218 */
219RTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
220#ifdef RTCRITSECT_STRICT
221{
222 return RTCritSectTryEnterDebug(pCritSect, __FILE__, __LINE__, 0);
223}
224RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
225#endif /* RTCRITSECT_STRICT */
226{
227 Assert(pCritSect);
228 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
229 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
230#ifdef RTCRITSECT_STRICT
231 RTTHREAD ThreadSelf = RTThreadSelf();
232 if (ThreadSelf == NIL_RTTHREAD)
233 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
234#endif
235
236 /*
237 * Try take the lock. (cLockers is -1 if it's free)
238 */
239 if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
240 {
241 /*
242 * Somebody is owning it (or will be soon). Perhaps it's us?
243 */
244 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
245 {
246 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
247 {
248 ASMAtomicIncS32(&pCritSect->cLockers);
249 pCritSect->cNestings++;
250 return VINF_SUCCESS;
251 }
252 AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
253 return VERR_SEM_NESTED;
254 }
255 return VERR_SEM_BUSY;
256 }
257
258 /*
259 * First time
260 */
261 pCritSect->cNestings = 1;
262 ASMAtomicXchgSize(&pCritSect->NativeThreadOwner, NativeThreadSelf);
263#ifdef RTCRITSECT_STRICT
264 pCritSect->Strict.pszEnterFile = pszFile;
265 pCritSect->Strict.u32EnterLine = uLine;
266 pCritSect->Strict.uEnterId = uId;
267 ASMAtomicXchgSize(&pCritSect->Strict.ThreadOwner, (RTUINTPTR)ThreadSelf); /* screw gcc and its pedantic warnings. */
268#endif
269
270 return VINF_SUCCESS;
271}
272
273
274/**
275 * Enter a critical section.
276 *
277 * @returns VINF_SUCCESS on success.
278 * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
279 * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
280 * @param pCritSect The critical section.
281 */
282RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect)
283#ifdef RTCRITSECT_STRICT
284{
285 return RTCritSectEnterDebug(pCritSect, __FILE__, __LINE__, 0);
286}
287RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
288#endif /* RTCRITSECT_STRICT */
289{
290 Assert(pCritSect);
291 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
292 RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
293#ifdef RTCRITSECT_STRICT
294 RTTHREAD ThreadSelf = RTThreadSelf();
295 if (ThreadSelf == NIL_RTTHREAD)
296 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
297#endif
298
299 /** If the critical section has already been destroyed, then inform the caller. */
300 if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
301 return VERR_SEM_DESTROYED;
302
303 /*
304 * Increment the waiter counter.
305 * This becomes 0 when the section is free.
306 */
307 if (ASMAtomicIncS32(&pCritSect->cLockers) > 0)
308 {
309 /*
310 * Nested?
311 */
312 if (pCritSect->NativeThreadOwner == NativeThreadSelf)
313 {
314 if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
315 {
316 pCritSect->cNestings++;
317 return VINF_SUCCESS;
318 }
319 else
320 {
321 AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
322 ASMAtomicDecS32(&pCritSect->cLockers);
323 return VERR_SEM_NESTED;
324 }
325 }
326
327 for (;;)
328 {
329#ifdef RTCRITSECT_STRICT
330 rtThreadBlocking(ThreadSelf, RTTHREADSTATE_CRITSECT, (uintptr_t)pCritSect, pszFile, uLine, uId);
331#endif
332 int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
333#ifdef RTCRITSECT_STRICT
334 rtThreadUnblocked(ThreadSelf, RTTHREADSTATE_CRITSECT);
335#endif
336 if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
337 return VERR_SEM_DESTROYED;
338 if (rc == VINF_SUCCESS)
339 break;
340 AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Vrc\n", rc));
341 }
342 AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
343 }
344
345 /*
346 * First time
347 */
348 pCritSect->cNestings = 1;
349 ASMAtomicXchgSize(&pCritSect->NativeThreadOwner, NativeThreadSelf);
350#ifdef RTCRITSECT_STRICT
351 pCritSect->Strict.pszEnterFile = pszFile;
352 pCritSect->Strict.u32EnterLine = uLine;
353 pCritSect->Strict.uEnterId = uId;
354 ASMAtomicXchgSize(&pCritSect->Strict.ThreadOwner, (RTUINTPTR)ThreadSelf); /* screw gcc and its pedantic warnings. */
355#endif
356
357 return VINF_SUCCESS;
358}
359
360
361/**
362 * Leave a critical section.
363 *
364 * @returns VINF_SUCCESS.
365 * @param pCritSect The critical section.
366 */
367RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect)
368{
369 /*
370 * Assert ownership and so on.
371 */
372 Assert(pCritSect);
373 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
374 Assert(pCritSect->cNestings > 0);
375 Assert(pCritSect->cLockers >= 0);
376 Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
377
378 /*
379 * Decrement nestings, if <= 0 when we'll release the critsec.
380 */
381 pCritSect->cNestings--;
382 if (pCritSect->cNestings > 0)
383 ASMAtomicDecS32(&pCritSect->cLockers);
384 else
385 {
386 /*
387 * Set owner to zero.
388 * Decrement waiters, if >= 0 then we have to wake one of them up.
389 */
390#ifdef RTCRITSECT_STRICT
391 ASMAtomicXchgSize(&pCritSect->Strict.ThreadOwner, NIL_RTTHREAD);
392#endif
393 ASMAtomicXchgSize(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
394 if (ASMAtomicDecS32(&pCritSect->cLockers) >= 0)
395 {
396 int rc = RTSemEventSignal(pCritSect->EventSem);
397 AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Vrc\n", rc));
398 }
399 }
400 return VINF_SUCCESS;
401}
402
403
404/**
405 * Leave multiple critical sections.
406 *
407 * @returns VINF_SUCCESS.
408 * @param cCritSects Number of critical sections in the array.
409 * @param papCritSects Array of critical section pointers.
410 */
411RTDECL(int) RTCritSectLeaveMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
412{
413 int rc = VINF_SUCCESS;
414 for (unsigned i = 0; i < cCritSects; i++)
415 {
416 int rc2 = RTCritSectLeave(papCritSects[i]);
417 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
418 rc = rc2;
419 }
420 return rc;
421}
422
423
424#ifndef RTCRITSECT_STRICT
425RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
426{
427 return RTCritSectEnter(pCritSect);
428}
429
430RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
431{
432 return RTCritSectTryEnter(pCritSect);
433}
434
435RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
436{
437 return RTCritSectEnterMultiple(cCritSects, papCritSects);
438}
439#endif /* RT_STRICT */
440
441
442/**
443 * Deletes a critical section.
444 *
445 * @returns VINF_SUCCESS.
446 * @param pCritSect The critical section.
447 */
448RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
449{
450 /*
451 * Assert free waiters and so on.
452 */
453 Assert(pCritSect);
454 Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
455 Assert(pCritSect->cNestings == 0);
456 Assert(pCritSect->cLockers == -1);
457 Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
458
459 /*
460 * Invalidate the structure and free the mutex.
461 * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
462 */
463 ASMAtomicXchgU32(&pCritSect->u32Magic, 0);
464 pCritSect->fFlags = 0;
465 pCritSect->cNestings = 0;
466 pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
467 RTSEMEVENT EventSem = pCritSect->EventSem;
468 pCritSect->EventSem = NULL;
469 while (pCritSect->cLockers-- >= 0)
470 RTSemEventSignal(EventSem);
471 ASMAtomicXchgS32(&pCritSect->cLockers, -1);
472 int rc = RTSemEventDestroy(EventSem);
473 AssertRC(rc);
474
475 return rc;
476}
477
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