VirtualBox

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

Last change on this file since 59512 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: 18.5 KB
Line 
1/* $Id: semevent-posix.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - 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/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)
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 pthread_condattr_t CondAttr;
124 rc = pthread_condattr_init(&CondAttr);
125 if (!rc)
126 {
127 rc = pthread_cond_init(&pThis->Cond, &CondAttr);
128 if (!rc)
129 {
130 /*
131 * Create the semaphore.
132 */
133 pthread_mutexattr_t MutexAttr;
134 rc = pthread_mutexattr_init(&MutexAttr);
135 if (!rc)
136 {
137 rc = pthread_mutex_init(&pThis->Mutex, &MutexAttr);
138 if (!rc)
139 {
140 pthread_mutexattr_destroy(&MutexAttr);
141 pthread_condattr_destroy(&CondAttr);
142
143 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
144 ASMAtomicWriteU32(&pThis->cWaiters, 0);
145 pThis->fFlags = fFlags;
146#ifdef RTSEMEVENT_STRICT
147 if (!pszNameFmt)
148 {
149 static uint32_t volatile s_iSemEventAnon = 0;
150 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
151 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
152 "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1);
153 }
154 else
155 {
156 va_list va;
157 va_start(va, pszNameFmt);
158 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
159 true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL),
160 pszNameFmt, va);
161 va_end(va);
162 }
163 pThis->fEverHadSignallers = false;
164#endif
165
166 *phEventSem = pThis;
167 return VINF_SUCCESS;
168 }
169
170 pthread_mutexattr_destroy(&MutexAttr);
171 }
172 pthread_cond_destroy(&pThis->Cond);
173 }
174 pthread_condattr_destroy(&CondAttr);
175 }
176
177 rc = RTErrConvertFromErrno(rc);
178 if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
179 RTMemFree(pThis);
180 else
181 rtMemBaseFree(pThis);
182 }
183 else
184 rc = VERR_NO_MEMORY;
185
186 return rc;
187}
188
189
190RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
191{
192 /*
193 * Validate handle.
194 */
195 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
196 if (pThis == NIL_RTSEMEVENT)
197 return VINF_SUCCESS;
198 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
199 uint32_t u32 = pThis->u32State;
200 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
201
202 /*
203 * Abort all waiters forcing them to return failure.
204 */
205 int rc;
206 for (int i = 30; i > 0; i--)
207 {
208 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_UNINITIALIZED);
209 rc = pthread_cond_destroy(&pThis->Cond);
210 if (rc != EBUSY)
211 break;
212 pthread_cond_broadcast(&pThis->Cond);
213 usleep(1000);
214 }
215 if (rc)
216 {
217 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", pThis, rc));
218 return RTErrConvertFromErrno(rc);
219 }
220
221 /*
222 * Destroy the semaphore
223 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
224 */
225 for (int i = 30; i > 0; i--)
226 {
227 rc = pthread_mutex_destroy(&pThis->Mutex);
228 if (rc != EBUSY)
229 break;
230 usleep(1000);
231 }
232 if (rc)
233 {
234 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", pThis, rc));
235 return RTErrConvertFromErrno(rc);
236 }
237
238 /*
239 * Free the semaphore memory and be gone.
240 */
241#ifdef RTSEMEVENT_STRICT
242 RTLockValidatorRecSharedDelete(&pThis->Signallers);
243#endif
244 if (!(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK))
245 RTMemFree(pThis);
246 else
247 rtMemBaseFree(pThis);
248 return VINF_SUCCESS;
249}
250
251
252RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
253{
254 /*
255 * Validate input.
256 */
257 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
258 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
259 uint32_t u32 = pThis->u32State;
260 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
261
262#ifdef RTSEMEVENT_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", hEventSem, rc));
278 return RTErrConvertFromErrno(rc);
279 }
280
281 /*
282 * Check the state.
283 */
284 if (pThis->u32State == EVENT_STATE_NOT_SIGNALED)
285 {
286 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_SIGNALED);
287 rc = pthread_cond_signal(&pThis->Cond);
288 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventSem, rc));
289 }
290 else if (pThis->u32State == EVENT_STATE_SIGNALED)
291 {
292 rc = pthread_cond_signal(&pThis->Cond); /* give'm another kick... */
293 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventSem, 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", hEventSem, rc));
303 if (rc)
304 return RTErrConvertFromErrno(rc);
305 if (rc2)
306 return RTErrConvertFromErrno(rc2);
307
308 return VINF_SUCCESS;
309}
310
311
312DECL_FORCE_INLINE(int) rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fAutoResume)
313{
314#ifdef RTSEMEVENT_STRICT
315 PCRTLOCKVALSRCPOS pSrcPos = NULL;
316#endif
317
318 /*
319 * Validate input.
320 */
321 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
322 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
323 uint32_t u32 = pThis->u32State;
324 AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE);
325
326 /*
327 * Timed or indefinite wait?
328 */
329 if (cMillies == RT_INDEFINITE_WAIT)
330 {
331 /* for fairness, yield before going to sleep. */
332 if ( ASMAtomicIncU32(&pThis->cWaiters) > 1
333 && pThis->u32State == EVENT_STATE_SIGNALED)
334 pthread_yield();
335
336 /* take mutex */
337 int rc = pthread_mutex_lock(&pThis->Mutex);
338 if (rc)
339 {
340 ASMAtomicDecU32(&pThis->cWaiters);
341 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
342 return RTErrConvertFromErrno(rc);
343 }
344
345 for (;;)
346 {
347 /* check state. */
348 if (pThis->u32State == EVENT_STATE_SIGNALED)
349 {
350 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
351 ASMAtomicDecU32(&pThis->cWaiters);
352 rc = pthread_mutex_unlock(&pThis->Mutex);
353 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
354 return VINF_SUCCESS;
355 }
356 if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
357 {
358 rc = pthread_mutex_unlock(&pThis->Mutex);
359 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
360 return VERR_SEM_DESTROYED;
361 }
362
363 /* wait */
364#ifdef RTSEMEVENT_STRICT
365 RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
366 ? RTThreadSelfAutoAdopt()
367 : RTThreadSelf();
368 if (pThis->fEverHadSignallers)
369 {
370 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
371 cMillies, RTTHREADSTATE_EVENT, true);
372 if (RT_FAILURE(rc))
373 {
374 ASMAtomicDecU32(&pThis->cWaiters);
375 pthread_mutex_unlock(&pThis->Mutex);
376 return rc;
377 }
378 }
379#else
380 RTTHREAD hThreadSelf = RTThreadSelf();
381#endif
382 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
383 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
384 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
385 if (rc)
386 {
387 AssertMsgFailed(("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
388 ASMAtomicDecU32(&pThis->cWaiters);
389 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
390 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc2)); NOREF(rc2);
391 return RTErrConvertFromErrno(rc);
392 }
393 }
394 }
395 else
396 {
397 /*
398 * Get current time and calc end of wait time.
399 */
400 struct timespec ts = {0,0};
401#if defined(RT_OS_DARWIN) || defined(RT_OS_HAIKU)
402 struct timeval tv = {0,0};
403 gettimeofday(&tv, NULL);
404 ts.tv_sec = tv.tv_sec;
405 ts.tv_nsec = tv.tv_usec * 1000;
406#else
407 clock_gettime(CLOCK_REALTIME, &ts);
408#endif
409 if (cMillies != 0)
410 {
411 ts.tv_nsec += (cMillies % 1000) * 1000000;
412 ts.tv_sec += cMillies / 1000;
413 if (ts.tv_nsec >= 1000000000)
414 {
415 ts.tv_nsec -= 1000000000;
416 ts.tv_sec++;
417 }
418 }
419
420 /* for fairness, yield before going to sleep. */
421 if (ASMAtomicIncU32(&pThis->cWaiters) > 1 && cMillies)
422 pthread_yield();
423
424 /* take mutex */
425 int rc = pthread_mutex_lock(&pThis->Mutex);
426 if (rc)
427 {
428 ASMAtomicDecU32(&pThis->cWaiters);
429 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event sem %p, rc=%d.\n", hEventSem, rc));
430 return RTErrConvertFromErrno(rc);
431 }
432
433 for (;;)
434 {
435 /* check state. */
436 if (pThis->u32State == EVENT_STATE_SIGNALED)
437 {
438 ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED);
439 ASMAtomicDecU32(&pThis->cWaiters);
440 rc = pthread_mutex_unlock(&pThis->Mutex);
441 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
442 return VINF_SUCCESS;
443 }
444 if (pThis->u32State == EVENT_STATE_UNINITIALIZED)
445 {
446 rc = pthread_mutex_unlock(&pThis->Mutex);
447 AssertMsg(!rc, ("Failed to unlock event sem %p, rc=%d.\n", hEventSem, rc)); NOREF(rc);
448 return VERR_SEM_DESTROYED;
449 }
450
451 /* we're done if the timeout is 0. */
452 if (!cMillies)
453 {
454 ASMAtomicDecU32(&pThis->cWaiters);
455 rc = pthread_mutex_unlock(&pThis->Mutex);
456 return VERR_TIMEOUT;
457 }
458
459 /* wait */
460#ifdef RTSEMEVENT_STRICT
461 RTTHREAD hThreadSelf = !(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)
462 ? RTThreadSelfAutoAdopt()
463 : RTThreadSelf();
464 if (pThis->fEverHadSignallers)
465 {
466 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
467 cMillies, RTTHREADSTATE_EVENT, true);
468 if (RT_FAILURE(rc))
469 {
470 ASMAtomicDecU32(&pThis->cWaiters);
471 pthread_mutex_unlock(&pThis->Mutex);
472 return rc;
473 }
474 }
475#else
476 RTTHREAD hThreadSelf = RTThreadSelf();
477#endif
478 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT, true);
479 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
480 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT);
481 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
482 {
483 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event sem %p, rc=%d.\n", hEventSem, rc));
484 ASMAtomicDecU32(&pThis->cWaiters);
485 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
486 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc2=%d.\n", hEventSem, rc2)); NOREF(rc2);
487 return RTErrConvertFromErrno(rc);
488 }
489 } /* for (;;) */
490 }
491}
492
493
494RTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
495{
496 int rc = rtSemEventWait(hEventSem, cMillies, true);
497 Assert(rc != VERR_INTERRUPTED);
498 return rc;
499}
500
501
502RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
503{
504 return rtSemEventWait(hEventSem, cMillies, false);
505}
506
507
508RTDECL(void) RTSemEventSetSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
509{
510#ifdef RTSEMEVENT_STRICT
511 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
512 AssertPtrReturnVoid(pThis);
513 uint32_t u32 = pThis->u32State;
514 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
515
516 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
517 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
518#endif
519}
520
521
522RTDECL(void) RTSemEventAddSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
523{
524#ifdef RTSEMEVENT_STRICT
525 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
526 AssertPtrReturnVoid(pThis);
527 uint32_t u32 = pThis->u32State;
528 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
529
530 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
531 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
532#endif
533}
534
535
536RTDECL(void) RTSemEventRemoveSignaller(RTSEMEVENT hEventSem, RTTHREAD hThread)
537{
538#ifdef RTSEMEVENT_STRICT
539 struct RTSEMEVENTINTERNAL *pThis = hEventSem;
540 AssertPtrReturnVoid(pThis);
541 uint32_t u32 = pThis->u32State;
542 AssertReturnVoid(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED);
543
544 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
545#endif
546}
547
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