VirtualBox

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

Last change on this file since 86186 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.4 KB
Line 
1/* $Id: semeventmulti-posix.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 rc = pthread_mutex_init(&pThis->Mutex, NULL);
145 if (!rc)
146 {
147 pthread_condattr_destroy(&CondAttr);
148
149 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
150 ASMAtomicXchgU32(&pThis->cWaiters, 0);
151#ifdef RTSEMEVENTMULTI_STRICT
152 if (!pszNameFmt)
153 {
154 static uint32_t volatile s_iSemEventMultiAnon = 0;
155 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
156 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
157 "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1);
158 }
159 else
160 {
161 va_list va;
162 va_start(va, pszNameFmt);
163 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
164 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
165 pszNameFmt, va);
166 va_end(va);
167 }
168 pThis->fEverHadSignallers = false;
169#else
170 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
171#endif
172
173 *phEventMultiSem = pThis;
174 return VINF_SUCCESS;
175 }
176
177 pthread_cond_destroy(&pThis->Cond);
178 }
179 pthread_condattr_destroy(&CondAttr);
180 }
181
182 rc = RTErrConvertFromErrno(rc);
183 RTMemFree(pThis);
184 }
185 else
186 rc = VERR_NO_MEMORY;
187
188 return rc;
189
190}
191
192
193RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
194{
195 /*
196 * Validate handle.
197 */
198 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
199 if (pThis == NIL_RTSEMEVENTMULTI)
200 return VINF_SUCCESS;
201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
202 uint32_t u32 = pThis->u32State;
203 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
204
205 /*
206 * Abort all waiters forcing them to return failure.
207 */
208 int rc;
209 for (int i = 30; i > 0; i--)
210 {
211 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED);
212 rc = pthread_cond_destroy(&pThis->Cond);
213 if (rc != EBUSY)
214 break;
215 pthread_cond_broadcast(&pThis->Cond);
216 usleep(1000);
217 }
218 if (rc)
219 {
220 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", hEventMultiSem, 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(&pThis->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", hEventMultiSem, rc));
238 return RTErrConvertFromErrno(rc);
239 }
240
241 /*
242 * Free the semaphore memory and be gone.
243 */
244#ifdef RTSEMEVENTMULTI_STRICT
245 RTLockValidatorRecSharedDelete(&pThis->Signallers);
246#endif
247 RTMemFree(pThis);
248 return VINF_SUCCESS;
249}
250
251
252RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
253{
254 /*
255 * Validate input.
256 */
257 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
258 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
259 uint32_t u32 = pThis->u32State;
260 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
261
262#ifdef RTSEMEVENTMULTI_STRICT
263 if (pThis->fEverHadSignallers)
264 {
265 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
266 if (RT_FAILURE(rc9))
267 return rc9;
268 }
269#endif
270
271 /*
272 * Lock the mutex semaphore.
273 */
274 int rc = pthread_mutex_lock(&pThis->Mutex);
275 if (rc)
276 {
277 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventMultiSem, rc));
278 return RTErrConvertFromErrno(rc);
279 }
280
281 /*
282 * Check the state.
283 */
284 if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED)
285 {
286 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED);
287 rc = pthread_cond_broadcast(&pThis->Cond);
288 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventMultiSem, rc));
289 }
290 else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
291 {
292 rc = pthread_cond_broadcast(&pThis->Cond); /* give'm another kick... */
293 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventMultiSem, rc));
294 }
295 else
296 rc = VERR_SEM_DESTROYED;
297
298 /*
299 * Release the mutex and return.
300 */
301 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
302 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventMultiSem, rc));
303 if (rc)
304 return RTErrConvertFromErrno(rc);
305 if (rc2)
306 return RTErrConvertFromErrno(rc2);
307
308 return VINF_SUCCESS;
309}
310
311
312RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
313{
314 /*
315 * Validate input.
316 */
317 int rc = VINF_SUCCESS;
318 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
319 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
320 uint32_t u32 = pThis->u32State;
321 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
322
323 /*
324 * Lock the mutex semaphore.
325 */
326 int rcPosix = pthread_mutex_lock(&pThis->Mutex);
327 if (RT_UNLIKELY(rcPosix))
328 {
329 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix));
330 return RTErrConvertFromErrno(rcPosix);
331 }
332
333 /*
334 * Check the state.
335 */
336 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
337 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
338 else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED)
339 rc = VERR_SEM_DESTROYED;
340
341 /*
342 * Release the mutex and return.
343 */
344 rcPosix = pthread_mutex_unlock(&pThis->Mutex);
345 if (RT_UNLIKELY(rcPosix))
346 {
347 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix));
348 return RTErrConvertFromErrno(rcPosix);
349 }
350
351 return rc;
352}
353
354
355/**
356 * Handle polling (timeout already expired at the time of the call).
357 *
358 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
359 * @param pThis The semaphore.
360 */
361DECLINLINE(int) rtSemEventMultiPosixWaitPoll(struct RTSEMEVENTMULTIINTERNAL *pThis)
362{
363 int rc = pthread_mutex_lock(&pThis->Mutex);
364 AssertMsgReturn(!rc, ("Failed to lock event multi sem %p, rc=%d.\n", pThis, rc), RTErrConvertFromErrno(rc));
365
366 uint32_t const u32State = pThis->u32State;
367
368 rc = pthread_mutex_unlock(&pThis->Mutex);
369 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc)); NOREF(rc);
370
371 return u32State == EVENTMULTI_STATE_SIGNALED
372 ? VINF_SUCCESS
373 : u32State != EVENTMULTI_STATE_UNINITIALIZED
374 ? VERR_TIMEOUT
375 : VERR_SEM_DESTROYED;
376}
377
378
379
380/**
381 * Implements the indefinite wait.
382 *
383 * @returns See RTSemEventMultiWaitEx.
384 * @param pThis The semaphore.
385 * @param fFlags See RTSemEventMultiWaitEx.
386 * @param pSrcPos The source position, can be NULL.
387 */
388static int rtSemEventMultiPosixWaitIndefinite(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, PCRTLOCKVALSRCPOS pSrcPos)
389{
390 /* take mutex */
391 int rc = pthread_mutex_lock(&pThis->Mutex);
392 AssertMsgReturn(!rc, ("Failed to lock event multi sem %p, rc=%d.\n", pThis, rc), RTErrConvertFromErrno(rc));
393 ASMAtomicIncU32(&pThis->cWaiters);
394
395 for (;;)
396 {
397 /* check state. */
398 uint32_t const u32State = pThis->u32State;
399 if (u32State != EVENTMULTI_STATE_NOT_SIGNALED)
400 {
401 ASMAtomicDecU32(&pThis->cWaiters);
402 rc = pthread_mutex_unlock(&pThis->Mutex);
403 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc));
404 return u32State == EVENTMULTI_STATE_SIGNALED
405 ? VINF_SUCCESS
406 : VERR_SEM_DESTROYED;
407 }
408
409 /* wait */
410#ifdef RTSEMEVENTMULTI_STRICT
411 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
412 if (pThis->fEverHadSignallers)
413 {
414 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
415 RT_INDEFINITE_WAIT, RTTHREADSTATE_EVENT_MULTI, true);
416 if (RT_FAILURE(rc))
417 {
418 ASMAtomicDecU32(&pThis->cWaiters);
419 pthread_mutex_unlock(&pThis->Mutex);
420 return rc;
421 }
422 }
423#else
424 RTTHREAD hThreadSelf = RTThreadSelf();
425 RT_NOREF_PV(pSrcPos);
426#endif
427 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
428 /** @todo interruptible wait is not implementable... */ NOREF(fFlags);
429 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
430 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
431 if (RT_UNLIKELY(rc))
432 {
433 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", pThis, rc));
434 ASMAtomicDecU32(&pThis->cWaiters);
435 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
436 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2);
437 return RTErrConvertFromErrno(rc);
438 }
439 }
440}
441
442
443/**
444 * Implements the timed wait.
445 *
446 * @returns See RTSemEventMultiWaitEx
447 * @param pThis The semaphore.
448 * @param fFlags See RTSemEventMultiWaitEx.
449 * @param uTimeout See RTSemEventMultiWaitEx.
450 * @param pSrcPos The source position, can be NULL.
451 */
452static int rtSemEventMultiPosixWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
453 PCRTLOCKVALSRCPOS pSrcPos)
454{
455 /*
456 * Convert uTimeout to a relative value in nano seconds.
457 */
458 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
459 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
460 ? uTimeout * UINT32_C(1000000)
461 : UINT64_MAX;
462 if (uTimeout == UINT64_MAX) /* unofficial way of indicating an indefinite wait */
463 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
464
465 uint64_t uAbsTimeout = uTimeout;
466 if (fFlags & RTSEMWAIT_FLAGS_ABSOLUTE)
467 {
468 uint64_t u64Now = RTTimeSystemNanoTS();
469 uTimeout = uTimeout > u64Now ? uTimeout - u64Now : 0;
470 }
471
472 if (uTimeout == 0)
473 return rtSemEventMultiPosixWaitPoll(pThis);
474
475 /*
476 * Get current time and calc end of deadline relative to real time.
477 */
478 struct timespec ts = {0,0};
479 if (!pThis->fMonotonicClock)
480 {
481#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
482 struct timeval tv = {0,0};
483 gettimeofday(&tv, NULL);
484 ts.tv_sec = tv.tv_sec;
485 ts.tv_nsec = tv.tv_usec * 1000;
486#else
487 clock_gettime(CLOCK_REALTIME, &ts);
488#endif
489 struct timespec tsAdd;
490 tsAdd.tv_nsec = uTimeout % UINT32_C(1000000000);
491 tsAdd.tv_sec = uTimeout / UINT32_C(1000000000);
492 if ( sizeof(ts.tv_sec) < sizeof(uint64_t)
493 && ( uTimeout > UINT64_C(1000000000) * UINT32_MAX
494 || (uint64_t)ts.tv_sec + tsAdd.tv_sec >= UINT32_MAX) )
495 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
496
497 ts.tv_sec += tsAdd.tv_sec;
498 ts.tv_nsec += tsAdd.tv_nsec;
499 if (ts.tv_nsec >= 1000000000)
500 {
501 ts.tv_nsec -= 1000000000;
502 ts.tv_sec++;
503 }
504 /* Note! No need to complete uAbsTimeout for RTSEMWAIT_FLAGS_RELATIVE in this path. */
505 }
506 else
507 {
508 /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */
509 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
510 uAbsTimeout += RTTimeSystemNanoTS();
511 if ( sizeof(ts.tv_sec) < sizeof(uint64_t)
512 && uAbsTimeout > UINT64_C(1000000000) * UINT32_MAX)
513 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
514 ts.tv_nsec = uAbsTimeout % UINT32_C(1000000000);
515 ts.tv_sec = uAbsTimeout / UINT32_C(1000000000);
516 }
517
518 /*
519 * To business!
520 */
521 /* take mutex */
522 int rc = pthread_mutex_lock(&pThis->Mutex);
523 AssertMsgReturn(rc == 0, ("rc=%d pThis=%p\n", rc, pThis), RTErrConvertFromErrno(rc)); NOREF(rc);
524 ASMAtomicIncU32(&pThis->cWaiters);
525
526 for (;;)
527 {
528 /* check state. */
529 uint32_t const u32State = pThis->u32State;
530 if (u32State != EVENTMULTI_STATE_NOT_SIGNALED)
531 {
532 ASMAtomicDecU32(&pThis->cWaiters);
533 rc = pthread_mutex_unlock(&pThis->Mutex);
534 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc));
535 return u32State == EVENTMULTI_STATE_SIGNALED
536 ? VINF_SUCCESS
537 : VERR_SEM_DESTROYED;
538 }
539
540 /* wait */
541#ifdef RTSEMEVENTMULTI_STRICT
542 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
543 if (pThis->fEverHadSignallers)
544 {
545 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
546 uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
547 if (RT_FAILURE(rc))
548 {
549 ASMAtomicDecU32(&pThis->cWaiters);
550 pthread_mutex_unlock(&pThis->Mutex);
551 return rc;
552 }
553 }
554#else
555 RTTHREAD hThreadSelf = RTThreadSelf();
556#endif
557 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
558 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
559 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
560 if ( rc
561 && ( rc != EINTR /* according to SuS this function shall not return EINTR, but linux man page says differently. */
562 || (fFlags & RTSEMWAIT_FLAGS_NORESUME)) )
563 {
564 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", pThis, rc));
565 ASMAtomicDecU32(&pThis->cWaiters);
566 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
567 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", pThis, rc2)); NOREF(rc2);
568 return RTErrConvertFromErrno(rc);
569 }
570
571 /* check the absolute deadline. */
572 }
573}
574
575
576DECLINLINE(int) rtSemEventMultiPosixWait(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
577 PCRTLOCKVALSRCPOS pSrcPos)
578{
579 /*
580 * Validate input.
581 */
582 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
583 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
584 uint32_t u32 = pThis->u32State;
585 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
586 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
587
588 /*
589 * Optimize the case where the event is signalled.
590 */
591 if (ASMAtomicUoReadU32(&pThis->u32State) == EVENTMULTI_STATE_SIGNALED)
592 {
593 int rc = rtSemEventMultiPosixWaitPoll(pThis);
594 if (RT_LIKELY(rc != VERR_TIMEOUT))
595 return rc;
596 }
597
598 /*
599 * Indefinite or timed wait?
600 */
601 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
602 return rtSemEventMultiPosixWaitIndefinite(pThis, fFlags, pSrcPos);
603 return rtSemEventMultiPosixWaitTimed(pThis, fFlags, uTimeout, pSrcPos);
604}
605
606
607#undef RTSemEventMultiWaitEx
608RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
609{
610#ifndef RTSEMEVENT_STRICT
611 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, NULL);
612#else
613 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
614 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
615#endif
616}
617
618
619RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
620 RTHCUINTPTR uId, RT_SRC_POS_DECL)
621{
622 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
623 return rtSemEventMultiPosixWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
624}
625
626
627RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
628{
629#ifdef RTSEMEVENTMULTI_STRICT
630 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
631 AssertPtrReturnVoid(pThis);
632 uint32_t u32 = pThis->u32State;
633 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
634
635 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
636 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
637#else
638 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
639#endif
640}
641
642
643RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
644{
645#ifdef RTSEMEVENTMULTI_STRICT
646 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
647 AssertPtrReturnVoid(pThis);
648 uint32_t u32 = pThis->u32State;
649 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
650
651 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
652 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
653#else
654 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
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#else
669 RT_NOREF_PV(hEventMultiSem); RT_NOREF_PV(hThread);
670#endif
671}
672
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