VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/semeventmulti-linux.cpp@ 25650

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

semeventmulti-linux.cpp: Fixed bug in rtSemEventMultiWait when calculating u64End where timeouts larger than 4294 ms would be truncated to 4294 ms or less.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.9 KB
Line 
1/* $Id: semeventmulti-linux.cpp 25649 2010-01-05 14:39:26Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphore, Linux (2.6.x+).
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.215389.xyz. 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#include <features.h>
33#if __GLIBC_PREREQ(2,6) && !defined(IPRT_WITH_FUTEX_BASED_SEMS) && !defined(DEBUG_bird)
34
35/*
36 * glibc 2.6 fixed a serious bug in the mutex implementation. We wrote this
37 * linux specific event semaphores code in order to work around the bug. As it
38 * turns out, this code seems to have an unresolved issue (#2599), so we'll
39 * fall back on the pthread based implementation if glibc is known to contain
40 * the bug fix.
41 *
42 * The external refernce to epoll_pwait is a hack which prevents that we link
43 * against glibc < 2.6.
44 */
45#include "../posix/semeventmulti-posix.cpp"
46asm volatile (".global epoll_pwait");
47
48#else /* glibc < 2.6 */
49
50/*******************************************************************************
51* Header Files *
52*******************************************************************************/
53#include <iprt/semaphore.h>
54#include "internal/iprt.h"
55
56#include <iprt/assert.h>
57#include <iprt/asm.h>
58#include <iprt/err.h>
59#include <iprt/lockvalidator.h>
60#include <iprt/mem.h>
61#include <iprt/time.h>
62#include "internal/magics.h"
63#include "internal/strict.h"
64
65
66#include <errno.h>
67#include <limits.h>
68#include <pthread.h>
69#include <unistd.h>
70#include <sys/time.h>
71#include <sys/syscall.h>
72#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
73# include <linux/futex.h>
74#else
75# define FUTEX_WAIT 0
76# define FUTEX_WAKE 1
77#endif
78
79
80/*******************************************************************************
81* Structures and Typedefs *
82*******************************************************************************/
83/**
84 * Linux multiple wakup event semaphore.
85 */
86struct RTSEMEVENTMULTIINTERNAL
87{
88 /** Magic value. */
89 uint32_t volatile u32Magic;
90 /** The futex state variable.
91 * -1 means signaled.
92 * 0 means not signaled, no waiters.
93 * 1 means not signaled and that someone is waiting.
94 */
95 int32_t volatile iState;
96#ifdef RTSEMEVENTMULTI_STRICT
97 /** Signallers. */
98 RTLOCKVALRECSHRD Signallers;
99 /** Indicates that lock validation should be performed. */
100 bool volatile fEverHadSignallers;
101#endif
102};
103
104
105/**
106 * Wrapper for the futex syscall.
107 */
108static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
109{
110 errno = 0;
111 long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
112 if (rc < 0)
113 {
114 Assert(rc == -1);
115 rc = -errno;
116 }
117 return rc;
118}
119
120
121RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
122{
123 /*
124 * Allocate semaphore handle.
125 */
126 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
127 if (pThis)
128 {
129 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
130 pThis->iState = 0;
131#ifdef RTSEMEVENTMULTI_STRICT
132 RTLockValidatorRecSharedInit(&pThis->Signallers,
133 NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_ANY,
134 "RTSemEventMulti", pThis, true /*fSignaller*/);
135 pThis->fEverHadSignallers = false;
136#endif
137 *pEventMultiSem = pThis;
138 return VINF_SUCCESS;
139 }
140 return VERR_NO_MEMORY;
141}
142
143
144RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
145{
146 /*
147 * Validate input.
148 */
149 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
150 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
151 VERR_INVALID_HANDLE);
152
153 /*
154 * Invalidate the semaphore and wake up anyone waiting on it.
155 */
156 ASMAtomicWriteSize(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC + 1);
157 if (ASMAtomicXchgS32(&pThis->iState, -1) == 1)
158 {
159 sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
160 usleep(1000);
161 }
162
163 /*
164 * Free the semaphore memory and be gone.
165 */
166#ifdef RTSEMEVENTMULTI_STRICT
167 RTLockValidatorRecSharedDelete(&pThis->Signallers);
168#endif
169 RTMemFree(pThis);
170 return VINF_SUCCESS;
171}
172
173
174RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
175{
176 /*
177 * Validate input.
178 */
179 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
180 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
181 VERR_INVALID_HANDLE);
182
183#ifdef RTSEMEVENTMULTI_STRICT
184 if (pThis->fEverHadSignallers)
185 {
186 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
187 if (RT_FAILURE(rc9))
188 return rc9;
189 }
190#endif
191
192
193 /*
194 * Signal it.
195 */
196 int32_t iOld = ASMAtomicXchgS32(&pThis->iState, -1);
197 if (iOld > 0)
198 {
199 /* wake up sleeping threads. */
200 long cWoken = sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
201 AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
202 }
203 Assert(iOld == 0 || iOld == -1 || iOld == 1);
204 return VINF_SUCCESS;
205}
206
207
208RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
209{
210 /*
211 * Validate input.
212 */
213 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
214 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
215 VERR_INVALID_HANDLE);
216#ifdef RT_STRICT
217 int32_t i = pThis->iState;
218 Assert(i == 0 || i == -1 || i == 1);
219#endif
220
221 /*
222 * Reset it.
223 */
224 ASMAtomicCmpXchgS32(&pThis->iState, 0, -1);
225 return VINF_SUCCESS;
226}
227
228
229static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
230{
231 PCRTLOCKVALSRCPOS pSrcPos = NULL;
232
233 /*
234 * Validate input.
235 */
236 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
237 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
238 VERR_INVALID_HANDLE);
239
240 /*
241 * Quickly check whether it's signaled.
242 */
243 int32_t iCur = ASMAtomicUoReadS32(&pThis->iState);
244 Assert(iCur == 0 || iCur == -1 || iCur == 1);
245 if (iCur == -1)
246 return VINF_SUCCESS;
247
248 /*
249 * Convert the timeout value.
250 */
251 struct timespec ts;
252 struct timespec *pTimeout = NULL;
253 uint64_t u64End = 0; /* shut up gcc */
254 if (cMillies != RT_INDEFINITE_WAIT)
255 {
256 /* If the timeout is zero, then we're done. */
257 if (!cMillies)
258 return VERR_TIMEOUT;
259 ts.tv_sec = cMillies / 1000;
260 ts.tv_nsec = (cMillies % 1000) * UINT32_C(1000000);
261 u64End = RTTimeSystemNanoTS() + cMillies * UINT64_C(1000000);
262 pTimeout = &ts;
263 }
264
265 /*
266 * The wait loop.
267 */
268#ifdef RTSEMEVENTMULTI_STRICT
269 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
270#else
271 RTTHREAD hThreadSelf = RTThreadSelf();
272#endif
273 for (unsigned i = 0;; i++)
274 {
275 /*
276 * Start waiting. We only account for there being or having been
277 * threads waiting on the semaphore to keep things simple.
278 */
279 iCur = ASMAtomicUoReadS32(&pThis->iState);
280 Assert(iCur == 0 || iCur == -1 || iCur == 1);
281 if ( iCur == 1
282 || ASMAtomicCmpXchgS32(&pThis->iState, 1, 0))
283 {
284 /* adjust the relative timeout */
285 if (pTimeout)
286 {
287 int64_t i64Diff = u64End - RTTimeSystemNanoTS();
288 if (i64Diff < 1000)
289 return VERR_TIMEOUT;
290 ts.tv_sec = (uint64_t)i64Diff / UINT32_C(1000000000);
291 ts.tv_nsec = (uint64_t)i64Diff % UINT32_C(1000000000);
292 }
293#ifdef RTSEMEVENTMULTI_STRICT
294 if (pThis->fEverHadSignallers)
295 {
296 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
297 RTTHREADSTATE_EVENT_MULTI, true);
298 if (RT_FAILURE(rc9))
299 return rc9;
300 }
301#endif
302 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
303 long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
304 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
305 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
306 return VERR_SEM_DESTROYED;
307 if (rc == 0)
308 return VINF_SUCCESS;
309
310 /*
311 * Act on the wakup code.
312 */
313 if (rc == -ETIMEDOUT)
314 {
315/** @todo something is broken here. shows up every now and again in the ata
316 * code. Should try to run the timeout against RTTimeMilliTS to
317 * check that it's doing the right thing... */
318 Assert(pTimeout);
319 return VERR_TIMEOUT;
320 }
321 if (rc == -EWOULDBLOCK)
322 /* retry, the value changed. */;
323 else if (rc == -EINTR)
324 {
325 if (!fAutoResume)
326 return VERR_INTERRUPTED;
327 }
328 else
329 {
330 /* this shouldn't happen! */
331 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
332 return RTErrConvertFromErrno(rc);
333 }
334 }
335 else if (iCur == -1)
336 return VINF_SUCCESS;
337 }
338}
339
340
341RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
342{
343 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
344 Assert(rc != VERR_INTERRUPTED);
345 return rc;
346}
347
348
349RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
350{
351 return rtSemEventMultiWait(EventMultiSem, cMillies, false);
352}
353
354
355RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
356{
357#ifdef RTSEMEVENTMULTI_STRICT
358 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
359 AssertPtrReturnVoid(pThis);
360 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
361
362 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
363 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
364#endif
365}
366
367
368RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
369{
370#ifdef RTSEMEVENTMULTI_STRICT
371 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
372 AssertPtrReturnVoid(pThis);
373 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
374
375 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
376 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
377#endif
378}
379
380
381RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
382{
383#ifdef RTSEMEVENTMULTI_STRICT
384 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
385 AssertPtrReturnVoid(pThis);
386 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
387
388 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
389#endif
390}
391
392#endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */
393
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