VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semevent-posix.cpp@ 76553

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 18.1 KB
Line 
1/* $Id: semevent-posix.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - Event Semaphore, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/mem.h>
38#include <iprt/lockvalidator.h>
39
40#include "internal/mem.h"
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#ifdef RT_OS_DARWIN
49# define pthread_yield() pthread_yield_np()
50#endif
51
52#if defined(RT_OS_SOLARIS) || defined(RT_OS_HAIKU) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD)
53# include <sched.h>
54# define pthread_yield() sched_yield()
55#endif
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61
62/** Internal representation of the POSIX implementation of an Event semaphore.
63 * The POSIX implementation uses a mutex and a condition variable to implement
64 * the automatic reset event semaphore semantics.
65 */
66struct RTSEMEVENTINTERNAL
67{
68 /** pthread condition. */
69 pthread_cond_t Cond;
70 /** pthread mutex which protects the condition and the event state. */
71 pthread_mutex_t Mutex;
72 /** The state of the semaphore.
73 * This is operated while owning mutex and using atomic updating. */
74 volatile uint32_t u32State;
75 /** Number of waiters. */
76 volatile uint32_t cWaiters;
77#ifdef RTSEMEVENT_STRICT
78 /** Signallers. */
79 RTLOCKVALRECSHRD Signallers;
80 /** Indicates that lock validation should be performed. */
81 bool volatile fEverHadSignallers;
82#endif
83 /** The creation flags. */
84 uint32_t fFlags;
85};
86
87/** The values of the u32State variable in a RTSEMEVENTINTERNAL.
88 * @{ */
89/** The object isn't initialized. */
90#define EVENT_STATE_UNINITIALIZED 0
91/** The semaphore is signaled. */
92#define EVENT_STATE_SIGNALED 0xff00ff00
93/** The semaphore is not signaled. */
94#define EVENT_STATE_NOT_SIGNALED 0x00ff00ff
95/** @} */
96
97
98RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
99{
100 return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
101}
102
103
104RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
105{
106 AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
107 Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
108
109 /*
110 * Allocate semaphore handle.
111 */
112 int rc;
113 struct RTSEMEVENTINTERNAL *pThis;
114 if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
115 pThis = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(*pThis));
116 else
117 pThis = (struct RTSEMEVENTINTERNAL *)rtMemBaseAlloc(sizeof(*pThis));
118 if (pThis)
119 {
120 /*
121 * Create the condition variable.
122 */
123 rc = pthread_cond_init(&pThis->Cond, NULL);
124 if (!rc)
125 {
126 /*
127 * Create the semaphore.
128 */
129 rc = pthread_mutex_init(&pThis->Mutex, NULL);
130 if (!rc)
131 {
132 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
133 ASMAtomicWriteU32(&pThis->cWaiters, 0);
134 pThis->fFlags = fFlags;
135#ifdef RTSEMEVENT_STRICT
136 if (!pszNameFmt)
137 {
138 static uint32_t volatile s_iSemEventAnon = 0;
139 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
140 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
141 "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
142 }
143 else
144 {
145 va_list va;
146 va_start(va, pszNameFmt);
147 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
148 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
149 pszNameFmt, va);
150 va_end(va);
151 }
152 pThis->fEverHadSignallers = false;
153#else
154 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
155#endif
156
157 *phEventSem = pThis;
158 return VINF_SUCCESS;
159 }
160 pthread_cond_destroy(&pThis->Cond);
161 }
162
163 rc = RTErrConvertFromErrno(rc);
164 if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
165 RTMemFree(pThis);
166 else
167 rtMemBaseFree(pThis);
168 }
169 else
170 rc = VERR_NO_MEMORY;
171
172 return rc;
173}
174
175
176RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
177{
178 /*
179 * Validate handle.
180 */
181 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
182 if (pThis == NIL_RTSEMEVENT)
183 return VINF_SUCCESS;
184 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
185 uint32_t u32 = pThis->u32State;
186 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
187
188 /*
189 * Abort all waiters forcing them to return failure.
190 */
191 int rc;
192 for (int i = 30; i > 0; i--)
193 {
194 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_UNINITIALIZED);
195 rc = pthread_cond_destroy(&pThis->Cond);
196 if (rc != EBUSY)
197 break;
198 pthread_cond_broadcast(&pThis->Cond);
199 usleep(1000);
200 }
201 if (rc)
202 {
203 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", pThis, rc));
204 return RTErrConvertFromErrno(rc);
205 }
206
207 /*
208 * Destroy the semaphore
209 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
210 */
211 for (int i = 30; i > 0; i--)
212 {
213 rc = pthread_mutex_destroy(&pThis->Mutex);
214 if (rc != EBUSY)
215 break;
216 usleep(1000);
217 }
218 if (rc)
219 {
220 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", pThis, rc));
221 return RTErrConvertFromErrno(rc);
222 }
223
224 /*
225 * Free the semaphore memory and be gone.
226 */
227#ifdef RTSEMEVENT_STRICT
228 RTLockValidatorRecSharedDelete(&pThis->Signallers);
229#endif
230 if (!(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
231 RTMemFree(pThis);
232 else
233 rtMemBaseFree(pThis);
234 return VINF_SUCCESS;
235}
236
237
238RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
239{
240 /*
241 * Validate input.
242 */
243 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
244 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
245 uint32_t u32 = pThis->u32State;
246 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
247
248#ifdef RTSEMEVENT_STRICT
249 if (pThis->fEverHadSignallers)
250 {
251 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
252 if (RT_FAILURE(rc9))
253 return rc9;
254 }
255#endif
256
257 /*
258 * Lock the mutex semaphore.
259 */
260 int rc = pthread_mutex_lock(&pThis->Mutex);
261 if (rc)
262 {
263 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
264 return RTErrConvertFromErrno(rc);
265 }
266
267 /*
268 * Check the state.
269 */
270 if (pThis->u32State == EVENT_STATE_NOT_SIGNALED)
271 {
272 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_SIGNALED);
273 rc = pthread_cond_signal(&pThis->Cond);
274 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventSem, rc));
275 }
276 else if (pThis->u32State == EVENT_STATE_SIGNALED)
277 {
278 rc = pthread_cond_signal(&pThis->Cond); /* give'm another kick... */
279 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventSem, rc));
280 }
281 else
282 rc = VERR_SEM_DESTROYED;
283
284 /*
285 * Release the mutex and return.
286 */
287 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
288 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc));
289 if (rc)
290 return RTErrConvertFromErrno(rc);
291 if (rc2)
292 return RTErrConvertFromErrno(rc2);
293
294 return VINF_SUCCESS;
295}
296
297
298DECL_FORCE_INLINE(int) rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fAutoResume)
299{
300#ifdef RTSEMEVENT_STRICT
301 PCRTLOCKVALSRCPOS pSrcPos = NULL;
302#endif
303
304 /*
305 * Validate input.
306 */
307 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
308 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
309 uint32_t u32 = pThis->u32State;
310 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
311
312 /*
313 * Timed or indefinite wait?
314 */
315 if (cMillies == RT_INDEFINITE_WAIT)
316 {
317 /* for fairness, yield before going to sleep. */
318 if ( ASMAtomicIncU32(&pThis->cWaiters) > 1
319 && pThis->u32State == EVENT_STATE_SIGNALED)
320 pthread_yield();
321
322 /* take mutex */
323 int rc = pthread_mutex_lock(&pThis->Mutex);
324 if (rc)
325 {
326 ASMAtomicDecU32(&pThis->cWaiters);
327 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
328 return RTErrConvertFromErrno(rc);
329 }
330
331 for (;;)
332 {
333 /* check state. */
334 if (pThis->u32State == EVENT_STATE_SIGNALED)
335 {
336 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
337 ASMAtomicDecU32(&pThis->cWaiters);
338 rc = pthread_mutex_unlock(&pThis->Mutex);
339 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
340 return VINF_SUCCESS;
341 }
342 if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
343 {
344 rc = pthread_mutex_unlock(&pThis->Mutex);
345 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
346 return VERR_SEM_DESTROYED;
347 }
348
349 /* wait */
350#ifdef RTSEMEVENT_STRICT
351 RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
352 ? RTThreadSelfAutoAdopt()
353 : RTThreadSelf();
354 if (pThis->fEverHadSignallers)
355 {
356 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
357 cMillies, RTTHREADSTATE_EVENT, true);
358 if (RT_FAILURE(rc))
359 {
360 ASMAtomicDecU32(&pThis->cWaiters);
361 pthread_mutex_unlock(&pThis->Mutex);
362 return rc;
363 }
364 }
365#else
366 RTTHREAD hThreadSelf = RTThreadSelf();
367#endif
368 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
369 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
370 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
371 if (rc)
372 {
373 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
374 ASMAtomicDecU32(&pThis->cWaiters);
375 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
376 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc2)); NOREF(rc2);
377 return RTErrConvertFromErrno(rc);
378 }
379 }
380 }
381 else
382 {
383 /*
384 * Get current time and calc end of wait time.
385 */
386 struct timespec ts = {0,0};
387#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
388 struct timeval tv = {0,0};
389 gettimeofday(&tv, NULL);
390 ts.tv_sec = tv.tv_sec;
391 ts.tv_nsec = tv.tv_usec * 1000;
392#else
393 clock_gettime(CLOCK_REALTIME, &ts);
394#endif
395 if (cMillies != 0)
396 {
397 ts.tv_nsec += (cMillies % 1000) * 1000000;
398 ts.tv_sec += cMillies / 1000;
399 if (ts.tv_nsec >= 1000000000)
400 {
401 ts.tv_nsec -= 1000000000;
402 ts.tv_sec++;
403 }
404 }
405
406 /* for fairness, yield before going to sleep. */
407 if (ASMAtomicIncU32(&pThis->cWaiters) > 1 && cMillies)
408 pthread_yield();
409
410 /* take mutex */
411 int rc = pthread_mutex_lock(&pThis->Mutex);
412 if (rc)
413 {
414 ASMAtomicDecU32(&pThis->cWaiters);
415 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
416 return RTErrConvertFromErrno(rc);
417 }
418
419 for (;;)
420 {
421 /* check state. */
422 if (pThis->u32State == EVENT_STATE_SIGNALED)
423 {
424 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
425 ASMAtomicDecU32(&pThis->cWaiters);
426 rc = pthread_mutex_unlock(&pThis->Mutex);
427 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
428 return VINF_SUCCESS;
429 }
430 if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
431 {
432 rc = pthread_mutex_unlock(&pThis->Mutex);
433 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
434 return VERR_SEM_DESTROYED;
435 }
436
437 /* we're done if the timeout is 0. */
438 if (!cMillies)
439 {
440 ASMAtomicDecU32(&pThis->cWaiters);
441 rc = pthread_mutex_unlock(&pThis->Mutex);
442 return VERR_TIMEOUT;
443 }
444
445 /* wait */
446#ifdef RTSEMEVENT_STRICT
447 RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
448 ? RTThreadSelfAutoAdopt()
449 : RTThreadSelf();
450 if (pThis->fEverHadSignallers)
451 {
452 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
453 cMillies, RTTHREADSTATE_EVENT, true);
454 if (RT_FAILURE(rc))
455 {
456 ASMAtomicDecU32(&pThis->cWaiters);
457 pthread_mutex_unlock(&pThis->Mutex);
458 return rc;
459 }
460 }
461#else
462 RTTHREAD hThreadSelf = RTThreadSelf();
463#endif
464 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
465 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
466 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
467 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
468 {
469 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
470 ASMAtomicDecU32(&pThis->cWaiters);
471 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
472 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", hEventSem, rc2)); NOREF(rc2);
473 return RTErrConvertFromErrno(rc);
474 }
475 } /* for (;;) */
476 }
477}
478
479
480RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
481{
482 int rc = rtSemEventWait(hEventSem, cMillies, true);
483 Assert(rc != VERR_INTERRUPTED);
484 return rc;
485}
486
487
488RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
489{
490 return rtSemEventWait(hEventSem, cMillies, false);
491}
492
493
494RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
495{
496#ifdef RTSEMEVENT_STRICT
497 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
498 AssertPtrReturnVoid(pThis);
499 uint32_t u32 = pThis->u32State;
500 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
501
502 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
503 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
504#else
505 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
506#endif
507}
508
509
510RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
511{
512#ifdef RTSEMEVENT_STRICT
513 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
514 AssertPtrReturnVoid(pThis);
515 uint32_t u32 = pThis->u32State;
516 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
517
518 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
519 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
520#else
521 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
522#endif
523}
524
525
526RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
527{
528#ifdef RTSEMEVENT_STRICT
529 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
530 AssertPtrReturnVoid(pThis);
531 uint32_t u32 = pThis->u32State;
532 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
533
534 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
535#else
536 RT_NOREF_PV(hEventSem); RT_NOREF_PV(hThread);
537#endif
538}
539
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use