VirtualBox

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

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

iprt,pdmcritsect: RTMSINTERVAL, RTLockValidatorClass* and some related renaming.

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