VirtualBox

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

Last change on this file since 21497 was 21337, checked in by vboxsync, 15 years ago

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

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