Skip to content

Commit 3101428

Browse files
authored
Merge pull request llvm#120 from pcc/filc11
Futex syscall: implement timeouts, FUTEX_WAIT_BITSET, FUTEX_CLOCK_REA…
2 parents d33b46c + f60f28b commit 3101428

File tree

4 files changed

+78
-11
lines changed

4 files changed

+78
-11
lines changed

filc/include/pizlonated_syscalls.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ int zsys_uname(void* buf);
221221
int zsys_sendfile(int out_fd, int in_fd, long* offset, __SIZE_TYPE__ count);
222222
void zsys_futex_wake(volatile int* addr, int cnt, int priv);
223223
void zsys_futex_wait(volatile int* addr, int val, int priv);
224-
/* These futex calls return the errno as a negative value. They do not set errno.
224+
/* These futex calls return the errno as a positive value. They do not set errno.
225225
226226
NOTE: the futex_timedwait uses an absolute timeout, which is not what the real futex syscall
227227
uses! */

filc/src/runtime.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <stdfil.h>
3131
#include <pizlonated_syscalls.h>
3232
#include <pizlonated_runtime.h>
33+
#include <linux/futex.h>
34+
#include <linux/time.h>
3335

3436
unsigned zversion(void)
3537
{
@@ -465,15 +467,11 @@ struct futex_args {
465467
volatile void* uaddr;
466468
long futex_op;
467469
unsigned long val;
468-
const void* timeout;
470+
const struct timespec* timeout;
469471
volatile void* uaddr2;
470472
unsigned long val3;
471473
};
472474

473-
#define FUTEX_WAIT 0
474-
#define FUTEX_WAKE 1
475-
#define FUTEX_PRIVATE 128
476-
477475
long zsys_syscall(long n, ...)
478476
{
479477
/* The goal is to have this code support all syscalls, but it doesn't do that, yet. So,
@@ -493,13 +491,38 @@ long zsys_syscall(long n, ...)
493491
struct futex_args* args = (struct futex_args*)syscall_args;
494492
switch (args->futex_op) {
495493
case FUTEX_WAIT:
496-
case FUTEX_WAIT | FUTEX_PRIVATE:
497-
ZASSERT(!args->timeout);
498-
zsys_futex_wait(args->uaddr, args->val, args->futex_op & FUTEX_PRIVATE);
494+
case FUTEX_WAIT | FUTEX_PRIVATE_FLAG:
495+
case FUTEX_WAIT | FUTEX_CLOCK_REALTIME:
496+
case FUTEX_WAIT | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME:
497+
case FUTEX_WAIT_BITSET:
498+
case FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG:
499+
case FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME:
500+
case FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME: {
501+
if (args->futex_op & FUTEX_WAIT_BITSET)
502+
ZASSERT(args->val3 == FUTEX_BITSET_MATCH_ANY);
503+
int clock_id = (args->futex_op & FUTEX_CLOCK_REALTIME) ? CLOCK_REALTIME : CLOCK_MONOTONIC;
504+
struct timespec timeout = {};
505+
if (args->timeout) {
506+
if (!(args->futex_op & FUTEX_WAIT_BITSET))
507+
zsys_clock_gettime(clock_id, &timeout);
508+
timeout.tv_sec += args->timeout->tv_sec;
509+
timeout.tv_nsec += args->timeout->tv_nsec;
510+
if (timeout.tv_nsec >= 1000000000) {
511+
timeout.tv_sec++;
512+
timeout.tv_nsec -= 1000000000;
513+
}
514+
}
515+
int err = zsys_futex_timedwait(args->uaddr, args->val, clock_id,
516+
args->timeout ? &timeout : 0, args->futex_op & FUTEX_PRIVATE_FLAG);
517+
if (err > 0) {
518+
zset_errno(err);
519+
return -1;
520+
}
499521
return 0;
522+
}
500523
case FUTEX_WAKE:
501-
case FUTEX_WAKE | FUTEX_PRIVATE:
502-
zsys_futex_wake(args->uaddr, args->val, args->futex_op & FUTEX_PRIVATE);
524+
case FUTEX_WAKE | FUTEX_PRIVATE_FLAG:
525+
zsys_futex_wake(args->uaddr, args->val, args->futex_op & FUTEX_PRIVATE_FLAG);
503526
return 0;
504527
default:
505528
zerrorf("unsupported futex op: %d.", args->futex_op);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <errno.h>
2+
#include <linux/futex.h>
3+
#include <stdfil.h>
4+
#include <stdint.h>
5+
#include <sys/syscall.h>
6+
#include <time.h>
7+
#include <unistd.h>
8+
9+
struct timespec now_plus(int clock_id, struct timespec addend)
10+
{
11+
struct timespec result;
12+
clock_gettime(clock_id, &result);
13+
result.tv_sec += addend.tv_sec;
14+
result.tv_nsec += addend.tv_nsec;
15+
if (result.tv_nsec >= 1000000000) {
16+
result.tv_sec++;
17+
result.tv_nsec -= 1000000000;
18+
}
19+
return result;
20+
}
21+
22+
int main()
23+
{
24+
struct timespec ten_ms = {0, 10000000};
25+
uint32_t fw = 0;
26+
27+
/* These take a relative timespec. */
28+
ZASSERT(syscall(SYS_futex, &fw, FUTEX_WAIT, 0, &ten_ms, 0, 0) == -1);
29+
ZASSERT(errno == ETIMEDOUT);
30+
ZASSERT(syscall(SYS_futex, &fw, FUTEX_WAIT | FUTEX_CLOCK_REALTIME, 0, &ten_ms, 0, 0) == -1);
31+
ZASSERT(errno == ETIMEDOUT);
32+
33+
/* These take an absolute timespec. */
34+
struct timespec timeout = now_plus(CLOCK_MONOTONIC, ten_ms);
35+
ZASSERT(syscall(SYS_futex, &fw, FUTEX_WAIT_BITSET, 0, &timeout, 0, FUTEX_BITSET_MATCH_ANY) == -1);
36+
ZASSERT(errno == ETIMEDOUT);
37+
timeout = now_plus(CLOCK_REALTIME, ten_ms);
38+
ZASSERT(syscall(SYS_futex, &fw, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, 0, &timeout, 0,
39+
FUTEX_BITSET_MATCH_ANY)
40+
== -1);
41+
ZASSERT(errno == ETIMEDOUT);
42+
}

filc/tests/futextimeout/manifest

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
return:
2+
success

0 commit comments

Comments
 (0)