VirtualBox

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

Last change on this file since 31453 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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