VirtualBox

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

Last change on this file since 43363 was 43363, checked in by vboxsync, 12 years ago

Haiku Additions.

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