VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/semwait-linux.h@ 95685

Last change on this file since 95685 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.4 KB
Line 
1/* $Id: semwait-linux.h 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Common semaphore wait code, Linux.
4 */
5
6/*
7 * Copyright (C) 2021-2022 Oracle Corporation
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
27#ifndef IPRT_INCLUDED_SRC_r3_linux_semwait_linux_h
28#define IPRT_INCLUDED_SRC_r3_linux_semwait_linux_h
29#ifndef RT_WITHOUT_PRAGMA_ONCE
30# pragma once
31#endif
32
33
34/* With 2.6.17 futex.h has become C++ unfriendly, so define the bits we need. */
35#define FUTEX_WAIT 0
36#define FUTEX_WAKE 1
37#define FUTEX_WAIT_BITSET 9 /**< @since 2.6.25 - uses absolute timeout. */
38
39
40/**
41 * Wrapper for the futex syscall.
42 */
43DECLINLINE(long) sys_futex(uint32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
44{
45 errno = 0;
46 long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
47 if (rc < 0)
48 {
49 Assert(rc == -1);
50 rc = -errno;
51 }
52 return rc;
53}
54
55
56DECL_NO_INLINE(static, void) rtSemLinuxCheckForFutexWaitBitSetSlow(int volatile *pfCanUseWaitBitSet)
57{
58 uint32_t uTestVar = UINT32_MAX;
59 long rc = sys_futex(&uTestVar, FUTEX_WAIT_BITSET, UINT32_C(0xf0f0f0f0), NULL, NULL, UINT32_MAX);
60 *pfCanUseWaitBitSet = rc == -EAGAIN;
61 AssertMsg(rc == -ENOSYS || rc == -EAGAIN, ("%d\n", rc));
62}
63
64
65DECLINLINE(void) rtSemLinuxCheckForFutexWaitBitSet(int volatile *pfCanUseWaitBitSet)
66{
67 if (*pfCanUseWaitBitSet != -1)
68 { /* likely */ }
69 else
70 rtSemLinuxCheckForFutexWaitBitSetSlow(pfCanUseWaitBitSet);
71}
72
73
74/**
75 * Converts a extended wait timeout specification to an timespec and
76 * corresponding futex operation, as well as an approximate relative nanosecond
77 * interval.
78 *
79 * @note This does not check for RTSEMWAIT_FLAGS_INDEFINITE, caller should've
80 * done that already.
81 *
82 * @returns The relative wait in nanoseconds. 0 for a poll call, UINT64_MAX for
83 * an effectively indefinite wait.
84 * @param fFlags RTSEMWAIT_FLAGS_XXX.
85 * @param fCanUseWaitBitSet Whether we can use FUTEX_WAIT_BITMSET or not.
86 * @param uTimeout The timeout.
87 * @param pDeadline Where to return the deadline.
88 * @param piWaitOp Where to return the FUTEX wait operation number.
89 * @param puWaitVal3 Where to return the FUTEX wait value 3.
90 * @param pnsAbsTimeout Where to return the absolute timeout in case of
91 * a resuming relative call (i.e. FUTEX_WAIT).
92 */
93DECL_FORCE_INLINE(uint64_t)
94rtSemLinuxCalcDeadline(uint32_t fFlags, uint64_t uTimeout, int fCanUseWaitBitSet,
95 struct timespec *pDeadline, int *piWaitOp, uint32_t *puWaitVal3, uint64_t *pnsAbsTimeout)
96{
97 Assert(!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE));
98
99 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
100 {
101 Assert(!(fFlags & RTSEMWAIT_FLAGS_ABSOLUTE));
102
103 /*
104 * Polling call?
105 */
106 if (uTimeout == 0)
107 return 0;
108
109 /*
110 * We use FUTEX_WAIT here as it takes a relative timespec.
111 *
112 * Note! For non-resuming waits, we can skip calculating the absolute
113 * time ASSUMING it is only needed for timeout adjustments
114 * after an -EINTR return.
115 */
116 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
117 {
118 if ( sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
119 || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
120 {
121 pDeadline->tv_sec = uTimeout / RT_MS_1SEC;
122 pDeadline->tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
123 uTimeout *= RT_NS_1MS;
124 }
125 else
126 return UINT64_MAX;
127 }
128 else
129 {
130 Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
131 if ( sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
132 || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
133 {
134 pDeadline->tv_sec = uTimeout / RT_NS_1SEC;
135 pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
136 }
137 else
138 return UINT64_MAX;
139 }
140
141#ifdef RT_STRICT
142 if (!(fFlags & RTSEMWAIT_FLAGS_RESUME))
143 *pnsAbsTimeout = uTimeout;
144 else
145#endif
146 *pnsAbsTimeout = RTTimeNanoTS() + uTimeout; /* Note! only relevant for relative waits (FUTEX_WAIT). */
147 }
148 else
149 {
150 /* Absolute deadline: */
151 Assert(fFlags & RTSEMWAIT_FLAGS_ABSOLUTE);
152 if (fCanUseWaitBitSet == true)
153 {
154 /*
155 * Use FUTEX_WAIT_BITSET as it takes an absolute deadline.
156 */
157 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
158 {
159 if ( sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
160 || uTimeout < (uint64_t)UINT32_MAX * RT_MS_1SEC)
161 {
162 pDeadline->tv_sec = uTimeout / RT_MS_1SEC;
163 pDeadline->tv_nsec = (uTimeout % RT_MS_1SEC) & RT_NS_1MS;
164 }
165 else
166 return UINT64_MAX;
167 }
168 else
169 {
170 Assert(fFlags & RTSEMWAIT_FLAGS_NANOSECS);
171 if ( sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
172 || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
173 {
174 pDeadline->tv_sec = uTimeout / RT_NS_1SEC;
175 pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
176 }
177 else
178 return UINT64_MAX;
179 }
180 *pnsAbsTimeout = uTimeout;
181 *piWaitOp = FUTEX_WAIT_BITSET;
182 *puWaitVal3 = UINT32_MAX;
183 return RT_MS_1SEC; /* Whatever non-zero; Whole point is not calling RTTimeNanoTS() in this path. */
184 }
185
186 /*
187 * FUTEX_WAIT_BITSET is not available, so use FUTEX_WAIT with a
188 * relative timeout.
189 */
190 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
191 {
192 if (uTimeout < UINT64_MAX / RT_NS_1MS)
193 uTimeout *= RT_NS_1MS;
194 else
195 return UINT64_MAX;
196 }
197
198 uint64_t const u64Now = RTTimeNanoTS();
199 if (u64Now < uTimeout)
200 {
201 *pnsAbsTimeout = uTimeout;
202 uTimeout -= u64Now;
203 }
204 else
205 return 0;
206
207 if ( sizeof(pDeadline->tv_sec) >= sizeof(uint64_t)
208 || uTimeout < (uint64_t)UINT32_MAX * RT_NS_1SEC)
209 {
210 pDeadline->tv_sec = uTimeout / RT_NS_1SEC;
211 pDeadline->tv_nsec = uTimeout % RT_NS_1SEC;
212 }
213 else
214 return UINT64_MAX;
215 }
216
217 *piWaitOp = FUTEX_WAIT;
218 *puWaitVal3 = 0;
219 return uTimeout;
220}
221
222#endif /* !IPRT_INCLUDED_SRC_r3_linux_semwait_linux_h */
223
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