VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp@ 57358

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.5 KB
Line 
1/* $Id: semeventmulti-posix.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/semaphore.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/lockvalidator.h>
38#include <iprt/mem.h>
39#include <iprt/time.h>
40
41#include "internal/strict.h"
42
43#include <errno.h>
44#include <pthread.h>
45#include <unistd.h>
46#include <sys/time.h>
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** @def IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
53 * Set if the platform implements pthread_condattr_setclock().
54 * Enables the use of the monotonic clock for waiting on condition variables. */
55#ifndef IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
56/* Linux detection */
57# if defined(RT_OS_LINUX) && defined(__USE_XOPEN2K)
58# include <features.h>
59# if __GLIBC_PREREQ(2,6) /** @todo figure the exact version where this was added */
60# define IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK
61# endif
62# endif
63/** @todo check other platforms */
64#endif
65
66
67/*********************************************************************************************************************************
68* Structures and Typedefs *
69*********************************************************************************************************************************/
70/** Posix internal representation of a Mutex Multi semaphore.
71 * The POSIX implementation uses a mutex and a condition variable to implement
72 * the automatic reset event semaphore semantics. */
73struct RTSEMEVENTMULTIINTERNAL
74{
75 /** pthread condition. */
76 pthread_cond_t Cond;
77 /** pthread mutex which protects the condition and the event state. */
78 pthread_mutex_t Mutex;
79 /** The state of the semaphore.
80 * This is operated while owning mutex and using atomic updating. */
81 volatile uint32_t u32State;
82 /** Number of waiters. */
83 volatile uint32_t cWaiters;
84#ifdef RTSEMEVENTMULTI_STRICT
85 /** Signallers. */
86 RTLOCKVALRECSHRD Signallers;
87 /** Indicates that lock validation should be performed. */
88 bool volatile fEverHadSignallers;
89#endif
90 /** Set if we're using the monotonic clock. */
91 bool fMonotonicClock;
92};
93
94/** The values of the u32State variable in RTSEMEVENTMULTIINTERNAL.
95 * @{ */
96/** The object isn't initialized. */
97#define EVENTMULTI_STATE_UNINITIALIZED 0
98/** The semaphore is signaled. */
99#define EVENTMULTI_STATE_SIGNALED 0xff00ff00
100/** The semaphore is not signaled. */
101#define EVENTMULTI_STATE_NOT_SIGNALED 0x00ff00ff
102/** @} */
103
104
105
106RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
107{
108 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
109}
110
111
112RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
113 const char *pszNameFmt, ...)
114{
115 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
116
117 /*
118 * Allocate semaphore handle.
119 */
120 int rc;
121 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
122 if (pThis)
123 {
124 /*
125 * Create the condition variable.
126 */
127 pthread_condattr_t CondAttr;
128 rc = pthread_condattr_init(&CondAttr);
129 if (!rc)
130 {
131#if defined(CLOCK_MONOTONIC) && defined(IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK)
132 /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */
133 rc = pthread_condattr_setclock(&CondAttr, CLOCK_MONOTONIC);
134 pThis->fMonotonicClock = rc == 0;
135#else
136 pThis->fMonotonicClock = false;
137#endif
138 rc = pthread_cond_init(&pThis->Cond, &CondAttr);
139 if (!rc)
140 {
141 /*
142 * Create the semaphore.
143 */
144 pthread_mutexattr_t MutexAttr;
145 rc = pthread_mutexattr_init(&MutexAttr);
146 if (!rc)
147 {
148 rc = pthread_mutex_init(&pThis->Mutex, &MutexAttr);
149 if (!rc)
150 {
151 pthread_mutexattr_destroy(&MutexAttr);
152 pthread_condattr_destroy(&CondAttr);
153
154 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
155 ASMAtomicXchgU32(&pThis->cWaiters, 0);
156#ifdef RTSEMEVENTMULTI_STRICT
157 if (!pszNameFmt)
158 {
159 static uint32_t volatile s_iSemEventMultiAnon = 0;
160 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
161 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
162 "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1);
163 }
164 else
165 {
166 va_list va;
167 va_start(va, pszNameFmt);
168 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
169 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
170 pszNameFmt, va);
171 va_end(va);
172 }
173 pThis->fEverHadSignallers = false;
174#endif
175
176 *phEventMultiSem = pThis;
177 return VINF_SUCCESS;
178 }
179
180 pthread_mutexattr_destroy(&MutexAttr);
181 }
182 pthread_cond_destroy(&pThis->Cond);
183 }
184 pthread_condattr_destroy(&CondAttr);
185 }
186
187 rc = RTErrConvertFromErrno(rc);
188 RTMemFree(pThis);
189 }
190 else
191 rc = VERR_NO_MEMORY;
192
193 return rc;
194
195}
196
197
198RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
199{
200 /*
201 * Validate handle.
202 */
203 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
204 if (pThis == NIL_RTSEMEVENTMULTI)
205 return VINF_SUCCESS;
206 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
207 uint32_t u32 = pThis->u32State;
208 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
209
210 /*
211 * Abort all waiters forcing them to return failure.
212 */
213 int rc;
214 for (int i = 30; i > 0; i--)
215 {
216 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED);
217 rc = pthread_cond_destroy(&pThis->Cond);
218 if (rc != EBUSY)
219 break;
220 pthread_cond_broadcast(&pThis->Cond);
221 usleep(1000);
222 }
223 if (rc)
224 {
225 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", hEventMultiSem, rc));
226 return RTErrConvertFromErrno(rc);
227 }
228
229 /*
230 * Destroy the semaphore
231 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
232 */
233 for (int i = 30; i > 0; i--)
234 {
235 rc = pthread_mutex_destroy(&pThis->Mutex);
236 if (rc != EBUSY)
237 break;
238 usleep(1000);
239 }
240 if (rc)
241 {
242 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", hEventMultiSem, rc));
243 return RTErrConvertFromErrno(rc);
244 }
245
246 /*
247 * Free the semaphore memory and be gone.
248 */
249#ifdef RTSEMEVENTMULTI_STRICT
250 RTLockValidatorRecSharedDelete(&pThis->Signallers);
251#endif
252 RTMemFree(pThis);
253 return VINF_SUCCESS;
254}
255
256
257RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
258{
259 /*
260 * Validate input.
261 */
262 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
263 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
264 uint32_t u32 = pThis->u32State;
265 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
266
267#ifdef RTSEMEVENTMULTI_STRICT
268 if (pThis->fEverHadSignallers)
269 {
270 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
271 if (RT_FAILURE(rc9))
272 return rc9;
273 }
274#endif
275
276 /*
277 * Lock the mutex semaphore.
278 */
279 int rc = pthread_mutex_lock(&pThis->Mutex);
280 if (rc)
281 {
282 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventMultiSem, rc));
283 return RTErrConvertFromErrno(rc);
284 }
285
286 /*
287 * Check the state.
288 */
289 if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED)
290 {
291 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED);
292 rc = pthread_cond_broadcast(&pThis->Cond);
293 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventMultiSem, rc));
294 }
295 else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
296 {
297 rc = pthread_cond_broadcast(&pThis->Cond); /* give'm another kick... */
298 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventMultiSem, rc));
299 }
300 else
301 rc = VERR_SEM_DESTROYED;
302
303 /*
304 * Release the mutex and return.
305 */
306 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
307 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventMultiSem, rc));
308 if (rc)
309 return RTErrConvertFromErrno(rc);
310 if (rc2)
311 return RTErrConvertFromErrno(rc2);
312
313 return VINF_SUCCESS;
314}
315
316
317RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
318{
319 /*
320 * Validate input.
321 */
322 int rc = VINF_SUCCESS;
323 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
324 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
325 uint32_t u32 = pThis->u32State;
326 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
327
328 /*
329 * Lock the mutex semaphore.
330 */
331 int rcPosix = pthread_mutex_lock(&pThis->Mutex);
332 if (RT_UNLIKELY(rcPosix))
333 {
334 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix));
335 return RTErrConvertFromErrno(rcPosix);
336 }
337
338 /*
339 * Check the state.
340 */
341 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
342 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
343 else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED)
344 rc = VERR_SEM_DESTROYED;
345
346 /*
347 * Release the mutex and return.
348 */
349 rcPosix = pthread_mutex_unlock(&pThis->Mutex);
350 if (RT_UNLIKELY(rcPosix))
351 {
352 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix));
353 return RTErrConvertFromErrno(rcPosix);
354 }
355
356 return rc;
357}
358
359
360/**
361 * Handle polling (timeout already expired at the time of the call).
362 *
363 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
364 * @param pThis The semaphore.
365 */
366DECLINLINE(int) rtSemEventMultiPosixWaitPoll(struct RTSEMEVENTMULTIINTERNAL *pThis)
367{
368 int rc = pthread_mutex_lock(&pThis->Mutex);
369 AssertMsgReturn(!rc, ("Failed to lock event multi sem %p, rc=%d.\n", pThis, rc), RTErrConvertFromErrno(rc));
370
371 uint32_t const u32State = pThis->u32State;
372
373 rc = pthread_mutex_unlock(&pThis->Mutex);
374 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc)); NOREF(rc);
375
376 return u32State == EVENTMULTI_STATE_SIGNALED
377 ? VINF_SUCCESS
378 : u32State != EVENTMULTI_STATE_UNINITIALIZED
379 ? VERR_TIMEOUT
380 : VERR_SEM_DESTROYED;
381}
382
383
384
385/**
386 * Implements the indefinite wait.
387 *
388 * @returns See RTSemEventMultiWaitEx.
389 * @param pThis The semaphore.
390 * @param fFlags See RTSemEventMultiWaitEx.
391 * @param pSrcPos The source position, can be NULL.
392 */
393static int rtSemEventMultiPosixWaitIndefinite(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, PCRTLOCKVALSRCPOS pSrcPos)
394{
395 /* take mutex */
396 int rc = pthread_mutex_lock(&pThis->Mutex);
397 AssertMsgReturn(!rc, ("Failed to lock event multi sem %p, rc=%d.\n", pThis, rc), RTErrConvertFromErrno(rc));
398 ASMAtomicIncU32(&pThis->cWaiters);
399
400 for (;;)
401 {
402 /* check state. */
403 uint32_t const u32State = pThis->u32State;
404 if (u32State != EVENTMULTI_STATE_NOT_SIGNALED)
405 {
406 ASMAtomicDecU32(&pThis->cWaiters);
407 rc = pthread_mutex_unlock(&pThis->Mutex);
408 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc));
409 return u32State == EVENTMULTI_STATE_SIGNALED
410 ? VINF_SUCCESS
411 : VERR_SEM_DESTROYED;
412 }
413
414 /* wait */
415#ifdef RTSEMEVENTMULTI_STRICT
416 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
417 if (pThis->fEverHadSignallers)
418 {
419 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
420 RT_INDEFINITE_WAIT, RTTHREADSTATE_EVENT_MULTI, true);
421 if (RT_FAILURE(rc))
422 {
423 ASMAtomicDecU32(&pThis->cWaiters);
424 pthread_mutex_unlock(&pThis->Mutex);
425 return rc;
426 }
427 }
428#else
429 RTTHREAD hThreadSelf = RTThreadSelf();
430#endif
431 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
432 /** @todo interruptible wait is not implementable... */ NOREF(fFlags);
433 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
434 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
435 if (RT_UNLIKELY(rc))
436 {
437 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", pThis, rc));
438 ASMAtomicDecU32(&pThis->cWaiters);
439 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
440 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2);
441 return RTErrConvertFromErrno(rc);
442 }
443 }
444}
445
446
447/**
448 * Implements the timed wait.
449 *
450 * @returns See RTSemEventMultiWaitEx
451 * @param pThis The semaphore.
452 * @param fFlags See RTSemEventMultiWaitEx.
453 * @param uTimeout See RTSemEventMultiWaitEx.
454 * @param pSrcPos The source position, can be NULL.
455 */
456static int rtSemEventMultiPosixWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
457 PCRTLOCKVALSRCPOS pSrcPos)
458{
459 /*
460 * Convert uTimeout to a relative value in nano seconds.
461 */
462 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
463 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
464 ? uTimeout * UINT32_C(1000000)
465 : UINT64_MAX;
466 if (uTimeout == UINT64_MAX) /* unofficial way of indicating an indefinite wait */
467 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
468
469 uint64_t uAbsTimeout = uTimeout;
470 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
471 {
472 uint64_t u64Now = RTTimeSystemNanoTS();
473 uTimeout = uTimeout > u64Now ? uTimeout - u64Now : 0;
474 }
475
476 if (uTimeout == 0)
477 return rtSemEventMultiPosixWaitPoll(pThis);
478
479 /*
480 * Get current time and calc end of deadline relative to real time.
481 */
482 struct timespec ts = {0,0};
483 if (!pThis->fMonotonicClock)
484 {
485#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
486 struct timeval tv = {0,0};
487 gettimeofday(&tv, NULL);
488 ts.tv_sec = tv.tv_sec;
489 ts.tv_nsec = tv.tv_usec * 1000;
490#else
491 clock_gettime(CLOCK_REALTIME, &ts);
492#endif
493 struct timespec tsAdd;
494 tsAdd.tv_nsec = uTimeout % UINT32_C(1000000000);
495 tsAdd.tv_sec = uTimeout / UINT32_C(1000000000);
496 if ( sizeof(ts.tv_sec) < sizeof(uint64_t)
497 && ( uTimeout > UINT64_C(1000000000) * UINT32_MAX
498 || (uint64_t)ts.tv_sec + tsAdd.tv_sec >= UINT32_MAX) )
499 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
500
501 ts.tv_sec += tsAdd.tv_sec;
502 ts.tv_nsec += tsAdd.tv_nsec;
503 if (ts.tv_nsec >= 1000000000)
504 {
505 ts.tv_nsec -= 1000000000;
506 ts.tv_sec++;
507 }
508 /* Note! No need to complete uAbsTimeout for RTSEMWAIT_FLAGS_RELATIVE in this path. */
509 }
510 else
511 {
512 /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */
513 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
514 uAbsTimeout += RTTimeSystemNanoTS();
515 if ( sizeof(ts.tv_sec) < sizeof(uint64_t)
516 && uAbsTimeout > UINT64_C(1000000000) * UINT32_MAX)
517 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
518 ts.tv_nsec = uAbsTimeout % UINT32_C(1000000000);
519 ts.tv_sec = uAbsTimeout / UINT32_C(1000000000);
520 }
521
522 /*
523 * To business!
524 */
525 /* take mutex */
526 int rc = pthread_mutex_lock(&pThis->Mutex);
527 AssertMsgReturn(rc == 0, ("rc=%d pThis=%p\n", rc, pThis), RTErrConvertFromErrno(rc)); NOREF(rc);
528 ASMAtomicIncU32(&pThis->cWaiters);
529
530 for (;;)
531 {
532 /* check state. */
533 uint32_t const u32State = pThis->u32State;
534 if (u32State != EVENTMULTI_STATE_NOT_SIGNALED)
535 {
536 ASMAtomicDecU32(&pThis->cWaiters);
537 rc = pthread_mutex_unlock(&pThis->Mutex);
538 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc));
539 return u32State == EVENTMULTI_STATE_SIGNALED
540 ? VINF_SUCCESS
541 : VERR_SEM_DESTROYED;
542 }
543
544 /* wait */
545#ifdef RTSEMEVENTMULTI_STRICT
546 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
547 if (pThis->fEverHadSignallers)
548 {
549 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
550 uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
551 if (RT_FAILURE(rc))
552 {
553 ASMAtomicDecU32(&pThis->cWaiters);
554 pthread_mutex_unlock(&pThis->Mutex);
555 return rc;
556 }
557 }
558#else
559 RTTHREAD hThreadSelf = RTThreadSelf();
560#endif
561 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
562 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
563 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
564 if ( rc
565 && ( rc != EINTR /* according to SuS this function shall not return EINTR, but linux man page says differently. */
566 || (fFlags & RTSEMWAIT_FLAGS_NORESUME)) )
567 {
568 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", pThis, rc));
569 ASMAtomicDecU32(&pThis->cWaiters);
570 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
571 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2);
572 return RTErrConvertFromErrno(rc);
573 }
574
575 /* check the absolute deadline. */
576 }
577}
578
579
580DECLINLINE(int) rtSemEventMultiPosixWait(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
581 PCRTLOCKVALSRCPOS pSrcPos)
582{
583 /*
584 * Validate input.
585 */
586 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
587 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
588 uint32_t u32 = pThis->u32State;
589 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
590 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
591
592 /*
593 * Optimize the case where the event is signalled.
594 */
595 if (ASMAtomicUoReadU32(&pThis->u32State) == EVENTMULTI_STATE_SIGNALED)
596 {
597 int rc = rtSemEventMultiPosixWaitPoll(pThis);
598 if (RT_LIKELY(rc != VERR_TIMEOUT))
599 return rc;
600 }
601
602 /*
603 * Indefinite or timed wait?
604 */
605 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
606 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
607 return rtSemEventMultiPosixWaitTimed(pThis, fFlags, uTimeout, pSrcPos);
608}
609
610
611#undef RTSemEventMultiWaitEx
612RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
613{
614#ifndef RTSEMEVENT_STRICT
615 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, NULL);
616#else
617 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
618 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
619#endif
620}
621
622
623RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
624 RTHCUINTPTR uId, RT_SRC_POS_DECL)
625{
626 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
627 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
628}
629
630
631RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
632{
633#ifdef RTSEMEVENTMULTI_STRICT
634 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
635 AssertPtrReturnVoid(pThis);
636 uint32_t u32 = pThis->u32State;
637 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
638
639 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
640 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
641#endif
642}
643
644
645RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
646{
647#ifdef RTSEMEVENTMULTI_STRICT
648 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
649 AssertPtrReturnVoid(pThis);
650 uint32_t u32 = pThis->u32State;
651 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
652
653 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
654 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
655#endif
656}
657
658
659RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
660{
661#ifdef RTSEMEVENTMULTI_STRICT
662 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
663 AssertPtrReturnVoid(pThis);
664 uint32_t u32 = pThis->u32State;
665 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
666
667 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
668#endif
669}
670
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