VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/semsrw-generic.cpp@ 980

Last change on this file since 980 was 403, checked in by vboxsync, 18 years ago

Need RTThreadWait in ring-0 too when using the generic timers, so thread.cpp was ported to ring-0. Fixed a bug in RTTimerStart() (the generic code). (hope this doesn't break the other platforms...)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.3 KB
Line 
1/* $Id: semsrw-generic.cpp 403 2007-01-28 08:45:05Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Read-Write Semaphore, Generic.
4 *
5 * This is a generic implementation for OSes which don't have
6 * native RW semaphores.
7 */
8
9/*
10 * Copyright (C) 2006 InnoTek Systemberatung GmbH
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License as published by the Free Software Foundation,
16 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
17 * distribution. VirtualBox OSE is distributed in the hope that it will
18 * be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * If you received this file as part of a commercial VirtualBox
21 * distribution, then only the terms of your commercial VirtualBox
22 * license agreement apply instead of the previous paragraph.
23 */
24
25/** @todo fix generic RW sems. (reimplement) */
26#define USE_CRIT_SECT
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#include <iprt/semaphore.h>
33#include <iprt/alloc.h>
34#include <iprt/time.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/thread.h>
38#include <iprt/err.h>
39#ifdef USE_CRIT_SECT
40#include <iprt/critsect.h>
41#endif
42
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48/** Internal representation of a Read-Write semaphore for the
49 * Generic implementation. */
50struct RTSEMRWINTERNAL
51{
52#ifdef USE_CRIT_SECT
53 /** Critical section. */
54 RTCRITSECT CritSect;
55#else
56 /** Magic (RTSEMRW_MAGIC). */
57 uint32_t u32Magic;
58 /** This critical section serializes the access to and updating of the structure members. */
59 RTCRITSECT CritSect;
60 /** The current number of readers. */
61 uint32_t cReaders;
62 /** The number of readers waiting. */
63 uint32_t cReadersWaiting;
64 /** The current number of waiting writers. */
65 uint32_t cWritersWaiting;
66 /** The handle of the event object on which the waiting readers block. (manual reset). */
67 RTSEMEVENTMULTI EventReaders;
68 /** The handle of the event object on which the waiting writers block. (manual reset). */
69 RTSEMEVENTMULTI EventWriters;
70 /** The current state of the read-write lock. */
71 KPRF_TYPE(,RWLOCKSTATE) enmState;
72
73#endif
74};
75
76/** RTSEMRWINTERNAL::u32Magic value. (Kosuke Fujishima) */
77#define RTSEMRW_MAGIC 0x19640707
78
79
80/**
81 * Validate a read-write semaphore handle passed to one of the interface.
82 *
83 * @returns true if valid.
84 * @returns false if invalid.
85 * @param pIntRWSem Pointer to the read-write semaphore to validate.
86 */
87inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
88{
89 if (!VALID_PTR(pIntRWSem))
90 return false;
91
92#ifdef USE_CRIT_SECT
93 if (pIntRWSem->CritSect.u32Magic != RTCRITSECT_MAGIC)
94 return false;
95#else
96 if (pIntRWSem->u32Check != (uint32_t)~0)
97 return false;
98#endif
99 return true;
100}
101
102
103RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
104{
105 int rc;
106
107 /*
108 * Allocate memory.
109 */
110 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
111 if (pIntRWSem)
112 {
113#ifdef USE_CRIT_SECT
114 rc = RTCritSectInit(&pIntRWSem->CritSect);
115 if (RT_SUCCESS(rc))
116 {
117 *pRWSem = pIntRWSem;
118 return VINF_SUCCESS;
119 }
120#else
121 /*
122 * Create the semaphores.
123 */
124 rc = RTSemEventCreate(&pIntRWSem->WriteEvent);
125 if (RT_SUCCESS(rc))
126 {
127 rc = RTSemEventMultiCreate(&pIntRWSem->ReadEvent);
128 if (RT_SUCCESS(rc))
129 {
130 rc = RTSemMutexCreate(&pIntRWSem->Mutex);
131 if (RT_SUCCESS(rc))
132 {
133 /*
134 * Signal the read semaphore and initialize other variables.
135 */
136 rc = RTSemEventMultiSignal(pIntRWSem->ReadEvent);
137 if (RT_SUCCESS(rc))
138 {
139 pIntRWSem->cReaders = 0;
140 pIntRWSem->cWriters = 0;
141 pIntRWSem->WROwner = NIL_RTTHREAD;
142 pIntRWSem->u32Check = ~0;
143 *pRWSem = pIntRWSem;
144 return VINF_SUCCESS;
145 }
146 RTSemMutexDestroy(pIntRWSem->Mutex);
147 }
148 RTSemEventMultiDestroy(pIntRWSem->ReadEvent);
149 }
150 RTSemEventDestroy(pIntRWSem->WriteEvent);
151 }
152#endif
153 RTMemFree(pIntRWSem);
154 }
155 else
156 rc = VERR_NO_MEMORY;
157
158 return rc;
159}
160
161
162RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
163{
164 /*
165 * Validate handle.
166 */
167 if (!rtsemRWValid(RWSem))
168 {
169 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
170 return VERR_INVALID_HANDLE;
171 }
172
173#ifdef USE_CRIT_SECT
174 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
175 int rc = RTCritSectDelete(&pIntRWSem->CritSect);
176 if (RT_SUCCESS(rc))
177 RTMemFree(pIntRWSem);
178 return rc;
179#else
180
181 /*
182 * Check if busy.
183 */
184 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
185 int rc = RTSemMutexRequest(pIntRWSem->Mutex, 32);
186 if (RT_SUCCESS(rc))
187 {
188 if (!pIntRWSem->cReaders && !pIntRWSem->cWriters)
189 {
190 /*
191 * Make it invalid and unusable.
192 */
193 ASMAtomicXchgU32(&pIntRWSem->u32Check, 0);
194 ASMAtomicXchgU32(&pIntRWSem->cReaders, ~0);
195
196 /*
197 * Do actual cleanup.
198 * None of these can now fail excep for the mutex which
199 * can be a little bit busy.
200 */
201 rc = RTSemEventMultiDestroy(pIntRWSem->ReadEvent);
202 AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiDestroy failed! rc=%d\n", rc)); NOREF(rc);
203 pIntRWSem->ReadEvent = NIL_RTSEMEVENTMULTI;
204
205 rc = RTSemEventDestroy(pIntRWSem->WriteEvent);
206 AssertMsg(RT_SUCCESS(rc), ("RTSemEventDestroy failed! rc=%d\n", rc)); NOREF(rc);
207 pIntRWSem->WriteEvent = NIL_RTSEMEVENT;
208
209 RTSemMutexRelease(pIntRWSem->Mutex);
210 for (unsigned i = 32; i > 0; i--)
211 {
212 rc = RTSemMutexDestroy(pIntRWSem->Mutex);
213 if (RT_SUCCESS(rc))
214 break;
215 RTThreadSleep(1);
216 }
217 AssertMsg(RT_SUCCESS(rc), ("RTSemMutexDestroy failed! rc=%d\n", rc)); NOREF(rc);
218 pIntRWSem->Mutex = (RTSEMMUTEX)0;
219
220 RTMemFree(pIntRWSem);
221 rc = VINF_SUCCESS;
222 }
223 else
224 {
225 rc = VERR_SEM_BUSY;
226 RTSemMutexRelease(pIntRWSem->Mutex);
227 }
228 }
229 else
230 rc = rc == VERR_TIMEOUT ? VERR_SEM_BUSY : rc;
231
232 return VINF_SUCCESS;
233#endif
234}
235
236
237RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
238{
239 /*
240 * Validate handle.
241 */
242 if (!rtsemRWValid(RWSem))
243 {
244 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
245 return VERR_INVALID_HANDLE;
246 }
247
248#ifdef USE_CRIT_SECT
249 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
250 return RTCritSectEnter(&pIntRWSem->CritSect);
251#else
252
253 /*
254 * Take mutex and check if already reader.
255 */
256 //RTTHREAD Self = RTThreadSelf();
257 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
258 unsigned cMilliesInitial = cMillies;
259 uint64_t tsStart = 0;
260 if (cMillies != RTSEM_INDEFINITE_WAIT)
261 tsStart = RTTimeNanoTS();
262
263 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
264 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
265 if (RT_FAILURE(rc))
266 {
267 AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
268 return rc;
269 }
270
271 unsigned i = pIntRWSem->cReaders;
272 while (i-- > 0)
273 {
274 if (pIntRWSem->aReaders[i].Thread == Self)
275 {
276 if (pIntRWSem->aReaders[i].cNesting + 1 < (unsigned)~0)
277 pIntRWSem->aReaders[i].cNesting++;
278 else
279 {
280 AssertMsgFailed(("Too many requests for one thread!\n"));
281 rc = RTSemMutexRelease(pIntRWSem->Mutex);
282 AssertMsg(RT_SUCCESS(rc), ("RTSemMutexRelease failed rc=%d\n", rc));
283 return VERR_TOO_MANY_SEM_REQUESTS;
284 }
285 }
286 }
287
288
289 for (;;)
290 {
291 /*
292 * Check if the stat of the affairs allow read access.
293 */
294 if (pIntRWSem->u32Check == (uint32_t)~0)
295 {
296 if (pIntRWSem->cWriters == 0)
297 {
298 if (pIntRWSem->cReaders < ELEMENTS(pIntRWSem->aReaders))
299 {
300 /*
301 * Add ourselves to the list of readers and return.
302 */
303 i = pIntRWSem->cReaders;
304 pIntRWSem->aReaders[i].Thread = Self;
305 pIntRWSem->aReaders[i].cNesting = 1;
306 ASMAtomicXchgU32(&pIntRWSem->cReaders, i + 1);
307
308 RTSemMutexRelease(pIntRWSem->Mutex);
309 return VINF_SUCCESS;
310 }
311 else
312 {
313 AssertMsgFailed(("Too many readers! How come we have so many threads!?!\n"));
314 rc = VERR_TOO_MANY_SEM_REQUESTS;
315 }
316 }
317 #if 0 /* any action here shouldn't be necessary */
318 else
319 {
320 rc = RTSemEventMultiReset(pIntRWSem->ReadEvent);
321 AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiReset failed on RWSem %p, rc=%d\n", RWSem, rc));
322 }
323 #endif
324 }
325 else
326 rc = VERR_SEM_DESTROYED;
327 RTSemMutexRelease(pIntRWSem->Mutex);
328 if (RT_FAILURE(rc))
329 break;
330
331
332 /*
333 * Wait till it's ready for reading.
334 */
335 if (cMillies != RTSEM_INDEFINITE_WAIT)
336 {
337 int64_t tsDelta = RTTimeNanoTS() - tsStart;
338 if (tsDelta >= 1000000)
339 {
340 cMillies = cMilliesInitial - (unsigned)(tsDelta / 1000000);
341 if (cMillies > cMilliesInitial)
342 cMillies = cMilliesInitial ? 1 : 0;
343 }
344 }
345 rc = RTSemEventMultiWait(pIntRWSem->ReadEvent, cMillies);
346 if (RT_FAILURE(rc))
347 {
348 AssertMsg(rc == VERR_TIMEOUT, ("RTSemEventMultiWait failed on rwsem %p, rc=%d\n", RWSem, rc));
349 break;
350 }
351
352 /*
353 * Get Mutex.
354 */
355 rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
356 if (RT_FAILURE(rc))
357 {
358 AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
359 break;
360 }
361 }
362
363 return rc;
364#endif
365}
366
367
368RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
369{
370 return RTSemRWRequestRead(RWSem, cMillies);
371}
372
373
374RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
375{
376 /*
377 * Validate handle.
378 */
379 if (!rtsemRWValid(RWSem))
380 {
381 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
382 return VERR_INVALID_HANDLE;
383 }
384
385#ifdef USE_CRIT_SECT
386 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
387 return RTCritSectLeave(&pIntRWSem->CritSect);
388#else
389
390 /*
391 * Take Mutex.
392 */
393 //RTTHREAD Self = RTThreadSelf();
394 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
395 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
396 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
397 if (RT_SUCCESS(rc))
398 {
399 unsigned i = pIntRWSem->cReaders;
400 while (i-- > 0)
401 {
402 if (pIntRWSem->aReaders[i].Thread == Self)
403 {
404 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("Impossible! Writers and Readers are exclusive!\n"));
405
406 if (pIntRWSem->aReaders[i].cNesting <= 1)
407 {
408 pIntRWSem->aReaders[i] = pIntRWSem->aReaders[pIntRWSem->cReaders - 1];
409 ASMAtomicXchgU32(&pIntRWSem->cReaders, pIntRWSem->cReaders - 1);
410
411 /* Kick off writers? */
412 if ( pIntRWSem->cWriters > 0
413 && pIntRWSem->cReaders == 0)
414 {
415 rc = RTSemEventSignal(pIntRWSem->WriteEvent);
416 AssertMsg(RT_SUCCESS(rc), ("Failed to signal writers on rwsem %p, rc=%d\n", RWSem, rc));
417 }
418 }
419 else
420 pIntRWSem->aReaders[i].cNesting--;
421
422 RTSemMutexRelease(pIntRWSem->Mutex);
423 return VINF_SUCCESS;
424 }
425 }
426
427 RTSemMutexRelease(pIntRWSem->Mutex);
428 rc = VERR_NOT_OWNER;
429 AssertMsgFailed(("Not reader of rwsem %p\n", RWSem));
430 }
431 else
432 AssertMsgFailed(("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc));
433
434 return rc;
435#endif
436}
437
438
439
440RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
441{
442 /*
443 * Validate handle.
444 */
445 if (!rtsemRWValid(RWSem))
446 {
447 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
448 return VERR_INVALID_HANDLE;
449 }
450
451#ifdef USE_CRIT_SECT
452 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
453 return RTCritSectEnter(&pIntRWSem->CritSect);
454#else
455
456 /*
457 * Get Mutex.
458 */
459 //RTTHREAD Self = RTThreadSelf();
460 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
461 unsigned cMilliesInitial = cMillies;
462 uint64_t tsStart = 0;
463 if (cMillies != RTSEM_INDEFINITE_WAIT)
464 tsStart = RTTimeNanoTS();
465
466 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
467 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
468 if (RT_FAILURE(rc))
469 {
470 AssertMsgFailed(("RTSemMutexWait failed on rwsem %p, rc=%d\n", RWSem, rc));
471 return rc;
472 }
473
474 /*
475 * Check that we're not a reader.
476 */
477 unsigned i = pIntRWSem->cReaders;
478 while (i-- > 0)
479 {
480 if (pIntRWSem->aReaders[i].Thread == Self)
481 {
482 AssertMsgFailed(("Deadlock - requested write access while being a reader! rwsem %p.\n", RWSem));
483 RTSemMutexRelease(pIntRWSem->Mutex);
484 return VERR_DEADLOCK;
485 }
486 }
487
488
489 /*
490 * Reset the reader event semaphore and increment number of readers.
491 */
492 rc = RTSemEventMultiReset(pIntRWSem->ReadEvent);
493 if (RT_FAILURE(rc))
494 {
495 AssertMsgFailed(("Failed to reset readers, rwsem %p, rc=%d.\n", RWSem, rc));
496 RTSemMutexRelease(pIntRWSem->Mutex);
497 return rc;
498 }
499 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters + 1);
500
501 /*
502 * Wait while there are other threads owning this sem.
503 */
504 while ( pIntRWSem->WROwner != NIL_RTTHREAD
505 || pIntRWSem->cReaders > 0)
506 {
507 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD || pIntRWSem->cWriters > 1,
508 ("The lock is write owned by there is only one waiter...\n"));
509
510 /*
511 * Release the mutex and wait on the writer semaphore.
512 */
513 rc = RTSemMutexRelease(pIntRWSem->Mutex);
514 if (RT_FAILURE(rc))
515 {
516 AssertMsgFailed(("RTSemMutexRelease failed on rwsem %p, rc=%d\n", RWSem, rc));
517 return VERR_SEM_DESTROYED;
518 }
519
520 /*
521 * Wait.
522 */
523 if (cMillies != RTSEM_INDEFINITE_WAIT)
524 {
525 int64_t tsDelta = RTTimeNanoTS() - tsStart;
526 if (tsDelta >= 1000000)
527 {
528 cMillies = cMilliesInitial - (unsigned)(tsDelta / 1000000);
529 if (cMillies > cMilliesInitial)
530 cMillies = cMilliesInitial ? 1 : 0;
531 }
532 }
533 rc = RTSemEventWait(pIntRWSem->WriteEvent, cMillies);
534
535 /*
536 * Check that the semaphore wasn't destroyed while we waited.
537 */
538 if ( rc == VERR_SEM_DESTROYED
539 || pIntRWSem->u32Check != (uint32_t)~0)
540 return VERR_SEM_DESTROYED;
541
542 /*
543 * Attempt take the mutex.
544 */
545 int rc2 = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
546 if (RT_FAILURE(rc) || RT_FAILURE(rc2))
547 {
548 AssertMsg(RT_SUCCESS(rc2), ("RTSemMutexRequest failed on rwsem %p, rc=%d\n", RWSem, rc2));
549 if (RT_SUCCESS(rc))
550 rc = rc2;
551 else
552 AssertMsg(rc == VERR_TIMEOUT, ("RTSemEventWait failed on rwsem %p, rc=%d\n", RWSem, rc));
553
554 /*
555 * Remove our selves from the writers queue.
556 */
557 /** @todo write an atomic dec function! (it's too late for that kind of stuff tonight) */
558 if (pIntRWSem->cWriters > 0)
559 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1);
560 if (!pIntRWSem->cWriters)
561 RTSemEventMultiSignal(pIntRWSem->ReadEvent);
562 if (RT_SUCCESS(rc2))
563 RTSemMutexRelease(pIntRWSem->Mutex);
564 return rc;
565 }
566
567 AssertMsg(pIntRWSem->WROwner == NIL_RTTHREAD, ("We woke up an there is owner! %#x\n", pIntRWSem->WROwner));
568 AssertMsg(!pIntRWSem->cReaders, ("We woke up an there are readers around!\n"));
569 }
570
571 /*
572 * If we get here we own the mutex and we are ready to take
573 * the read-write ownership.
574 */
575 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)Self);
576 rc = RTSemMutexRelease(pIntRWSem->Mutex);
577 AssertMsg(RT_SUCCESS(rc), ("RTSemMutexRelease failed. rc=%d\n", rc)); NOREF(rc);
578
579 return VINF_SUCCESS;
580#endif
581}
582
583
584RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
585{
586 return RTSemRWRequestWrite(RWSem, cMillies);
587}
588
589
590
591RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
592{
593 /*
594 * Validate handle.
595 */
596 if (!rtsemRWValid(RWSem))
597 {
598 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
599 return VERR_INVALID_HANDLE;
600 }
601
602#ifdef USE_CRIT_SECT
603 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
604 return RTCritSectLeave(&pIntRWSem->CritSect);
605#else
606
607 /*
608 * Check if owner.
609 */
610 //RTTHREAD Self = RTThreadSelf();
611 RTTHREAD Self = (RTTHREAD)RTThreadNativeSelf();
612 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
613 if (pIntRWSem->WROwner != Self)
614 {
615 AssertMsgFailed(("Not read-write owner of rwsem %p.\n", RWSem));
616 return VERR_NOT_OWNER;
617 }
618
619 /*
620 * Request the mutex.
621 */
622 int rc = RTSemMutexRequest(pIntRWSem->Mutex, RTSEM_INDEFINITE_WAIT);
623 if (RT_FAILURE(rc))
624 {
625 AssertMsgFailed(("RTSemMutexWait failed on rwsem %p, rc=%d\n", RWSem, rc));
626 return rc;
627 }
628
629 /*
630 * Release ownership and remove ourselves from the writers count.
631 */
632 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)NIL_RTTHREAD);
633 Assert(pIntRWSem->cWriters > 0);
634 ASMAtomicXchgU32(&pIntRWSem->cWriters, pIntRWSem->cWriters - 1);
635
636 /*
637 * Release the readers if no more writers.
638 */
639 if (!pIntRWSem->cWriters)
640 {
641 rc = RTSemEventMultiSignal(pIntRWSem->ReadEvent);
642 AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); NOREF(rc);
643 }
644 rc = RTSemMutexRelease(pIntRWSem->Mutex);
645 AssertMsg(RT_SUCCESS(rc), ("RTSemEventMultiSignal failed for rwsem %p, rc=%d.\n", RWSem, rc)); NOREF(rc);
646
647 return VINF_SUCCESS;
648#endif
649}
650
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