VirtualBox

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

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

iprt/lockvalidation: give better names to anonymous locks

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.9 KB
Line 
1/* $Id: semeventmulti-linux.cpp 25831 2010-01-14 15:12:53Z 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) && !defined(IPRT_WITH_FUTEX_BASED_SEMS)
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 phEventMultiSem)
122{
123 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
124}
125
126
127RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
128 const char *pszNameFmt, ...)
129{
130 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
131
132 /*
133 * Allocate semaphore handle.
134 */
135 struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL));
136 if (pThis)
137 {
138 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
139 pThis->iState = 0;
140#ifdef RTSEMEVENTMULTI_STRICT
141 if (!pszNameFmt)
142 {
143 static uint32_t volatile s_iSemEventMultiAnon = 0;
144 RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
145 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
146 "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1);
147 }
148 else
149 {
150 va_list va;
151 va_start(va, pszNameFmt);
152 RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis,
153 true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL),
154 pszNameFmt, va);
155 va_end(va);
156 }
157 pThis->fEverHadSignallers = false;
158#endif
159
160 *phEventMultiSem = pThis;
161 return VINF_SUCCESS;
162 }
163 return VERR_NO_MEMORY;
164}
165
166
167RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
168{
169 /*
170 * Validate input.
171 */
172 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
173 if (pThis == NIL_RTSEMEVENTMULTI)
174 return VINF_SUCCESS;
175 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
176 AssertReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, VERR_INVALID_HANDLE);
177
178 /*
179 * Invalidate the semaphore and wake up anyone waiting on it.
180 */
181 ASMAtomicWriteSize(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC + 1);
182 if (ASMAtomicXchgS32(&pThis->iState, -1) == 1)
183 {
184 sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
185 usleep(1000);
186 }
187
188 /*
189 * Free the semaphore memory and be gone.
190 */
191#ifdef RTSEMEVENTMULTI_STRICT
192 RTLockValidatorRecSharedDelete(&pThis->Signallers);
193#endif
194 RTMemFree(pThis);
195 return VINF_SUCCESS;
196}
197
198
199RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
200{
201 /*
202 * Validate input.
203 */
204 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
205 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
206 VERR_INVALID_HANDLE);
207
208#ifdef RTSEMEVENTMULTI_STRICT
209 if (pThis->fEverHadSignallers)
210 {
211 int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD);
212 if (RT_FAILURE(rc9))
213 return rc9;
214 }
215#endif
216
217
218 /*
219 * Signal it.
220 */
221 int32_t iOld = ASMAtomicXchgS32(&pThis->iState, -1);
222 if (iOld > 0)
223 {
224 /* wake up sleeping threads. */
225 long cWoken = sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
226 AssertMsg(cWoken >= 0, ("%ld\n", cWoken)); NOREF(cWoken);
227 }
228 Assert(iOld == 0 || iOld == -1 || iOld == 1);
229 return VINF_SUCCESS;
230}
231
232
233RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
234{
235 /*
236 * Validate input.
237 */
238 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
239 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
240 VERR_INVALID_HANDLE);
241#ifdef RT_STRICT
242 int32_t i = pThis->iState;
243 Assert(i == 0 || i == -1 || i == 1);
244#endif
245
246 /*
247 * Reset it.
248 */
249 ASMAtomicCmpXchgS32(&pThis->iState, 0, -1);
250 return VINF_SUCCESS;
251}
252
253
254static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fAutoResume)
255{
256 PCRTLOCKVALSRCPOS pSrcPos = NULL;
257
258 /*
259 * Validate input.
260 */
261 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
262 AssertReturn(VALID_PTR(pThis) && pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
263 VERR_INVALID_HANDLE);
264
265 /*
266 * Quickly check whether it's signaled.
267 */
268 int32_t iCur = ASMAtomicUoReadS32(&pThis->iState);
269 Assert(iCur == 0 || iCur == -1 || iCur == 1);
270 if (iCur == -1)
271 return VINF_SUCCESS;
272
273 /*
274 * Convert the timeout value.
275 */
276 struct timespec ts;
277 struct timespec *pTimeout = NULL;
278 uint64_t u64End = 0; /* shut up gcc */
279 if (cMillies != RT_INDEFINITE_WAIT)
280 {
281 /* If the timeout is zero, then we're done. */
282 if (!cMillies)
283 return VERR_TIMEOUT;
284 ts.tv_sec = cMillies / 1000;
285 ts.tv_nsec = (cMillies % 1000) * UINT32_C(1000000);
286 u64End = RTTimeSystemNanoTS() + cMillies * UINT64_C(1000000);
287 pTimeout = &ts;
288 }
289
290 /*
291 * The wait loop.
292 */
293#ifdef RTSEMEVENTMULTI_STRICT
294 RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
295#else
296 RTTHREAD hThreadSelf = RTThreadSelf();
297#endif
298 for (unsigned i = 0;; i++)
299 {
300 /*
301 * Start waiting. We only account for there being or having been
302 * threads waiting on the semaphore to keep things simple.
303 */
304 iCur = ASMAtomicUoReadS32(&pThis->iState);
305 Assert(iCur == 0 || iCur == -1 || iCur == 1);
306 if ( iCur == 1
307 || ASMAtomicCmpXchgS32(&pThis->iState, 1, 0))
308 {
309 /* adjust the relative timeout */
310 if (pTimeout)
311 {
312 int64_t i64Diff = u64End - RTTimeSystemNanoTS();
313 if (i64Diff < 1000)
314 return VERR_TIMEOUT;
315 ts.tv_sec = (uint64_t)i64Diff / UINT32_C(1000000000);
316 ts.tv_nsec = (uint64_t)i64Diff % UINT32_C(1000000000);
317 }
318#ifdef RTSEMEVENTMULTI_STRICT
319 if (pThis->fEverHadSignallers)
320 {
321 int rc9 = RTLockValidatorRecSharedCheckBlocking(&pThis->Signallers, hThreadSelf, pSrcPos, false,
322 cMillies, RTTHREADSTATE_EVENT_MULTI, true);
323 if (RT_FAILURE(rc9))
324 return rc9;
325 }
326#endif
327 RTThreadBlocking(hThreadSelf, RTTHREADSTATE_EVENT_MULTI, true);
328 long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 1, pTimeout, NULL, 0);
329 RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_EVENT_MULTI);
330 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
331 return VERR_SEM_DESTROYED;
332 if (rc == 0)
333 return VINF_SUCCESS;
334
335 /*
336 * Act on the wakup code.
337 */
338 if (rc == -ETIMEDOUT)
339 {
340/** @todo something is broken here. shows up every now and again in the ata
341 * code. Should try to run the timeout against RTTimeMilliTS to
342 * check that it's doing the right thing... */
343 Assert(pTimeout);
344 return VERR_TIMEOUT;
345 }
346 if (rc == -EWOULDBLOCK)
347 /* retry, the value changed. */;
348 else if (rc == -EINTR)
349 {
350 if (!fAutoResume)
351 return VERR_INTERRUPTED;
352 }
353 else
354 {
355 /* this shouldn't happen! */
356 AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
357 return RTErrConvertFromErrno(rc);
358 }
359 }
360 else if (iCur == -1)
361 return VINF_SUCCESS;
362 }
363}
364
365
366RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
367{
368 int rc = rtSemEventMultiWait(hEventMultiSem, cMillies, true);
369 Assert(rc != VERR_INTERRUPTED);
370 return rc;
371}
372
373
374RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
375{
376 return rtSemEventMultiWait(hEventMultiSem, cMillies, false);
377}
378
379
380RTDECL(void) RTSemEventMultiSetSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
381{
382#ifdef RTSEMEVENTMULTI_STRICT
383 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
384 AssertPtrReturnVoid(pThis);
385 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
386
387 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
388 RTLockValidatorRecSharedResetOwner(&pThis->Signallers, hThread, NULL);
389#endif
390}
391
392
393RTDECL(void) RTSemEventMultiAddSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
394{
395#ifdef RTSEMEVENTMULTI_STRICT
396 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
397 AssertPtrReturnVoid(pThis);
398 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
399
400 ASMAtomicWriteBool(&pThis->fEverHadSignallers, true);
401 RTLockValidatorRecSharedAddOwner(&pThis->Signallers, hThread, NULL);
402#endif
403}
404
405
406RTDECL(void) RTSemEventMultiRemoveSignaller(RTSEMEVENTMULTI hEventMultiSem, RTTHREAD hThread)
407{
408#ifdef RTSEMEVENTMULTI_STRICT
409 struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem;
410 AssertPtrReturnVoid(pThis);
411 AssertReturnVoid(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
412
413 RTLockValidatorRecSharedRemoveOwner(&pThis->Signallers, hThread);
414#endif
415}
416
417#endif /* glibc < 2.6 || IPRT_WITH_FUTEX_BASED_SEMS */
418
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