Skip to content

Commit bcaad08

Browse files
wkozaczuknyh
authored andcommitted
futex: implement FUTEX_WAIT_BITSET
New version of C++ standard library that is part of GCC 11 toolchain started using futex() syscall with the FUTEX_WAIT_BITSET operation. It turns out we are pretty lucky (so far at least) because the bitmask value passed in the val3 parameter is equal to FUTEX_BITSET_MATCH_ANY. According to the spec, it means that FUTEX_WAIT_BITSET with val3 equal to FUTEX_BITSET_MATCH_ANY is equivalent to FUTEX_WAIT except for the different handling of the timeout argument. This patch implements minimal functionality of FUTEX_WAIT_BITSET that handles FUTEX_BITSET_MATCH_ANY and is enough to make failing tst-async.cc and tst-promise.cc pass. Fixes #1147 Signed-off-by: Waldemar Kozaczuk <jwkozaczuk@gmail.com> Message-Id: <20210621060640.8041-1-jwkozaczuk@gmail.com>
1 parent 660345d commit bcaad08

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

linux.cc

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,44 @@ static mutex queues_mutex;
6262
enum {
6363
FUTEX_WAIT = 0,
6464
FUTEX_WAKE = 1,
65+
FUTEX_WAIT_BITSET = 9,
6566
FUTEX_PRIVATE_FLAG = 128,
6667
FUTEX_CLOCK_REALTIME = 256,
6768
FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME),
6869
};
6970

71+
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
72+
7073
int futex(int *uaddr, int op, int val, const struct timespec *timeout,
71-
int *uaddr2, int val3)
74+
int *uaddr2, uint32_t val3)
7275
{
7376
switch (op & FUTEX_CMD_MASK) {
77+
case FUTEX_WAIT_BITSET:
78+
if (val3 != FUTEX_BITSET_MATCH_ANY) {
79+
abort("Unimplemented futex() operation %d\n", op);
80+
}
81+
7482
case FUTEX_WAIT:
7583
WITH_LOCK(queues_mutex) {
7684
if (*uaddr == val) {
7785
waitqueue &q = queues[uaddr];
7886
if (timeout) {
7987
sched::timer tmr(*sched::thread::current());
80-
tmr.set(std::chrono::seconds(timeout->tv_sec) +
81-
std::chrono::nanoseconds(timeout->tv_nsec));
88+
if ((op & FUTEX_CMD_MASK) == FUTEX_WAIT_BITSET) {
89+
// If FUTEX_WAIT_BITSET we need to interpret timeout as an absolute
90+
// time point. If futex operation FUTEX_CLOCK_REALTIME is set we will use
91+
// real-time clock otherwise we will use monotonic clock
92+
if (op & FUTEX_CLOCK_REALTIME) {
93+
tmr.set(osv::clock::wall::time_point(std::chrono::seconds(timeout->tv_sec) +
94+
std::chrono::nanoseconds(timeout->tv_nsec)));
95+
} else {
96+
tmr.set(osv::clock::uptime::time_point(std::chrono::seconds(timeout->tv_sec) +
97+
std::chrono::nanoseconds(timeout->tv_nsec)));
98+
}
99+
} else {
100+
tmr.set(std::chrono::seconds(timeout->tv_sec) +
101+
std::chrono::nanoseconds(timeout->tv_nsec));
102+
}
82103
sched::thread::wait_for(queues_mutex, tmr, q);
83104
// FIXME: testing if tmr was expired isn't quite right -
84105
// we could have had both a wakeup and timer expiration
@@ -403,7 +424,7 @@ long syscall(long number, ...)
403424
SYSCALL0(gettid);
404425
SYSCALL2(clock_gettime, clockid_t, struct timespec *);
405426
SYSCALL2(clock_getres, clockid_t, struct timespec *);
406-
SYSCALL6(futex, int *, int, int, const struct timespec *, int *, int);
427+
SYSCALL6(futex, int *, int, int, const struct timespec *, int *, uint32_t);
407428
SYSCALL1(close, int);
408429
SYSCALL2(pipe2, int *, int);
409430
SYSCALL1(epoll_create1, int);

0 commit comments

Comments
 (0)