[PATCH 1/5] futex: Add qemu_futex_timedwait()

Akihiko Odaki posted 5 patches 2 weeks, 2 days ago
Maintainers: "Alex Bennée" <alex.bennee@linaro.org>, Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>, Dmitry Osipenko <dmitry.osipenko@collabora.com>, "Michael S. Tsirkin" <mst@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
[PATCH 1/5] futex: Add qemu_futex_timedwait()
Posted by Akihiko Odaki 2 weeks, 2 days ago
qemu_futex_timedwait() is equivalent to qemu_futex_wait(), except it has
an absolute timeout.

Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
 include/qemu/futex.h | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/include/qemu/futex.h b/include/qemu/futex.h
index 607613eec835..e5e56603d117 100644
--- a/include/qemu/futex.h
+++ b/include/qemu/futex.h
@@ -24,6 +24,7 @@
 #ifndef QEMU_FUTEX_H
 #define QEMU_FUTEX_H
 
+#include "qemu/timer.h"
 #define HAVE_FUTEX
 
 #ifdef CONFIG_LINUX
@@ -42,18 +43,28 @@ static inline void qemu_futex_wake_single(void *f)
     qemu_futex(f, FUTEX_WAKE, 1, NULL, NULL, 0);
 }
 
-static inline void qemu_futex_wait(void *f, unsigned val)
+static inline bool qemu_futex_timedwait(void *f, unsigned val, int64_t ns)
 {
-    while (qemu_futex(f, FUTEX_WAIT, (int) val, NULL, NULL, 0)) {
+    struct timespec ts;
+    uint32_t bitset = FUTEX_BITSET_MATCH_ANY;
+
+    ts.tv_sec = ns / NANOSECONDS_PER_SECOND;
+    ts.tv_nsec = ns % NANOSECONDS_PER_SECOND;
+
+    while (qemu_futex(f, FUTEX_WAIT_BITSET, (int) val, &ts, NULL, bitset)) {
         switch (errno) {
         case EWOULDBLOCK:
-            return;
+            return true;
         case EINTR:
             break; /* get out of switch and retry */
+        case ETIMEDOUT:
+            return false;
         default:
             abort();
         }
     }
+
+    return true;
 }
 #elif defined(CONFIG_WIN32)
 #include <synchapi.h>
@@ -68,12 +79,20 @@ static inline void qemu_futex_wake_single(void *f)
     WakeByAddressSingle(f);
 }
 
-static inline void qemu_futex_wait(void *f, unsigned val)
+static inline bool qemu_futex_timedwait(void *f, unsigned val, int64_t ns)
 {
-    WaitOnAddress(f, &val, sizeof(val), INFINITE);
+    uint32_t duration = MIN((ns - get_clock()) / SCALE_MS, UINT32_MAX);
+    return WaitOnAddress(f, &val, sizeof(val), duration);
 }
 #else
 #undef HAVE_FUTEX
 #endif
 
+#ifdef HAVE_FUTEX
+static inline void qemu_futex_wait(void *f, unsigned val)
+{
+    qemu_futex_timedwait(f, val, INT64_MAX);
+}
+#endif
+
 #endif /* QEMU_FUTEX_H */

-- 
2.51.0
Re: [PATCH 1/5] futex: Add qemu_futex_timedwait()
Posted by Alex Bennée 2 weeks, 1 day ago
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:

> qemu_futex_timedwait() is equivalent to qemu_futex_wait(), except it has
> an absolute timeout.
>
> Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>

Hmm this broke my compile, I guess a name clash:

  FAILED: tests/qtest/stm32l4x5_usart-test.p/stm32l4x5_usart-test.c.o 
  cc -m64 -Itests/qtest/stm32l4x5_usart-test.p -Itests/qtest -I../../tests/qtest -I. -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/sysprof-6 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -isystem /home/alex/lsrc/qemu.git/linux-headers -isystem linux-headers -iquote . -iquote /home/alex/lsrc/qemu.git -iquote /home/alex/lsrc/qemu.git/include -iquote /home/alex/lsrc/qemu.git/host/include/x86_64 -iquote /home/alex/lsrc/qemu.git/host/include/generic -iquote /home/alex/lsrc/qemu.git/tcg/i386 -pthread -mcx16 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -fPIE -MD -MQ tests/qtest/stm32l4x5_usart-test.p/stm32l4x5_usart-test.c.o -MF tests/qtest/stm32l4x5_usart-test.p/stm32l4x5_usart-test.c.o.d -o tests/qtest/stm32l4x5_usart-test.p/stm32l4x5_usart-test.c.o -c ../../tests/qtest/stm32l4x5_usart-test.c
  ../../tests/qtest/stm32l4x5_usart-test.c:114:13: error: conflicting types for ‘init_clocks’; have ‘void(QTestState *)’
    114 | static void init_clocks(QTestState *qts)
        |             ^~~~~~~~~~~
  In file included from /home/alex/lsrc/qemu.git/include/qemu/futex.h:27,
                   from /home/alex/lsrc/qemu.git/include/qemu/thread.h:6,
                   from /home/alex/lsrc/qemu.git/include/qemu/rcu.h:27,
                   from /home/alex/lsrc/qemu.git/include/hw/qdev-core.h:7,
                   from /home/alex/lsrc/qemu.git/include/hw/sysbus.h:6,
                   from /home/alex/lsrc/qemu.git/include/hw/misc/stm32l4x5_rcc.h:21,
                   from /home/alex/lsrc/qemu.git/include/hw/misc/stm32l4x5_rcc_internals.h:22,
                   from ../../tests/qtest/stm32l4x5_usart-test.c:13:
  /home/alex/lsrc/qemu.git/include/qemu/timer.h:793:6: note: previous declaration of ‘init_clocks’ with type ‘void(void (*)(void *, QEMUClockType))’
    793 | void init_clocks(QEMUTimerListNotifyCB *notify_cb);
        |      ^~~~~~~~~~~
  ninja: build stopped: cannot make progress due to previous errors.
  make: *** [Makefile:168: run-ninja] Error 1
  make: Target 'all' not remade because of errors.
  make: Leaving directory '/home/alex/lsrc/qemu.git/builds/all'


> ---
>  include/qemu/futex.h | 29 ++++++++++++++++++++++++-----
>  1 file changed, 24 insertions(+), 5 deletions(-)
>
> diff --git a/include/qemu/futex.h b/include/qemu/futex.h
> index 607613eec835..e5e56603d117 100644
> --- a/include/qemu/futex.h
> +++ b/include/qemu/futex.h
> @@ -24,6 +24,7 @@
>  #ifndef QEMU_FUTEX_H
>  #define QEMU_FUTEX_H
>  
> +#include "qemu/timer.h"
>  #define HAVE_FUTEX
>  
>  #ifdef CONFIG_LINUX
> @@ -42,18 +43,28 @@ static inline void qemu_futex_wake_single(void *f)
>      qemu_futex(f, FUTEX_WAKE, 1, NULL, NULL, 0);
>  }
>  
> -static inline void qemu_futex_wait(void *f, unsigned val)
> +static inline bool qemu_futex_timedwait(void *f, unsigned val, int64_t ns)
>  {
> -    while (qemu_futex(f, FUTEX_WAIT, (int) val, NULL, NULL, 0)) {
> +    struct timespec ts;
> +    uint32_t bitset = FUTEX_BITSET_MATCH_ANY;
> +
> +    ts.tv_sec = ns / NANOSECONDS_PER_SECOND;
> +    ts.tv_nsec = ns % NANOSECONDS_PER_SECOND;
> +
> +    while (qemu_futex(f, FUTEX_WAIT_BITSET, (int) val, &ts, NULL, bitset)) {
>          switch (errno) {
>          case EWOULDBLOCK:
> -            return;
> +            return true;
>          case EINTR:
>              break; /* get out of switch and retry */
> +        case ETIMEDOUT:
> +            return false;
>          default:
>              abort();
>          }
>      }
> +
> +    return true;
>  }
>  #elif defined(CONFIG_WIN32)
>  #include <synchapi.h>
> @@ -68,12 +79,20 @@ static inline void qemu_futex_wake_single(void *f)
>      WakeByAddressSingle(f);
>  }
>  
> -static inline void qemu_futex_wait(void *f, unsigned val)
> +static inline bool qemu_futex_timedwait(void *f, unsigned val, int64_t ns)
>  {
> -    WaitOnAddress(f, &val, sizeof(val), INFINITE);
> +    uint32_t duration = MIN((ns - get_clock()) / SCALE_MS, UINT32_MAX);
> +    return WaitOnAddress(f, &val, sizeof(val), duration);
>  }
>  #else
>  #undef HAVE_FUTEX
>  #endif
>  
> +#ifdef HAVE_FUTEX
> +static inline void qemu_futex_wait(void *f, unsigned val)
> +{
> +    qemu_futex_timedwait(f, val, INT64_MAX);
> +}
> +#endif
> +
>  #endif /* QEMU_FUTEX_H */

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro