VirtualBox

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

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

fixed small memory leaks on certain hosts (Solaris) when using pthread_*attr functions

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