VirtualBox

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

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

iprt: Added RTSemEventMultiCreateEx and did some cleanups of the RTSemEventMultiDestroy behavior wrt NIL handles.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.4 KB
Line 
1/* $Id: semeventmulti-posix.cpp 25720 2010-01-11 13:57:09Z 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 va_list va;
133 va_start(va, pszNameFmt);
134 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
135 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
136 pszNameFmt, va);
137 va_end(va);
138 pThis->fEverHadSignallers = false;
139#endif
140
141 *phEventMultiSem = pThis;
142 return VINF_SUCCESS;
143 }
144
145 pthread_mutexattr_destroy(&MutexAttr);
146 }
147 pthread_cond_destroy(&pThis->Cond);
148 }
149 pthread_condattr_destroy(&CondAttr);
150 }
151
152 rc = RTErrConvertFromErrno(rc);
153 RTMemFree(pThis);
154 }
155 else
156 rc = VERR_NO_MEMORY;
157
158 return rc;
159
160}
161
162
163RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
164{
165 /*
166 * Validate handle.
167 */
168 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
169 if (pThis == NIL_RTSEMEVENTMULTI)
170 return VINF_SUCCESS;
171 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
172 uint32_t u32 = pThis->u32State;
173 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
174
175 /*
176 * Abort all waiters forcing them to return failure.
177 */
178 int rc;
179 for (int i = 30; i > 0; i--)
180 {
181 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED);
182 rc = pthread_cond_destroy(&pThis->Cond);
183 if (rc != EBUSY)
184 break;
185 pthread_cond_broadcast(&pThis->Cond);
186 usleep(1000);
187 }
188 if (rc)
189 {
190 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", hEventMultiSem, rc));
191 return RTErrConvertFromErrno(rc);
192 }
193
194 /*
195 * Destroy the semaphore
196 * If it's busy we'll wait a bit to give the threads a chance to be scheduled.
197 */
198 for (int i = 30; i > 0; i--)
199 {
200 rc = pthread_mutex_destroy(&pThis->Mutex);
201 if (rc != EBUSY)
202 break;
203 usleep(1000);
204 }
205 if (rc)
206 {
207 AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", hEventMultiSem, rc));
208 return RTErrConvertFromErrno(rc);
209 }
210
211 /*
212 * Free the semaphore memory and be gone.
213 */
214#ifdef RTSEMEVENTMULTI_STRICT
215 RTLockValidatorRecSharedDelete(&pThis->Signallers);
216#endif
217 RTMemFree(pThis);
218 return VINF_SUCCESS;
219}
220
221
222RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
223{
224 /*
225 * Validate input.
226 */
227 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
228 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
229 uint32_t u32 = pThis->u32State;
230 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
231
232#ifdef RTSEMEVENTMULTI_STRICT
233 if (pThis->fEverHadSignallers)
234 {
235 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
236 if (RT_FAILURE(rc9))
237 return rc9;
238 }
239#endif
240
241 /*
242 * Lock the mutex semaphore.
243 */
244 int rc = pthread_mutex_lock(&pThis->Mutex);
245 if (rc)
246 {
247 AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventMultiSem, rc));
248 return RTErrConvertFromErrno(rc);
249 }
250
251 /*
252 * Check the state.
253 */
254 if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED)
255 {
256 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED);
257 rc = pthread_cond_broadcast(&pThis->Cond);
258 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventMultiSem, rc));
259 }
260 else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
261 {
262 rc = pthread_cond_broadcast(&pThis->Cond); /* give'm another kick... */
263 AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventMultiSem, rc));
264 }
265 else
266 rc = VERR_SEM_DESTROYED;
267
268 /*
269 * Release the mutex and return.
270 */
271 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
272 AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventMultiSem, rc));
273 if (rc)
274 return RTErrConvertFromErrno(rc);
275 if (rc2)
276 return RTErrConvertFromErrno(rc2);
277
278 return VINF_SUCCESS;
279}
280
281
282RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
283{
284 /*
285 * Validate input.
286 */
287 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
288 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
289 uint32_t u32 = pThis->u32State;
290 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
291
292 /*
293 * Lock the mutex semaphore.
294 */
295 int rc = pthread_mutex_lock(&pThis->Mutex);
296 if (rc)
297 {
298 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
299 return RTErrConvertFromErrno(rc);
300 }
301
302 /*
303 * Check the state.
304 */
305 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
306 ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED);
307 else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED)
308 rc = VERR_SEM_DESTROYED;
309
310 /*
311 * Release the mutex and return.
312 */
313 rc = pthread_mutex_unlock(&pThis->Mutex);
314 if (rc)
315 {
316 AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
317 return RTErrConvertFromErrno(rc);
318 }
319
320 return VINF_SUCCESS;
321
322}
323
324
325static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies, bool fAutoResume)
326{
327 PCRTLOCKVALSRCPOS pSrcPos = NULL;
328
329 /*
330 * Validate input.
331 */
332 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
333 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
334 uint32_t u32 = pThis->u32State;
335 AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE);
336
337 /*
338 * Timed or indefinite wait?
339 */
340 if (cMillies == RT_INDEFINITE_WAIT)
341 {
342 /* take mutex */
343 int rc = pthread_mutex_lock(&pThis->Mutex);
344 if (rc)
345 {
346 AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
347 return RTErrConvertFromErrno(rc);
348 }
349 ASMAtomicIncU32(&pThis->cWaiters);
350
351 for (;;)
352 {
353 /* check state. */
354 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
355 {
356 ASMAtomicDecU32(&pThis->cWaiters);
357 rc = pthread_mutex_unlock(&pThis->Mutex);
358 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rc)); NOREF(rc);
359 return VINF_SUCCESS;
360 }
361 if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED)
362 {
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 VERR_SEM_DESTROYED;
366 }
367
368 /* wait */
369#ifdef RTSEMEVENTMULTI_STRICT
370 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
371 if (pThis->fEverHadSignallers)
372 {
373 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
374 cMillies, RTTHREADSTATE_EVENT_MULTI, true);
375 if (RT_FAILURE(rc))
376 {
377 ASMAtomicDecU32(&pThis->cWaiters);
378 pthread_mutex_unlock(&pThis->Mutex);
379 return rc;
380 }
381 }
382#else
383 RTTHREAD hThreadSelf = RTThreadSelf();
384#endif
385 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
386 rc = pthread_cond_wait(&pThis->Cond, &pThis->Mutex);
387 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
388 if (rc)
389 {
390 AssertMsgFailed(("Failed to wait on event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
391 ASMAtomicDecU32(&pThis->cWaiters);
392 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
393 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rc2)); NOREF(rc2);
394 return RTErrConvertFromErrno(rc);
395 }
396 }
397 }
398 else
399 {
400 /*
401 * Get current time and calc end of wait time.
402 */
403 /** @todo Something is braindead here. we're getting occational timeouts after no time has
404 * elapsed on linux 2.6.23. (ata code typically)
405 *
406 * The general problem here is that we're using the realtime clock, i.e. the wall clock
407 * that is subject to ntp updates and user alteration, so we will have to compenstate
408 * for this by using RTTimeMilliTS together with the clock_gettime()/gettimeofday() call.
409 * Joy, oh joy. */
410 struct timespec ts = {0,0};
411#ifdef RT_OS_DARWIN
412 struct timeval tv = {0,0};
413 gettimeofday(&tv, NULL);
414 ts.tv_sec = tv.tv_sec;
415 ts.tv_nsec = tv.tv_usec * 1000;
416#else
417 clock_gettime(CLOCK_REALTIME, &ts);
418#endif
419 if (cMillies != 0)
420 {
421 ts.tv_nsec += (cMillies % 1000) * 1000000;
422 ts.tv_sec += cMillies / 1000;
423 if (ts.tv_nsec >= 1000000000)
424 {
425 ts.tv_nsec -= 1000000000;
426 ts.tv_sec++;
427 }
428 }
429
430 /* take mutex */
431 int rc = pthread_mutex_lock(&pThis->Mutex);
432 if (rc)
433 {
434 AssertMsg(rc == ETIMEDOUT, ("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
435 return RTErrConvertFromErrno(rc);
436 }
437 ASMAtomicIncU32(&pThis->cWaiters);
438
439 for (;;)
440 {
441 /* check state. */
442 if (pThis->u32State == EVENTMULTI_STATE_SIGNALED)
443 {
444 ASMAtomicDecU32(&pThis->cWaiters);
445 rc = pthread_mutex_unlock(&pThis->Mutex);
446 AssertMsg(!rc, ("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rc)); NOREF(rc);
447 return VINF_SUCCESS;
448 }
449 if (pThis->u32State == EVENTMULTI_STATE_UNINITIALIZED)
450 {
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 VERR_SEM_DESTROYED;
454 }
455
456 /* we're done if the timeout is 0. */
457 if (!cMillies)
458 {
459 ASMAtomicDecU32(&pThis->cWaiters);
460 rc = pthread_mutex_unlock(&pThis->Mutex);
461 return VERR_TIMEOUT;
462 }
463
464 /* wait */
465#ifdef RTSEMEVENTMULTI_STRICT
466 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
467 if (pThis->fEverHadSignallers)
468 {
469 rc = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
470 cMillies, RTTHREADSTATE_EVENT_MULTI, true);
471 if (RT_FAILURE(rc))
472 {
473 ASMAtomicDecU32(&pThis->cWaiters);
474 pthread_mutex_unlock(&pThis->Mutex);
475 return rc;
476 }
477 }
478#else
479 RTTHREAD hThreadSelf = RTThreadSelf();
480#endif
481 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
482 rc = pthread_cond_timedwait(&pThis->Cond, &pThis->Mutex, &ts);
483 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
484 if (rc && (rc != EINTR || !fAutoResume)) /* according to SuS this function shall not return EINTR, but linux man page says differently. */
485 {
486 AssertMsg(rc == ETIMEDOUT, ("Failed to wait on event multi sem %p, rc=%d.\n", hEventMultiSem, rc));
487 ASMAtomicDecU32(&pThis->cWaiters);
488 int rc2 = pthread_mutex_unlock(&pThis->Mutex);
489 AssertMsg(!rc2, ("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rc2)); NOREF(rc2);
490 return RTErrConvertFromErrno(rc);
491 }
492 }
493 }
494}
495
496
497RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies)
498{
499 int rc = rtSemEventMultiWait(hEventMultiSem, cMillies, true);
500 Assert(rc != VERR_INTERRUPTED);
501 return rc;
502}
503
504
505RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, unsigned cMillies)
506{
507 return rtSemEventMultiWait(hEventMultiSem, cMillies, false);
508}
509
510
511RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
512{
513#ifdef RTSEMEVENTMULTI_STRICT
514 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
515 AssertPtrReturnVoid(pThis);
516 uint32_t u32 = pThis->u32State;
517 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
518
519 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
520 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
521#endif
522}
523
524
525RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
526{
527#ifdef RTSEMEVENTMULTI_STRICT
528 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
529 AssertPtrReturnVoid(pThis);
530 uint32_t u32 = pThis->u32State;
531 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
532
533 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
534 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
535#endif
536}
537
538
539RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
540{
541#ifdef RTSEMEVENTMULTI_STRICT
542 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
543 AssertPtrReturnVoid(pThis);
544 uint32_t u32 = pThis->u32State;
545 AssertReturnVoid(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED);
546
547 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
548#endif
549}
550
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette