From: Kurt Kanzenbach via Libc-alpha <libc-alpha@sourceware.org>
To: libc-alpha@sourceware.org
Cc: Florian Weimer <fweimer@redhat.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Kurt Kanzenbach <kurt@linutronix.de>,
Peter Zijlstra <peterz@infradead.org>,
Thomas Gleixner <tglx@linutronix.de>,
Joseph Myers <joseph@codesourcery.com>
Subject: [PATCH v1 2/6] nptl: Introduce futex_lock_pi2()
Date: Fri, 25 Jun 2021 10:11:00 +0200 [thread overview]
Message-ID: <20210625081104.1134598-3-kurt@linutronix.de> (raw)
In-Reply-To: <20210625081104.1134598-1-kurt@linutronix.de>
This variant of futex_lock() has support for selectable clocks and priority
inheritance. The underlying FUTEX_LOCK_PI2 operation has been recently
introduced into the Linux kernel.
It can be used for implementing pthread_mutex_clocklock(MONOTONIC)/PI.
The code works like this:
* If kernel support is assumed, then use FUTEX_LOCK_PI2
* If not, distuingish between clockid:
* For realtime use FUTEX_LOCK_PI
* For monotonic try to use FUTEX_LOCK_PI2 which might not be available
Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
---
sysdeps/nptl/futex-internal.h | 131 ++++++++++++++++++++++++++++++
sysdeps/nptl/lowlevellock-futex.h | 1 +
2 files changed, 132 insertions(+)
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index 79a366604d9e..38c969831276 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -303,6 +303,137 @@ futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime,
}
}
+/* The operation checks the value of the futex, if the value is 0, then
+ it is atomically set to the caller's thread ID. If the futex value is
+ nonzero, it is atomically sets the FUTEX_WAITERS bit, which signals wrt
+ other futex owner that it cannot unlock the futex in user space by
+ atomically by setting its value to 0.
+
+ If more than one wait operations is issued, the enqueueing of the waiters
+ are done in descending priority order.
+
+ The ABSTIME arguments provides an absolute timeout (measured against the
+ CLOCK_REALTIME or CLOCK_MONOTONIC clock). If TIMEOUT is NULL, the operation
+ will block indefinitely.
+
+ Returns:
+
+ - 0 if woken by a PI unlock operation or spuriously.
+ - EAGAIN if the futex owner thread ID is about to exit, but has not yet
+ handled the state cleanup.
+ - EDEADLK if the futex is already locked by the caller.
+ - ESRCH if the thread ID int he futex does not exist.
+ - EINVAL is the state is corrupted or if there is a waiter on the
+ futex or if the clockid is invalid.
+ - ETIMEDOUT if the ABSTIME expires.
+*/
+static __always_inline int
+futex_lock_pi2_64 (int *futex_word, clockid_t clockid,
+ const struct __timespec64 *abstime, int private)
+{
+ unsigned int clockbit;
+ int err;
+
+ if (! lll_futex_supported_clockid (clockid))
+ return EINVAL;
+
+ clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0;
+ int op = __lll_private_flag (FUTEX_LOCK_PI2 | clockbit, private);
+
+ /* FUTEX_LOCK_PI2 is a new futex operation. It supports selectable clocks
+ whereas the old FUTEX_LOCK_PI does only support CLOCK_REALTIME.
+
+ Therefore, the code works like this:
+
+ - If kernel support is available, then use FUTEX_LOCK_PI2
+ - If not, distuingish between clockid: For realtime use FUTEX_LOCK_PI and
+ for monotonic try to use FUTEX_LOCK_PI2 which might not be available. */
+
+#if __ASSUME_FUTEX_LOCK_PI2
+
+# ifdef __ASSUME_TIME64_SYSCALLS
+ err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, 0, abstime);
+# else
+
+ bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
+ if (need_time64)
+ {
+ err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, 0, abstime);
+ if (err == -ENOSYS)
+ err = -EOVERFLOW;
+ }
+ else
+ {
+ struct timespec ts32;
+
+ if (abstime != NULL)
+ ts32 = valid_timespec64_to_timespec (*abstime);
+
+ err = INTERNAL_SYSCALL_CALL (futex, futex_word, op, 0,
+ abstime != NULL ? &ts32 : NULL);
+ }
+# endif /* __ASSUME_TIME64_SYSCALLS */
+
+#else
+
+ /* For CLOCK_MONOTONIC the only option is to use FUTEX_LOCK_PI2 */
+ if (abstime != NULL && clockid != CLOCK_REALTIME)
+ {
+# ifdef __ASSUME_TIME64_SYSCALLS
+ err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, 0, abstime);
+# else
+ bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
+ if (need_time64)
+ {
+ err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, 0,
+ abstime);
+ }
+ else
+ {
+ struct timespec ts32;
+
+ if (abstime != NULL)
+ ts32 = valid_timespec64_to_timespec (*abstime);
+
+ err = INTERNAL_SYSCALL_CALL (futex, futex_word, op, 0,
+ abstime != NULL ? &ts32 : NULL);
+ }
+# endif /* __ASSUME_TIME64_SYSCALLS */
+
+ /* FUTEX_LOCK_PI2 is not available on this kernel */
+ if (err == -ENOSYS)
+ return EINVAL;
+ }
+ else
+ {
+ /* Otherwise use CLOCK_REALTIME and FUTEX_LOCK_PI */
+ return futex_lock_pi64 (futex_word, abstime, private);
+ }
+#endif /* __ASSUME_FUTEX_LOCK_PI2 */
+
+ switch (err)
+ {
+ case 0:
+ case -EAGAIN:
+ case -EINTR:
+ case -ETIMEDOUT:
+ case -ESRCH:
+ case -EDEADLK:
+ case -EINVAL: /* This indicates either state corruption or that the kernel
+ found a waiter on futex address which is waiting via
+ FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
+ some futex_lock_pi usage (pthread_mutex_timedlock for
+ instance). */
+ return -err;
+
+ case -EFAULT: /* Must have been caused by a glibc or application bug. */
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ futex_fatal_error ();
+ }
+}
+
/* Wakes the top priority waiter that called a futex_lock_pi operation on
the futex.
diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h
index 66ebfe50f4c1..abda179e0de2 100644
--- a/sysdeps/nptl/lowlevellock-futex.h
+++ b/sysdeps/nptl/lowlevellock-futex.h
@@ -38,6 +38,7 @@
#define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
+#define FUTEX_LOCK_PI2 13
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
--
2.30.2
next prev parent reply other threads:[~2021-06-25 8:12 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-25 8:10 [PATCH v1 0/6] nptl: Introduce and use FUTEX_LOCK_PI2 Kurt Kanzenbach via Libc-alpha
2021-06-25 8:10 ` [PATCH v1 1/6] Linux: Add FUTEX_LOCK_PI2 Kurt Kanzenbach via Libc-alpha
2021-07-09 13:32 ` Adhemerval Zanella via Libc-alpha
2021-06-25 8:11 ` Kurt Kanzenbach via Libc-alpha [this message]
2021-07-09 14:13 ` [PATCH v1 2/6] nptl: Introduce futex_lock_pi2() Adhemerval Zanella via Libc-alpha
2021-06-25 8:11 ` [PATCH v1 3/6] nptl: Use futex_lock_pi2() Kurt Kanzenbach via Libc-alpha
2021-07-09 14:21 ` Adhemerval Zanella via Libc-alpha
2021-06-25 8:11 ` [PATCH v1 4/6] nptl: Remove mutex test 10 Kurt Kanzenbach via Libc-alpha
2021-07-09 14:23 ` Adhemerval Zanella via Libc-alpha
2021-06-25 8:11 ` [PATCH v1 5/6] nptl: mutex-test5: Include CLOCK_MONOTONIC for PI Kurt Kanzenbach via Libc-alpha
2021-06-25 8:11 ` [PATCH v1 6/6] nptl: mutex-test9: " Kurt Kanzenbach via Libc-alpha
2021-07-09 6:57 ` [PATCH v1 0/6] nptl: Introduce and use FUTEX_LOCK_PI2 Kurt Kanzenbach via Libc-alpha
2021-07-09 13:30 ` Adhemerval Zanella via Libc-alpha
2021-07-09 14:20 ` Kurt Kanzenbach via Libc-alpha
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/libc/involved.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210625081104.1134598-3-kurt@linutronix.de \
--to=libc-alpha@sourceware.org \
--cc=bigeasy@linutronix.de \
--cc=fweimer@redhat.com \
--cc=joseph@codesourcery.com \
--cc=kurt@linutronix.de \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).