VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp@ 95685

Last change on this file since 95685 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 20.2 KB
Line 
1/* $Id: semeventmulti-linux.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphore, Linux (2.6.x+).
4 */
5
6/*
7 * Copyright (C) 2006-2022 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#include <features.h>
29#if __GLIBC_PREREQ(2,6) && !defined(IPRT_WITH_FUTEX_BASED_SEMS)
30
31/*
32 * glibc 2.6 fixed a serious bug in the mutex implementation. We wrote this
33 * linux specific event semaphores code in order to work around the bug. As it
34 * turns out, this code seems to have an unresolved issue (@bugref{2599}), so we'll
35 * fall back on the pthread based implementation if glibc is known to contain
36 * the bug fix.
37 *
38 * The external reference to epoll_pwait is a hack which prevents that we link
39 * against glibc < 2.6.
40 */
41#include "../posix/semeventmulti-posix.cpp"
42__asm__ (".global epoll_pwait");
43
44#else /* glibc < 2.6 */
45
46
47/*********************************************************************************************************************************
48* Header Files *
49*********************************************************************************************************************************/
50#include <iprt/semaphore.h>
51#include "internal/iprt.h"
52
53#include <iprt/assert.h>
54#include <iprt/asm.h>
55#include <iprt/err.h>
56#include <iprt/lockvalidator.h>
57#include <iprt/mem.h>
58#include <iprt/time.h>
59#include "internal/magics.h"
60#include "internal/strict.h"
61
62
63#include <errno.h>
64#include <limits.h>
65#include <pthread.h>
66#include <unistd.h>
67#include <sys/time.h>
68#include <sys/syscall.h>
69
70#include "semwait-linux.h"
71
72
73/*********************************************************************************************************************************
74* Structures and Typedefs *
75*********************************************************************************************************************************/
76/**
77 * Linux multiple wakup event semaphore.
78 */
79struct RTSEMEVENTMULTIINTERNAL
80{
81 /** Magic value. */
82 uint32_t volatile u32Magic;
83 /** The futex state variable, see RTSEMEVENTMULTI_LNX_XXX. */
84 uint32_t volatile uState;
85#ifdef RT_STRICT
86 /** Increased on every signalling call. */
87 uint32_t volatile uSignalSerialNo;
88#endif
89#ifdef RTSEMEVENTMULTI_STRICT
90 /** Signallers. */
91 RTLOCKVALRECSHRD Signallers;
92 /** Indicates that lock validation should be performed. */
93 bool volatile fEverHadSignallers;
94#endif
95};
96
97
98/*********************************************************************************************************************************
99* Defined Constants And Macros *
100*********************************************************************************************************************************/
101/** @name RTSEMEVENTMULTI_LNX_XXX - state
102 * @{ */
103#define RTSEMEVENTMULTI_LNX_NOT_SIGNALED UINT32_C(0x00000000)
104#define RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS UINT32_C(0x00000001)
105#define RTSEMEVENTMULTI_LNX_SIGNALED UINT32_C(0x00000003)
106/** @} */
107
108#define ASSERT_VALID_STATE(a_uState) \
109 AssertMsg( (a_uState) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED \
110 || (a_uState) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS \
111 || (a_uState) == RTSEMEVENTMULTI_LNX_SIGNALED, \
112 (#a_uState "=%s\n", a_uState))
113
114
115/*********************************************************************************************************************************
116* Global Variables *
117*********************************************************************************************************************************/
118/** Whether we can use FUTEX_WAIT_BITSET. */
119static int volatile g_fCanUseWaitBitSet = -1;
120
121
122RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
123{
124 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
125}
126
127
128RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
129 const char *pszNameFmt, ...)
130{
131 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
132
133 /*
134 * Make sure we know whether FUTEX_WAIT_BITSET works.
135 */
136 rtSemLinuxCheckForFutexWaitBitSet(&g_fCanUseWaitBitSet);
137#if defined(DEBUG_bird) && !defined(IN_GUEST)
138 Assert(g_fCanUseWaitBitSet == true);
139#endif
140
141 /*
142 * Allocate semaphore handle.
143 */
144 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
145 if (pThis)
146 {
147 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
148 pThis->uState = RTSEMEVENTMULTI_LNX_NOT_SIGNALED;
149#ifdef RT_STRICT
150 pThis->uSignalSerialNo = 0;
151#endif
152#ifdef RTSEMEVENTMULTI_STRICT
153 if (!pszNameFmt)
154 {
155 static uint32_t volatile s_iSemEventMultiAnon = 0;
156 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
157 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
158 "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1);
159 }
160 else
161 {
162 va_list va;
163 va_start(va, pszNameFmt);
164 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
165 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
166 pszNameFmt, va);
167 va_end(va);
168 }
169 pThis->fEverHadSignallers = false;
170#else
171 RT_NOREF(hClass, pszNameFmt);
172#endif
173
174 *phEventMultiSem = pThis;
175 return VINF_SUCCESS;
176 }
177 return VERR_NO_MEMORY;
178}
179
180
181RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
182{
183 /*
184 * Validate input.
185 */
186 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
187 if (pThis == NIL_RTSEMEVENTMULTI)
188 return VINF_SUCCESS;
189 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
190 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
191
192 /*
193 * Invalidate the semaphore and wake up anyone waiting on it.
194 */
195 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC + 1);
196 if (ASMAtomicXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_SIGNALED) == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS)
197 {
198 sys_futex(&pThis->uState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
199 usleep(1000);
200 }
201
202 /*
203 * Free the semaphore memory and be gone.
204 */
205#ifdef RTSEMEVENTMULTI_STRICT
206 RTLockValidatorRecSharedDelete(&pThis->Signallers);
207#endif
208 RTMemFree(pThis);
209 return VINF_SUCCESS;
210}
211
212
213RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
214{
215 /*
216 * Validate input.
217 */
218 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
219 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
220 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
221
222#ifdef RTSEMEVENTMULTI_STRICT
223 if (pThis->fEverHadSignallers)
224 {
225 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
226 if (RT_FAILURE(rc9))
227 return rc9;
228 }
229#endif
230
231 /*
232 * Signal it.
233 */
234#ifdef RT_STRICT
235 ASMAtomicIncU32(&pThis->uSignalSerialNo);
236#endif
237 uint32_t uOld = ASMAtomicXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_SIGNALED);
238 if (uOld == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS)
239 {
240 /* wake up sleeping threads. */
241 long cWoken = sys_futex(&pThis->uState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
242 AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
243 }
244 ASSERT_VALID_STATE(uOld);
245 return VINF_SUCCESS;
246}
247
248
249RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
250{
251 /*
252 * Validate input.
253 */
254 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
255 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
256 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
257#ifdef RT_STRICT
258 uint32_t const uState = pThis->uState;
259 ASSERT_VALID_STATE(uState);
260#endif
261
262 /*
263 * Reset it.
264 */
265 ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED, RTSEMEVENTMULTI_LNX_SIGNALED);
266 return VINF_SUCCESS;
267}
268
269
270/**
271 * Performs an indefinite wait on the event.
272 */
273static int rtSemEventMultiLinuxWaitIndefinite(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, PCRTLOCKVALSRCPOS pSrcPos)
274{
275 RT_NOREF(pSrcPos);
276
277 /*
278 * Quickly check whether it's signaled.
279 */
280 uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
281 if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
282 return VINF_SUCCESS;
283 ASSERT_VALID_STATE(uState);
284
285 /*
286 * The wait loop.
287 */
288#ifdef RTSEMEVENTMULTI_STRICT
289 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
290#else
291 RTTHREAD hThreadSelf = RTThreadSelf();
292#endif
293 for (unsigned i = 0;; i++)
294 {
295 /*
296 * Start waiting. We only account for there being or having been
297 * threads waiting on the semaphore to keep things simple.
298 */
299 uState = ASMAtomicUoReadU32(&pThis->uState);
300 if ( uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS
301 || ( uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED
302 && ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS,
303 RTSEMEVENTMULTI_LNX_NOT_SIGNALED)))
304 {
305#ifdef RTSEMEVENTMULTI_STRICT
306 if (pThis->fEverHadSignallers)
307 {
308 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
309 RT_INDEFINITE_WAIT, RTTHREADSTATE_EVENT_MULTI, true);
310 if (RT_FAILURE(rc9))
311 return rc9;
312 }
313#endif
314#ifdef RT_STRICT
315 uint32_t const uPrevSignalSerialNo = ASMAtomicReadU32(&pThis->uSignalSerialNo);
316#endif
317 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
318 long rc = sys_futex(&pThis->uState, FUTEX_WAIT, 1, NULL /*pTimeout*/, NULL, 0);
319 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
320
321 /* Check that the structure is still alive before continuing. */
322 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
323 { /*likely*/ }
324 else
325 return VERR_SEM_DESTROYED;
326
327 /*
328 * Return if success.
329 */
330 if (rc == 0)
331 {
332 Assert(uPrevSignalSerialNo != ASMAtomicReadU32(&pThis->uSignalSerialNo));
333 return VINF_SUCCESS;
334 }
335
336 /*
337 * Act on the wakup code.
338 */
339 if (rc == -EWOULDBLOCK)
340 /* retry, the value changed. */;
341 else if (rc == -EINTR)
342 {
343 if (fFlags & RTSEMWAIT_FLAGS_NORESUME)
344 return VERR_INTERRUPTED;
345 }
346 else
347 {
348 /* this shouldn't happen! */
349 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
350 return RTErrConvertFromErrno(rc);
351 }
352 }
353 else if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
354 return VINF_SUCCESS;
355 else
356 ASSERT_VALID_STATE(uState);
357 }
358}
359
360
361/**
362 * Handle polling (timeout already expired at the time of the call).
363 *
364 * @returns VINF_SUCCESS, VERR_TIMEOUT, VERR_SEM_DESTROYED.
365 * @param pThis The semaphore.
366 */
367static int rtSemEventMultiLinuxWaitPoll(struct RTSEMEVENTMULTIINTERNAL *pThis)
368{
369 uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
370 if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
371 return VINF_SUCCESS;
372 return VERR_TIMEOUT;
373}
374
375
376/**
377 * Performs an indefinite wait on the event.
378 */
379static int rtSemEventMultiLinuxWaitTimed(struct RTSEMEVENTMULTIINTERNAL *pThis, uint32_t fFlags, uint64_t uTimeout,
380 PCRTLOCKVALSRCPOS pSrcPos)
381{
382 RT_NOREF(pSrcPos);
383
384 /*
385 * Quickly check whether it's signaled.
386 */
387 uint32_t uState = ASMAtomicUoReadU32(&pThis->uState);
388 if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
389 return VINF_SUCCESS;
390 ASSERT_VALID_STATE(uState);
391
392 /*
393 * Convert the timeout value.
394 */
395 struct timespec TsTimeout;
396 int iWaitOp;
397 uint32_t uWaitVal3;
398 uint64_t nsAbsTimeout = uTimeout; /* (older gcc maybe used uninitialized) */
399 uTimeout = rtSemLinuxCalcDeadline(fFlags, uTimeout, g_fCanUseWaitBitSet, &TsTimeout, &iWaitOp, &uWaitVal3, &nsAbsTimeout);
400 if (uTimeout == 0)
401 return rtSemEventMultiLinuxWaitPoll(pThis);
402 if (uTimeout == UINT64_MAX)
403 return rtSemEventMultiLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
404
405 /*
406 * The wait loop.
407 */
408#ifdef RTSEMEVENTMULTI_STRICT
409 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
410#else
411 RTTHREAD hThreadSelf = RTThreadSelf();
412#endif
413 for (unsigned i = 0;; i++)
414 {
415 /*
416 * Start waiting. We only account for there being or having been
417 * threads waiting on the semaphore to keep things simple.
418 */
419 uState = ASMAtomicUoReadU32(&pThis->uState);
420 if ( uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS
421 || ( uState == RTSEMEVENTMULTI_LNX_NOT_SIGNALED
422 && ASMAtomicCmpXchgU32(&pThis->uState, RTSEMEVENTMULTI_LNX_NOT_SIGNALED_WAITERS,
423 RTSEMEVENTMULTI_LNX_NOT_SIGNALED)))
424 {
425#ifdef RTSEMEVENTMULTI_STRICT
426 if (pThis->fEverHadSignallers)
427 {
428 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
429 uTimeout / UINT32_C(1000000), RTTHREADSTATE_EVENT_MULTI, true);
430 if (RT_FAILURE(rc9))
431 return rc9;
432 }
433#endif
434#ifdef RT_STRICT
435 uint32_t const uPrevSignalSerialNo = ASMAtomicReadU32(&pThis->uSignalSerialNo);
436#endif
437 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
438 long rc = sys_futex(&pThis->uState, iWaitOp, 1, &TsTimeout, NULL, uWaitVal3);
439 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
440
441 /* Check that the structure is still alive before continuing. */
442 if (RT_LIKELY(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC))
443 { /*likely*/ }
444 else
445 return VERR_SEM_DESTROYED;
446
447 /*
448 * Return if success.
449 */
450 if (rc == 0)
451 {
452 Assert(uPrevSignalSerialNo != ASMAtomicReadU32(&pThis->uSignalSerialNo));
453 return VINF_SUCCESS;
454 }
455
456 /*
457 * Act on the wakup code.
458 */
459 if (rc == -ETIMEDOUT)
460 {
461 /** @todo something is broken here. shows up every now and again in the ata
462 * code. Should try to run the timeout against RTTimeMilliTS to
463 * check that it's doing the right thing... */
464#ifdef RT_STRICT
465 uint64_t const uNow = RTTimeNanoTS();
466 AssertMsg(uNow >= nsAbsTimeout || nsAbsTimeout - uNow < RT_NS_1MS,
467 ("%#RX64 - %#RX64 => %#RX64 (%RI64)\n", nsAbsTimeout, uNow, nsAbsTimeout - uNow, nsAbsTimeout - uNow));
468#endif
469 return VERR_TIMEOUT;
470 }
471 if (rc == -EWOULDBLOCK)
472 {
473 /* retry, the value changed. */;
474 }
475 else if (rc == -EINTR)
476 {
477 if (fFlags & RTSEMWAIT_FLAGS_NORESUME)
478 return VERR_INTERRUPTED;
479 }
480 else
481 {
482 /* this shouldn't happen! */
483 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
484 return RTErrConvertFromErrno(rc);
485 }
486 }
487 else if (uState == RTSEMEVENTMULTI_LNX_SIGNALED)
488 return VINF_SUCCESS;
489 else
490 ASSERT_VALID_STATE(uState);
491
492 /* adjust the relative timeout if relative */
493 if (iWaitOp == FUTEX_WAIT)
494 {
495 int64_t i64Diff = nsAbsTimeout - RTTimeSystemNanoTS();
496 if (i64Diff < 1000)
497 return VERR_TIMEOUT;
498 TsTimeout.tv_sec = (uint64_t)i64Diff / RT_NS_1SEC;
499 TsTimeout.tv_nsec = (uint64_t)i64Diff % RT_NS_1SEC;
500 }
501 }
502}
503
504/**
505 * Internal wait worker function.
506 */
507DECLINLINE(int) rtSemEventLnxMultiWait(RTSEMEVENTMULTI hEventSem, uint32_t fFlags, uint64_t uTimeout, PCRTLOCKVALSRCPOS pSrcPos)
508{
509 /*
510 * Validate input.
511 */
512 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventSem;
513 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
514 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
515 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
516
517 /*
518 * Timed or indefinite wait?
519 */
520 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
521 return rtSemEventMultiLinuxWaitIndefinite(pThis, fFlags, pSrcPos);
522 return rtSemEventMultiLinuxWaitTimed(hEventSem, fFlags, uTimeout, pSrcPos);
523}
524
525
526#undef RTSemEventMultiWaitEx
527RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
528{
529#ifndef RTSEMEVENT_STRICT
530 return rtSemEventLnxMultiWait(hEventMultiSem, fFlags, uTimeout, NULL);
531#else
532 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
533 return rtSemEventLnxMultiWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
534#endif
535}
536
537
538RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
539 RTHCUINTPTR uId, RT_SRC_POS_DECL)
540{
541 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
542 return rtSemEventLnxMultiWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
543}
544
545
546RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
547{
548#ifdef RTSEMEVENTMULTI_STRICT
549 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
550 AssertPtrReturnVoid(pThis);
551 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
552
553 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
554 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
555#else
556 RT_NOREF(hEventMultiSem, hThread);
557#endif
558}
559
560
561RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
562{
563#ifdef RTSEMEVENTMULTI_STRICT
564 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
565 AssertPtrReturnVoid(pThis);
566 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
567
568 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
569 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
570#else
571 RT_NOREF(hEventMultiSem, hThread);
572#endif
573}
574
575
576RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
577{
578#ifdef RTSEMEVENTMULTI_STRICT
579 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
580 AssertPtrReturnVoid(pThis);
581 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
582
583 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
584#else
585 RT_NOREF(hEventMultiSem, hThread);
586#endif
587}
588
589#endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */
590
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