VirtualBox

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

Last change on this file since 14429 was 14429, checked in by vboxsync, 16 years ago

when building against glibc 2.6, use the Posix implementation of the event mutexes as the glibc futex bug is fixed there

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.1 KB
Line 
1/* $Id: semeventmulti-linux.cpp 14429 2008-11-20 17:23:43Z 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.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#include <features.h>
33#if __GLIBC_PREREQ(2,6)
34
35/* glibc 2.6 fixed a serious bug in the mutex implementation.
36 * The external refernce to epoll_pwait is a hack which prevents
37 * that we link against glibc < 2.6 */
38
39asm volatile (".global epoll_pwait");
40
41#include "r3/posix/semeventmulti-posix.cpp"
42
43#else /* glibc < 2.6 */
44
45/*******************************************************************************
46* Header Files *
47*******************************************************************************/
48#include <iprt/semaphore.h>
49#include <iprt/assert.h>
50#include <iprt/alloc.h>
51#include <iprt/asm.h>
52#include <iprt/err.h>
53#include "internal/magics.h"
54
55#include <errno.h>
56#include <limits.h>
57#include <pthread.h>
58#include <unistd.h>
59#include <sys/time.h>
60#include <sys/syscall.h>
61#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
62# include <linux/futex.h>
63#else
64# define FUTEX_WAIT 0
65# define FUTEX_WAKE 1
66#endif
67
68
69/*******************************************************************************
70* Structures and Typedefs *
71*******************************************************************************/
72/**
73 * Linux multiple wakup event semaphore.
74 */
75struct RTSEMEVENTMULTIINTERNAL
76{
77 /** Magic value. */
78 intptr_t volatile iMagic;
79 /** The futex state variable.
80 * -1 means signaled.
81 * 0 means not signaled, no waiters.
82 * >0 means not signaled, and the value gives the number of waiters.
83 */
84 int32_t volatile iState;
85};
86
87
88/**
89 * Wrapper for the futex syscall.
90 */
91static long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
92{
93 errno = 0;
94 long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
95 if (rc < 0)
96 {
97 Assert(rc == -1);
98 rc = -errno;
99 }
100 return rc;
101}
102
103
104RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
105{
106 /*
107 * Allocate semaphore handle.
108 */
109 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
110 if (pThis)
111 {
112 pThis->iMagic = RTSEMEVENTMULTI_MAGIC;
113 pThis->iState = 0;
114 *pEventMultiSem = pThis;
115 return VINF_SUCCESS;
116 }
117 return VERR_NO_MEMORY;
118}
119
120
121RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
122{
123 /*
124 * Validate input.
125 */
126 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
127 AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENTMULTI_MAGIC,
128 VERR_INVALID_HANDLE);
129
130 /*
131 * Invalidate the semaphore and wake up anyone waiting on it.
132 */
133 ASMAtomicWriteSize(&pThis->iMagic, RTSEMEVENTMULTI_MAGIC + 1);
134 if (ASMAtomicXchgS32(&pThis->iState, -1) == 1)
135 {
136 sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
137 usleep(1000);
138 }
139
140 /*
141 * Free the semaphore memory and be gone.
142 */
143 RTMemFree(pThis);
144 return VINF_SUCCESS;
145}
146
147
148RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
149{
150 /*
151 * Validate input.
152 */
153 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
154 AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENTMULTI_MAGIC,
155 VERR_INVALID_HANDLE);
156 /*
157 * Signal it.
158 */
159 int32_t iOld = ASMAtomicXchgS32(&pThis->iState, -1);
160 if (iOld > 0)
161 {
162 /* wake up sleeping threads. */
163 long cWoken = sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
164 AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
165 }
166 Assert(iOld == 0 || iOld == -1 || iOld == 1);
167 return VINF_SUCCESS;
168}
169
170
171RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
172{
173 /*
174 * Validate input.
175 */
176 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
177 AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENTMULTI_MAGIC,
178 VERR_INVALID_HANDLE);
179#ifdef RT_STRICT
180 int32_t i = pThis->iState;
181 Assert(i == 0 || i == -1 || i == 1);
182#endif
183
184 /*
185 * Reset it.
186 */
187 ASMAtomicCmpXchgS32(&pThis->iState, 0, -1);
188 return VINF_SUCCESS;
189}
190
191
192static int rtSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies, bool fAutoResume)
193{
194 /*
195 * Validate input.
196 */
197 struct RTSEMEVENTMULTIINTERNAL *pThis = EventMultiSem;
198 AssertReturn(VALID_PTR(pThis) && pThis->iMagic == RTSEMEVENTMULTI_MAGIC,
199 VERR_INVALID_HANDLE);
200
201 /*
202 * Quickly check whether it's signaled.
203 */
204 int32_t iCur = ASMAtomicUoReadS32(&pThis->iState);
205 Assert(iCur == 0 || iCur == -1 || iCur == 1);
206 if (iCur == -1)
207 return VINF_SUCCESS;
208 if (!cMillies)
209 return VERR_TIMEOUT;
210
211 /*
212 * Convert timeout value.
213 */
214 struct timespec ts;
215 struct timespec *pTimeout = NULL;
216 if (cMillies != RT_INDEFINITE_WAIT)
217 {
218 ts.tv_sec = cMillies / 1000;
219 ts.tv_nsec = (cMillies % 1000) * 1000000;
220 pTimeout = &ts;
221 }
222
223 /*
224 * The wait loop.
225 */
226 for (unsigned i = 0;; i++)
227 {
228 /*
229 * Start waiting. We only account for there being or having been
230 * threads waiting on the semaphore to keep things simple.
231 */
232 iCur = ASMAtomicUoReadS32(&pThis->iState);
233 Assert(iCur == 0 || iCur == -1 || iCur == 1);
234 if ( iCur == 1
235 || ASMAtomicCmpXchgS32(&pThis->iState, 1, 0))
236 {
237 long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
238 if (RT_UNLIKELY(pThis->iMagic != RTSEMEVENTMULTI_MAGIC))
239 return VERR_SEM_DESTROYED;
240 if (rc == 0)
241 return VINF_SUCCESS;
242
243 /*
244 * Act on the wakup code.
245 */
246 if (rc == -ETIMEDOUT)
247 {
248/** @something is broken here. shows up every now and again in the ata code. Should try to run the timeout against RTTimeMilliTS to check that it's doing the right thing... */
249 Assert(pTimeout);
250 return VERR_TIMEOUT;
251 }
252 if (rc == -EWOULDBLOCK)
253 /* retry, the value changed. */;
254 else if (rc == -EINTR)
255 {
256 if (!fAutoResume)
257 return VERR_INTERRUPTED;
258 }
259 else
260 {
261 /* this shouldn't happen! */
262 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
263 return RTErrConvertFromErrno(rc);
264 }
265 }
266 else if (iCur == -1)
267 return VINF_SUCCESS;
268 }
269}
270
271
272RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
273{
274 int rc = rtSemEventMultiWait(EventMultiSem, cMillies, true);
275 Assert(rc != VERR_INTERRUPTED);
276 return rc;
277}
278
279
280RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
281{
282 return rtSemEventMultiWait(EventMultiSem, cMillies, false);
283}
284
285#endif /* glibc < 2.6 */
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