VirtualBox

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

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

Solaris.

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