VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/semeventmulti-posix.cpp@ 28800

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