VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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