VirtualBox

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

Last change on this file since 25831 was 25831, checked in by vboxsync, 15 years ago

iprt/lockvalidation: give better names to anonymous locks

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