VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/sems-posix.cpp@ 2981

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

InnoTek -> innotek: all the headers and comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.1 KB
Line 
1/* $Id: sems-posix.cpp 2981 2007-06-01 16:01:28Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Semaphores, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <iprt/semaphore.h>
26#include <iprt/assert.h>
27#include <iprt/alloc.h>
28#include <iprt/asm.h>
29#include <iprt/err.h>
30
31#include <errno.h>
32#include <pthread.h>
33#include <unistd.h>
34#include <sys/time.h>
35
36#ifdef __DARWIN__
37# define pthread_yield() pthread_yield_np()
38#endif
39
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44
45/** Internal representation of the POSIX implementation of an Event semaphore.
46 * The POSIX implementation uses a mutex and a condition variable to implement
47 * the automatic reset event semaphore semantics.
48 *
49 * This must be identical to RTSEMEVENTMULTIINTERNAL!
50 */
51struct RTSEMEVENTINTERNAL
52{
53 /** pthread condition. */
54 pthread_cond_t Cond;
55 /** pthread mutex which protects the condition and the event state. */
56 pthread_mutex_t Mutex;
57 /** The state of the semaphore.
58 * This is operated while owning mutex and using atomic updating. */
59 volatile uint32_t u32State;
60 /** Number of waiters. */
61 volatile uint32_t cWaiters;
62};
63
64/** Posix internal representation of a Mutex Multi semaphore.
65 * This must be identical to RTSEMEVENTINTERNAL! */
66struct RTSEMEVENTMULTIINTERNAL
67{
68 /** pthread condition. */
69 pthread_cond_t Cond;
70 /** pthread mutex which protects the condition and the event state. */
71 pthread_mutex_t Mutex;
72 /** The state of the semaphore.
73 * This is operated while owning mutex and using atomic updating. */
74 volatile uint32_t u32State;
75 /** Number of waiters. */
76 volatile uint32_t cWaiters;
77};
78
79/** The valus of the u32State variable in a RTSEMEVENTINTERNAL and RTSEMEVENTMULTIINTERNAL.
80 * @{ */
81/** The object isn't initialized. */
82#define EVENT_STATE_UNINITIALIZED 0
83/** The semaphore is is signaled. */
84#define EVENT_STATE_SIGNALED 0xff00ff00
85/** The semaphore is not signaled. */
86#define EVENT_STATE_NOT_SIGNALED 0x00ff00ff
87/** @} */
88
89
90/** Posix internal representation of a Mutex semaphore. */
91struct RTSEMMUTEXINTERNAL
92{
93 /** pthread mutex. */
94 pthread_mutex_t Mutex;
95 /** The owner of the mutex. */
96 volatile pthread_t Owner;
97 /** Nesting count. */
98 volatile uint32_t cNesting;
99};
100
101/** Posix internal representation of a read-write semaphore. */
102struct RTSEMRWINTERNAL
103{
104 /** pthread rwlock. */
105 pthread_rwlock_t RWLock;
106 /** Variable to check if initialized.
107 * 0 is uninitialized, ~0 is inititialized. */
108 volatile unsigned uCheck;
109 /** The write owner of the lock. */
110 volatile pthread_t WROwner;
111};
112
113
114/**
115 * Validate an Event semaphore handle passed to one of the interface.
116 *
117 * @returns true if valid.
118 * @returns false if invalid.
119 * @param pIntEventSem Pointer to the event semaphore to validate.
120 */
121inline bool rtsemEventValid(struct RTSEMEVENTINTERNAL *pIntEventSem)
122{
123 if ((uintptr_t)pIntEventSem < 0x10000)
124 return false;
125
126 uint32_t u32 = pIntEventSem->u32State; /* this is volatile, so a explicit read like this is needed. */
127 if ( u32 != EVENT_STATE_NOT_SIGNALED
128 && u32 != EVENT_STATE_SIGNALED)
129 return false;
130
131 return true;
132}
133
134
135RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)
136{
137 int rc;
138
139 /*
140 * Allocate semaphore handle.
141 */
142 struct RTSEMEVENTINTERNAL *pIntEventSem = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTINTERNAL));
143 if (pIntEventSem)
144 {
145 /*
146 * Create the condition variable.
147 */
148 pthread_condattr_t CondAttr;
149 rc = pthread_condattr_init(&CondAttr);
150 if (!rc)
151 {
152 rc = pthread_cond_init(&pIntEventSem->Cond, &CondAttr);
153 if (!rc)
154 {
155 /*
156 * Create the semaphore.
157 */
158 pthread_mutexattr_t MutexAttr;
159 rc = pthread_mutexattr_init(&MutexAttr);
160 if (!rc)
161 {
162 rc = pthread_mutex_init(&pIntEventSem->Mutex, &MutexAttr);
163 if (!rc)
164 {
165 pthread_mutexattr_destroy(&MutexAttr);
166 pthread_condattr_destroy(&CondAttr);
167
168 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
169 ASMAtomicXchgU32(&pIntEventSem->cWaiters, 0);
170
171 *pEventSem = pIntEventSem;
172 return VINF_SUCCESS;
173 }
174 pthread_mutexattr_destroy(&MutexAttr);
175 }
176 pthread_cond_destroy(&pIntEventSem->Cond);
177 }
178 pthread_condattr_destroy(&CondAttr);
179 }
180
181 rc = RTErrConvertFromErrno(rc);
182 RTMemFree(pIntEventSem);
183 }
184 else
185 rc = VERR_NO_MEMORY;
186
187 return rc;
188}
189
190
191RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)
192{
193 /*
194 * Validate handle.
195 */
196 if (!rtsemEventValid(EventSem))
197 {
198 AssertMsgFailed(("Invalid handle %p!\n", EventSem));
199 return VERR_INVALID_HANDLE;
200 }
201
202 /*
203 * Abort all waiters forcing them to return failure.
204 *
205 */
206 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
207 int rc;
208 for (int i = 30; i > 0; i--)
209 {
210 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_UNINITIALIZED);
211 rc = pthread_cond_destroy(&pIntEventSem->Cond);
212 if (rc != EBUSY)
213 break;
214 pthread_cond_broadcast(&pIntEventSem->Cond);
215 usleep(1000);
216 } while (rc == EBUSY);
217 if (rc)
218 {
219 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", EventSem, rc));
220 return RTErrConvertFromErrno(rc);
221 }
222
223 /*
224 * Destroy the semaphore
225 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
226 */
227 for (int i = 30; i > 0; i--)
228 {
229 rc = pthread_mutex_destroy(&pIntEventSem->Mutex);
230 if (rc != EBUSY)
231 break;
232 usleep(1000);
233 }
234 if (rc)
235 {
236 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", EventSem, rc));
237 return RTErrConvertFromErrno(rc);
238 }
239
240 /*
241 * Free the semaphore memory and be gone.
242 */
243 RTMemFree(pIntEventSem);
244 return VINF_SUCCESS;
245}
246
247
248RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)
249{
250 /*
251 * Validate input.
252 */
253 if (!rtsemEventValid(EventSem))
254 {
255 AssertMsgFailed(("Invalid handle %p!\n", EventSem));
256 return VERR_INVALID_HANDLE;
257 }
258
259 /*
260 * Lock the mutex semaphore.
261 */
262 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
263 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
264 if (rc)
265 {
266 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
267 return RTErrConvertFromErrno(rc);
268 }
269
270 /*
271 * Check the state.
272 */
273 if (pIntEventSem->u32State == EVENT_STATE_NOT_SIGNALED)
274 {
275 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_SIGNALED);
276 rc = pthread_cond_signal(&pIntEventSem->Cond);
277 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", EventSem, rc));
278 }
279 else if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
280 {
281 rc = pthread_cond_signal(&pIntEventSem->Cond); /* give'm another kick... */
282 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", EventSem, rc));
283 }
284 else
285 rc = VERR_SEM_DESTROYED;
286
287 /*
288 * Release the mutex and return.
289 */
290 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
291 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc));
292 if (rc)
293 return RTErrConvertFromErrno(rc);
294 if (rc2)
295 return RTErrConvertFromErrno(rc2);
296
297 return VINF_SUCCESS;
298}
299
300
301static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fAutoResume)
302{
303 /*
304 * Validate input.
305 */
306 if (!rtsemEventValid(EventSem))
307 {
308 AssertMsgFailed(("Invalid handle %p!\n", EventSem));
309 return VERR_INVALID_HANDLE;
310 }
311
312 /*
313 * Timed or indefinite wait?
314 */
315 struct RTSEMEVENTINTERNAL *pIntEventSem = EventSem;
316 if (cMillies == RT_INDEFINITE_WAIT)
317 {
318 /* for fairness, yield before going to sleep. */
319 if ( ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1
320 && pIntEventSem->u32State == EVENT_STATE_SIGNALED)
321 pthread_yield();
322
323 /* take mutex */
324 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
325 if (rc)
326 {
327 ASMAtomicDecU32(&pIntEventSem->cWaiters);
328 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
329 return RTErrConvertFromErrno(rc);
330 }
331
332 for (;;)
333 {
334 /* check state. */
335 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
336 {
337 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
338 ASMAtomicDecU32(&pIntEventSem->cWaiters);
339 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
340 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
341 return VINF_SUCCESS;
342 }
343 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
344 {
345 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
346 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
347 return VERR_SEM_DESTROYED;
348 }
349
350 /* wait */
351 rc = pthread_cond_wait(&pIntEventSem->Cond, &pIntEventSem->Mutex);
352 if (rc)
353 {
354 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
355 ASMAtomicDecU32(&pIntEventSem->cWaiters);
356 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
357 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc2)); NOREF(rc2);
358 return RTErrConvertFromErrno(rc);
359 }
360 }
361 }
362 else
363 {
364 /*
365 * Get current time and calc end of wait time.
366 */
367 struct timespec ts = {0,0};
368#ifdef __DARWIN__
369 struct timeval tv = {0,0};
370 gettimeofday(&tv, NULL);
371 ts.tv_sec = tv.tv_sec;
372 ts.tv_nsec = tv.tv_usec * 1000;
373#else
374 clock_gettime(CLOCK_REALTIME, &ts);
375#endif
376 if (cMillies != 0)
377 {
378 ts.tv_nsec += (cMillies % 1000) * 1000000;
379 ts.tv_sec += cMillies / 1000;
380 if (ts.tv_nsec >= 1000000000)
381 {
382 ts.tv_nsec -= 1000000000;
383 ts.tv_sec++;
384 }
385 }
386
387 /* for fairness, yield before going to sleep. */
388 if (ASMAtomicIncU32(&pIntEventSem->cWaiters) > 1)
389 pthread_yield();
390
391 /* take mutex */
392#ifdef __DARWIN__
393 int rc = pthread_mutex_lock(&pIntEventSem->Mutex);
394#else
395 int rc = pthread_mutex_timedlock(&pIntEventSem->Mutex, &ts);
396#endif
397 if (rc)
398 {
399 ASMAtomicDecU32(&pIntEventSem->cWaiters);
400 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", EventSem, rc));
401 return RTErrConvertFromErrno(rc);
402 }
403
404 for (;;)
405 {
406 /* check state. */
407 if (pIntEventSem->u32State == EVENT_STATE_SIGNALED)
408 {
409 ASMAtomicXchgU32(&pIntEventSem->u32State, EVENT_STATE_NOT_SIGNALED);
410 ASMAtomicDecU32(&pIntEventSem->cWaiters);
411 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
412 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
413 return VINF_SUCCESS;
414 }
415 if (pIntEventSem->u32State == EVENT_STATE_UNINITIALIZED)
416 {
417 rc = pthread_mutex_unlock(&pIntEventSem->Mutex);
418 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", EventSem, rc)); NOREF(rc);
419 return VERR_SEM_DESTROYED;
420 }
421
422 /* wait */
423 rc = pthread_cond_timedwait(&pIntEventSem->Cond, &pIntEventSem->Mutex, &ts);
424 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
425 {
426 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", EventSem, rc));
427 ASMAtomicDecU32(&pIntEventSem->cWaiters);
428 int rc2 = pthread_mutex_unlock(&pIntEventSem->Mutex);
429 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", EventSem, rc2)); NOREF(rc2);
430 return RTErrConvertFromErrno(rc);
431 }
432 } /* for (;;) */
433 }
434}
435
436
437RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
438{
439 int rc = rtSemEventWait(EventSem, cMillies, true);
440 Assert(rc != VERR_INTERRUPTED);
441 return rc;
442}
443
444
445RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
446{
447 return rtSemEventWait(EventSem, cMillies, false);
448}
449
450
451
452
453
454
455/**
456 * Validate an event multi semaphore handle passed to one of the interface.
457 *
458 * @returns true if valid.
459 * @returns false if invalid.
460 * @param pIntEventMultiSem Pointer to the event semaphore to validate.
461 */
462inline bool rtsemEventMultiValid(struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem)
463{
464 if ((uintptr_t)pIntEventMultiSem < 0x10000)
465 return false;
466
467 uint32_t u32 = pIntEventMultiSem->u32State; /* this is volatile, so a explicit read like this is needed. */
468 if ( u32 != EVENT_STATE_NOT_SIGNALED
469 && u32 != EVENT_STATE_SIGNALED)
470 return false;
471
472 return true;
473}
474
475
476RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
477{
478 /* the code and the structure is identical with other type for this function. */
479 return RTSemEventCreate((PRTSEMEVENT)pEventMultiSem);
480}
481
482
483RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
484{
485 /* the code and the structure is identical with other type for this function. */
486 return RTSemEventDestroy((RTSEMEVENT)EventMultiSem);
487}
488
489
490RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
491{
492 /* the code and the structure is identical with other type for this function. */
493 return RTSemEventSignal((RTSEMEVENT)EventMultiSem);
494}
495
496
497RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
498{
499 /*
500 * Validate input.
501 */
502 if (!rtsemEventMultiValid(EventMultiSem))
503 {
504 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
505 return VERR_INVALID_HANDLE;
506 }
507
508 /*
509 * Lock the mutex semaphore.
510 */
511 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
512 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
513 if (rc)
514 {
515 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
516 return RTErrConvertFromErrno(rc);
517 }
518
519 /*
520 * Check the state.
521 */
522 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
523 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
524 else if (pIntEventMultiSem->u32State != EVENT_STATE_NOT_SIGNALED)
525 rc = VERR_SEM_DESTROYED;
526
527 /*
528 * Release the mutex and return.
529 */
530 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
531 if (rc)
532 {
533 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
534 return RTErrConvertFromErrno(rc);
535 }
536
537 return VINF_SUCCESS;
538
539}
540
541
542static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
543{
544 /*
545 * Validate input.
546 */
547 if (!rtsemEventMultiValid(EventMultiSem))
548 {
549 AssertMsgFailed(("Invalid handle %p!\n", EventMultiSem));
550 return VERR_INVALID_HANDLE;
551 }
552
553 /*
554 * Timed or indefinite wait?
555 */
556 struct RTSEMEVENTMULTIINTERNAL *pIntEventMultiSem = EventMultiSem;
557 if (cMillies == RT_INDEFINITE_WAIT)
558 {
559 /* take mutex */
560 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
561 if (rc)
562 {
563 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
564 return RTErrConvertFromErrno(rc);
565 }
566 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
567
568 for (;;)
569 {
570 /* check state. */
571 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
572 {
573 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
574 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
575 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
576 return VINF_SUCCESS;
577 }
578 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
579 {
580 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
581 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
582 return VERR_SEM_DESTROYED;
583 }
584
585 /* wait */
586 rc = pthread_cond_wait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex);
587 if (rc)
588 {
589 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
590 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
591 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
592 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
593 return RTErrConvertFromErrno(rc);
594 }
595 }
596 }
597 else
598 {
599 /*
600 * Get current time and calc end of wait time.
601 */
602 struct timespec ts = {0,0};
603#ifdef __DARWIN__
604 struct timeval tv = {0,0};
605 gettimeofday(&tv, NULL);
606 ts.tv_sec = tv.tv_sec;
607 ts.tv_nsec = tv.tv_usec * 1000;
608#else
609 clock_gettime(CLOCK_REALTIME, &ts);
610#endif
611 if (cMillies != 0)
612 {
613 ts.tv_nsec += (cMillies % 1000) * 1000000;
614 ts.tv_sec += cMillies / 1000;
615 if (ts.tv_nsec >= 1000000000)
616 {
617 ts.tv_nsec -= 1000000000;
618 ts.tv_sec++;
619 }
620 }
621
622 /* take mutex */
623#ifdef __DARWIN__
624 int rc = pthread_mutex_lock(&pIntEventMultiSem->Mutex);
625#else
626 int rc = pthread_mutex_timedlock(&pIntEventMultiSem->Mutex, &ts);
627#endif
628 if (rc)
629 {
630 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", EventMultiSem, rc));
631 return RTErrConvertFromErrno(rc);
632 }
633 ASMAtomicIncU32(&pIntEventMultiSem->cWaiters);
634
635 for (;;)
636 {
637 /* check state. */
638 if (pIntEventMultiSem->u32State == EVENT_STATE_SIGNALED)
639 {
640 ASMAtomicXchgU32(&pIntEventMultiSem->u32State, EVENT_STATE_NOT_SIGNALED);
641 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
642 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
643 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
644 return VINF_SUCCESS;
645 }
646 if (pIntEventMultiSem->u32State == EVENT_STATE_UNINITIALIZED)
647 {
648 rc = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
649 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc)); NOREF(rc);
650 return VERR_SEM_DESTROYED;
651 }
652
653 /* wait */
654 rc = pthread_cond_timedwait(&pIntEventMultiSem->Cond, &pIntEventMultiSem->Mutex, &ts);
655 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
656 {
657 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", EventMultiSem, rc));
658 ASMAtomicDecU32(&pIntEventMultiSem->cWaiters);
659 int rc2 = pthread_mutex_unlock(&pIntEventMultiSem->Mutex);
660 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", EventMultiSem, rc2)); NOREF(rc2);
661 return RTErrConvertFromErrno(rc);
662 }
663 }
664 }
665}
666
667
668RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
669{
670 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
671 Assert(rc != VERR_INTERRUPTED);
672 return rc;
673}
674
675
676RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
677{
678 return rtSemEventMultiWait(EventMultiSem, cMillies, false);
679}
680
681
682
683
684
685/**
686 * Validate a Mutex semaphore handle passed to one of the interface.
687 *
688 * @returns true if valid.
689 * @returns false if invalid.
690 * @param pIntMutexSem Pointer to the mutex semaphore to validate.
691 */
692inline bool rtsemMutexValid(struct RTSEMMUTEXINTERNAL *pIntMutexSem)
693{
694 if ((uintptr_t)pIntMutexSem < 0x10000)
695 return false;
696
697 if (pIntMutexSem->cNesting == (uint32_t)~0)
698 return false;
699
700 return true;
701}
702
703
704RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
705{
706 int rc;
707
708 /*
709 * Allocate semaphore handle.
710 */
711 struct RTSEMMUTEXINTERNAL *pIntMutexSem = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
712 if (pIntMutexSem)
713 {
714 /*
715 * Create the semaphore.
716 */
717 pthread_mutexattr_t MutexAttr;
718 rc = pthread_mutexattr_init(&MutexAttr);
719 if (!rc)
720 {
721 rc = pthread_mutex_init(&pIntMutexSem->Mutex, &MutexAttr);
722 if (!rc)
723 {
724 pthread_mutexattr_destroy(&MutexAttr);
725
726 pIntMutexSem->Owner = (pthread_t)~0;
727 pIntMutexSem->cNesting = 0;
728
729 *pMutexSem = pIntMutexSem;
730 return VINF_SUCCESS;
731 }
732 pthread_mutexattr_destroy(&MutexAttr);
733 }
734 RTMemFree(pIntMutexSem);
735 }
736 else
737 rc = VERR_NO_MEMORY;
738
739 return rc;
740}
741
742
743RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)
744{
745 /*
746 * Validate input.
747 */
748 if (!rtsemMutexValid(MutexSem))
749 {
750 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
751 return VERR_INVALID_HANDLE;
752 }
753
754 /*
755 * Try destroy it.
756 */
757 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
758 int rc = pthread_mutex_destroy(&pIntMutexSem->Mutex);
759 if (rc)
760 {
761 AssertMsgFailed(("Failed to destroy mutex sem %p, rc=%d.\n", MutexSem, rc));
762 return RTErrConvertFromErrno(rc);
763 }
764
765 /*
766 * Free the memory and be gone.
767 */
768 pIntMutexSem->Owner = (pthread_t)~0;
769 pIntMutexSem->cNesting = ~0;
770 RTMemTmpFree(pIntMutexSem);
771
772 return VINF_SUCCESS;
773}
774
775
776RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
777{
778 /*
779 * Validate input.
780 */
781 if (!rtsemMutexValid(MutexSem))
782 {
783 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
784 return VERR_INVALID_HANDLE;
785 }
786
787 /*
788 * Check if nested request.
789 */
790 pthread_t Self = pthread_self();
791 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
792 if ( pIntMutexSem->Owner == Self
793 && pIntMutexSem->cNesting > 0)
794 {
795 pIntMutexSem->cNesting++;
796 return VINF_SUCCESS;
797 }
798
799 /*
800 * Lock it.
801 */
802 if (cMillies == RT_INDEFINITE_WAIT)
803 {
804 /* take mutex */
805 int rc = pthread_mutex_lock(&pIntMutexSem->Mutex);
806 if (rc)
807 {
808 AssertMsgFailed(("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
809 return RTErrConvertFromErrno(rc);
810 }
811 }
812 else
813 {
814#ifdef __DARWIN__
815 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
816 return VERR_NOT_IMPLEMENTED;
817#else /* !__DARWIN__ */
818 /*
819 * Get current time and calc end of wait time.
820 */
821 struct timespec ts = {0,0};
822 clock_gettime(CLOCK_REALTIME, &ts);
823 if (cMillies != 0)
824 {
825 ts.tv_nsec += (cMillies % 1000) * 1000000;
826 ts.tv_sec += cMillies / 1000;
827 if (ts.tv_nsec >= 1000000000)
828 {
829 ts.tv_nsec -= 1000000000;
830 ts.tv_sec++;
831 }
832 }
833
834 /* take mutex */
835 int rc = pthread_mutex_timedlock(&pIntMutexSem->Mutex, &ts);
836 if (rc)
837 {
838 AssertMsg(rc == ETIMEDOUT, ("Failed to lock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
839 return RTErrConvertFromErrno(rc);
840 }
841#endif /* !__DARWIN__ */
842 }
843
844 /*
845 * Set the owner and nesting.
846 */
847 pIntMutexSem->Owner = Self;
848 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 1);
849
850 return VINF_SUCCESS;
851}
852
853
854RTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
855{
856 /* EINTR isn't returned by the wait functions we're using. */
857 return RTSemMutexRequest(MutexSem, cMillies);
858}
859
860
861RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)
862{
863 /*
864 * Validate input.
865 */
866 if (!rtsemMutexValid(MutexSem))
867 {
868 AssertMsgFailed(("Invalid handle %p!\n", MutexSem));
869 return VERR_INVALID_HANDLE;
870 }
871
872 /*
873 * Check if nested.
874 */
875 pthread_t Self = pthread_self();
876 struct RTSEMMUTEXINTERNAL *pIntMutexSem = MutexSem;
877 if ( pIntMutexSem->Owner != Self
878 || pIntMutexSem->cNesting == (uint32_t)~0)
879 {
880 AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
881 pIntMutexSem, Self, pIntMutexSem->Owner, pIntMutexSem->cNesting));
882 return VERR_NOT_OWNER;
883 }
884
885 /*
886 * If nested we'll just pop a nesting.
887 */
888 if (pIntMutexSem->cNesting > 1)
889 {
890 pIntMutexSem->cNesting--;
891 return VINF_SUCCESS;
892 }
893
894 /*
895 * Clear the state. (cNesting == 1)
896 */
897 pIntMutexSem->Owner = (pthread_t)~0;
898 ASMAtomicXchgU32(&pIntMutexSem->cNesting, 0);
899
900 /*
901 * Unlock mutex semaphore.
902 */
903 int rc = pthread_mutex_unlock(&pIntMutexSem->Mutex);
904 if (rc)
905 {
906 AssertMsgFailed(("Failed to unlock mutex sem %p, rc=%d.\n", MutexSem, rc)); NOREF(rc);
907 return RTErrConvertFromErrno(rc);
908 }
909
910 return VINF_SUCCESS;
911}
912
913
914
915
916
917/**
918 * Validate a read-write semaphore handle passed to one of the interface.
919 *
920 * @returns true if valid.
921 * @returns false if invalid.
922 * @param pIntRWSem Pointer to the read-write semaphore to validate.
923 */
924inline bool rtsemRWValid(struct RTSEMRWINTERNAL *pIntRWSem)
925{
926 if ((uintptr_t)pIntRWSem < 0x10000)
927 return false;
928
929 if (pIntRWSem->uCheck != (unsigned)~0)
930 return false;
931
932 return true;
933}
934
935
936RTDECL(int) RTSemRWCreate(PRTSEMRW pRWSem)
937{
938 int rc;
939
940 /*
941 * Allocate handle.
942 */
943 struct RTSEMRWINTERNAL *pIntRWSem = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
944 if (pIntRWSem)
945 {
946 /*
947 * Create the rwlock.
948 */
949 pthread_rwlockattr_t Attr;
950 rc = pthread_rwlockattr_init(&Attr);
951 if (!rc)
952 {
953 rc = pthread_rwlock_init(&pIntRWSem->RWLock, &Attr);
954 if (!rc)
955 {
956 pIntRWSem->uCheck = ~0;
957 pIntRWSem->WROwner = (pthread_t)~0;
958 *pRWSem = pIntRWSem;
959 return VINF_SUCCESS;
960 }
961 }
962
963 rc = RTErrConvertFromErrno(rc);
964 RTMemFree(pIntRWSem);
965 }
966 else
967 rc = VERR_NO_MEMORY;
968
969 return rc;
970}
971
972
973RTDECL(int) RTSemRWDestroy(RTSEMRW RWSem)
974{
975 /*
976 * Validate input.
977 */
978 if (!rtsemRWValid(RWSem))
979 {
980 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
981 return VERR_INVALID_HANDLE;
982 }
983
984 /*
985 * Try destroy it.
986 */
987 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
988 int rc = pthread_rwlock_destroy(&pIntRWSem->RWLock);
989 if (!rc)
990 {
991 pIntRWSem->uCheck = 0;
992 RTMemFree(pIntRWSem);
993 rc = VINF_SUCCESS;
994 }
995 else
996 {
997 AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
998 rc = RTErrConvertFromErrno(rc);
999 }
1000
1001 return rc;
1002}
1003
1004
1005RTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
1006{
1007 /*
1008 * Validate input.
1009 */
1010 if (!rtsemRWValid(RWSem))
1011 {
1012 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
1013 return VERR_INVALID_HANDLE;
1014 }
1015
1016 /*
1017 * Try lock it.
1018 */
1019 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
1020 if (cMillies == RT_INDEFINITE_WAIT)
1021 {
1022 /* take rwlock */
1023 int rc = pthread_rwlock_rdlock(&pIntRWSem->RWLock);
1024 if (rc)
1025 {
1026 AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1027 return RTErrConvertFromErrno(rc);
1028 }
1029 }
1030 else
1031 {
1032#ifdef __DARWIN__
1033 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
1034 return VERR_NOT_IMPLEMENTED;
1035#else /* !__DARWIN__ */
1036 /*
1037 * Get current time and calc end of wait time.
1038 */
1039 struct timespec ts = {0,0};
1040 clock_gettime(CLOCK_REALTIME, &ts);
1041 if (cMillies != 0)
1042 {
1043 ts.tv_nsec += (cMillies % 1000) * 1000000;
1044 ts.tv_sec += cMillies / 1000;
1045 if (ts.tv_nsec >= 1000000000)
1046 {
1047 ts.tv_nsec -= 1000000000;
1048 ts.tv_sec++;
1049 }
1050 }
1051
1052 /* take rwlock */
1053 int rc = pthread_rwlock_timedrdlock(&pIntRWSem->RWLock, &ts);
1054 if (rc)
1055 {
1056 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1057 return RTErrConvertFromErrno(rc);
1058 }
1059#endif /* !__DARWIN__ */
1060 }
1061
1062 return VINF_SUCCESS;
1063}
1064
1065
1066RTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
1067{
1068 /* EINTR isn't returned by the wait functions we're using. */
1069 return RTSemRWRequestRead(RWSem, cMillies);
1070}
1071
1072
1073RTDECL(int) RTSemRWReleaseRead(RTSEMRW RWSem)
1074{
1075 /*
1076 * Validate input.
1077 */
1078 if (!rtsemRWValid(RWSem))
1079 {
1080 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
1081 return VERR_INVALID_HANDLE;
1082 }
1083
1084 /*
1085 * Try unlock it.
1086 */
1087 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
1088 if (pIntRWSem->WROwner == pthread_self())
1089 {
1090 AssertMsgFailed(("Tried to read unlock when write owner - read-write sem %p.\n", RWSem));
1091 return VERR_NOT_OWNER;
1092 }
1093 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
1094 if (rc)
1095 {
1096 AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
1097 return RTErrConvertFromErrno(rc);
1098 }
1099
1100 return VINF_SUCCESS;
1101}
1102
1103
1104RTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
1105{
1106 /*
1107 * Validate input.
1108 */
1109 if (!rtsemRWValid(RWSem))
1110 {
1111 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
1112 return VERR_INVALID_HANDLE;
1113 }
1114
1115 /*
1116 * Try lock it.
1117 */
1118 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
1119 if (cMillies == RT_INDEFINITE_WAIT)
1120 {
1121 /* take rwlock */
1122 int rc = pthread_rwlock_wrlock(&pIntRWSem->RWLock);
1123 if (rc)
1124 {
1125 AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
1126 return RTErrConvertFromErrno(rc);
1127 }
1128 }
1129 else
1130 {
1131#ifdef __DARWIN__
1132 AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
1133 return VERR_NOT_IMPLEMENTED;
1134#else /* !__DARWIN__ */
1135 /*
1136 * Get current time and calc end of wait time.
1137 */
1138 struct timespec ts = {0,0};
1139 clock_gettime(CLOCK_REALTIME, &ts);
1140 if (cMillies != 0)
1141 {
1142 ts.tv_nsec += (cMillies % 1000) * 1000000;
1143 ts.tv_sec += cMillies / 1000;
1144 if (ts.tv_nsec >= 1000000000)
1145 {
1146 ts.tv_nsec -= 1000000000;
1147 ts.tv_sec++;
1148 }
1149 }
1150
1151 /* take rwlock */
1152 int rc = pthread_rwlock_timedwrlock(&pIntRWSem->RWLock, &ts);
1153 if (rc)
1154 {
1155 AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1156 return RTErrConvertFromErrno(rc);
1157 }
1158#endif /* !__DARWIN__ */
1159 }
1160
1161 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)pthread_self());
1162
1163 return VINF_SUCCESS;
1164}
1165
1166
1167RTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
1168{
1169 /* EINTR isn't returned by the wait functions we're using. */
1170 return RTSemRWRequestWrite(RWSem, cMillies);
1171}
1172
1173
1174RTDECL(int) RTSemRWReleaseWrite(RTSEMRW RWSem)
1175{
1176 /*
1177 * Validate input.
1178 */
1179 if (!rtsemRWValid(RWSem))
1180 {
1181 AssertMsgFailed(("Invalid handle %p!\n", RWSem));
1182 return VERR_INVALID_HANDLE;
1183 }
1184
1185 /*
1186 * Try unlock it.
1187 */
1188 pthread_t Self = pthread_self();
1189 struct RTSEMRWINTERNAL *pIntRWSem = RWSem;
1190 if (pIntRWSem->WROwner != Self)
1191 {
1192 AssertMsgFailed(("Not Write owner!\n"));
1193 return VERR_NOT_OWNER;
1194 }
1195
1196 /*
1197 * Try unlock it.
1198 */
1199 AssertMsg(sizeof(pthread_t) == sizeof(void *), ("pthread_t is not the size of a pointer but %d bytes\n", sizeof(pthread_t)));
1200 ASMAtomicXchgPtr((void * volatile *)&pIntRWSem->WROwner, (void *)(uintptr_t)~0);
1201 int rc = pthread_rwlock_unlock(&pIntRWSem->RWLock);
1202 if (rc)
1203 {
1204 AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
1205 return RTErrConvertFromErrno(rc);
1206 }
1207
1208 return VINF_SUCCESS;
1209}
1210
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