VirtualBox

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