I think I have found the culprit. We have to check the futex operation flag
that specify which clock to use.
„
*FUTEX_CLOCK_REALTIME *(since Linux 2.6.28)
This option bit can be employed only with the
*FUTEX_WAIT_BITSET*, *FUTEX_WAIT_REQUEUE_PI*, and (since Linux
4.5) *FUTEX_WAIT *operations.
If this option is set, the kernel measures the *timeout*
against the *CLOCK_REALTIME *clock.
If this option is not set, the kernel measures the *timeout*
against the *CLOCK_MONOTONIC *clock.”
In our case the FUTEX_REAL_TIME is not set so if I change my code to
use mono tonic clocks, all works.
Waldek
On Fri, Jun 18, 2021 at 23:45 Waldek Kozaczuk <[email protected]> wrote:
> For whatever reason this patch does not work and tst-async.cc fails like
> below:
>
> diff --git a/linux.cc b/linux.cc
> index 522ed8ba..d91feb89 100644
> --- a/linux.cc
> +++ b/linux.cc
> @@ -62,23 +62,37 @@ static mutex queues_mutex;
> enum {
> FUTEX_WAIT = 0,
> FUTEX_WAKE = 1,
> + FUTEX_WAIT_BITSET = 9,
> FUTEX_PRIVATE_FLAG = 128,
> FUTEX_CLOCK_REALTIME = 256,
> FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME),
> };
>
> +#define FUTEX_BITSET_MATCH_ANY 0xffffffff
> +
> int futex(int *uaddr, int op, int val, const struct timespec *timeout,
> - int *uaddr2, int val3)
> + int *uaddr2, uint32_t val3)
> {
> switch (op & FUTEX_CMD_MASK) {
> + case FUTEX_WAIT_BITSET:
> + if (val3 != FUTEX_BITSET_MATCH_ANY) {
> + abort("Unimplemented futex() operation %d\n", op);
> + }
> +
> case FUTEX_WAIT:
> WITH_LOCK(queues_mutex) {
> if (*uaddr == val) {
> waitqueue &q = queues[uaddr];
> if (timeout) {
> sched::timer tmr(*sched::thread::current());
> - tmr.set(std::chrono::seconds(timeout->tv_sec) +
> - std::chrono::nanoseconds(timeout->tv_nsec));
> + if ((op & FUTEX_CMD_MASK) == FUTEX_WAIT_BITSET) {
> + osv::clock::wall::time_point
> abs_time(std::chrono::seconds(timeout->tv_sec) +
> +
> std::chrono::nanoseconds(timeout->tv_nsec));
> + tmr.set(abs_time);
> + } else {
> + tmr.set(std::chrono::seconds(timeout->tv_sec) +
>
> std::chrono::nanoseconds(timeout->tv_nsec));
> + }
> sched::thread::wait_for(queues_mutex, tmr, q);
> // FIXME: testing if tmr was expired isn't quite
> right -
> // we could have had both a wakeup and timer
> expiration
> @@ -403,7 +417,7 @@ long syscall(long number, ...)
> SYSCALL0(gettid);
> SYSCALL2(clock_gettime, clockid_t, struct timespec *);
> SYSCALL2(clock_getres, clockid_t, struct timespec *);
> - SYSCALL6(futex, int *, int, int, const struct timespec *, int *, int);
> + SYSCALL6(futex, int *, int, int, const struct timespec *, int *,
> uint32_t);
> SYSCALL1(close, int);
> SYSCALL2(pipe2, int *, int);
> SYSCALL1(epoll_create1, int);
>
> ./scripts/run.py -e '/tests/tst-async.so'
> OSv v0.55.0-285-g660345d5
> eth0: 192.168.122.15
> Booted up in 259.57 ms
> Cmdline: /tests/tst-async.so
> Running 18 test cases...
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_one_shot_task_fires_soon": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_async_task_fires": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_async_task_can_be_reprogrammed_while_armed": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_async_task_can_be_reprogrammed_after_cancelled": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_desctructor_does_not_block_when_called_after_task_is_done": critical
> check promise.get_future().wait_for(duration) == std::future_status::ready
> has failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_destructor_waits_for_callback_to_finish": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_async_task_can_be_reprogrammed_after_done": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_async_task_can_be_reprogrammed_from_the_callback": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_destructor_waits_for_callbacks_which_have_rescheduled_themselves":
> critical check promise.get_future().wait_for(duration) ==
> std::future_status::ready has failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_a_task_which_is_set_far_in_future_does_not_block_new_task": critical
> check promise.get_future().wait_for(duration) == std::future_status::ready
> has failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_task_which_is_scheduled_second_but_with_sooner_expiration_time_fires_first":
> critical check promise.get_future().wait_for(duration) ==
> std::future_status::ready has failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_timers_with_same_expiration_time_fire_separately": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> /git-repos/osv/tests/tst-async.cc(24): fatal error: in
> "test_serial_timer__cancel_sync_waits_for_callback": critical check
> promise.get_future().wait_for(duration) == std::future_status::ready has
> failed
> Assertion failed: _n_scheduled == 0 (core/async.cc: ~serial_timer_task:
> 386)
>
> [backtrace]
> 0x00000000402382a8 <__assert_fail+24>
> 0x000000004042736c <async::serial_timer_task::~serial_timer_task()+44>
> 0x000010000000c6f8 <???+50936>
> 0x0000100000019b26 <???+105254>
> 0x00000000408a278f <vtable for std::basic_streambuf<char,
> std::char_traits<char> >+15>
>
> What is interesting if I set relative timer for FUTEX_WAIT_BITSET instead
> of the absolute one as the spec demands, the test passes.
>
> What am I doing wrong?
>
> Waldek
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "OSv Development" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/osv-dev/ktzFAJFxbs4/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/osv-dev/bb0272e8-0864-47d8-adc7-b43ada1af0f4n%40googlegroups.com
> <https://groups.google.com/d/msgid/osv-dev/bb0272e8-0864-47d8-adc7-b43ada1af0f4n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/osv-dev/CAL9cFfOREbGpWwB4X8ycAjBbxad%3DcWD8H6XWiW-Wi8Qfho%2BsFw%40mail.gmail.com.