Re: [RFC PATCH 01/13] futex2: Implement wait and wake functions

From: André Almeida
Date: Thu Feb 18 2021 - 15:12:19 EST


Hi Peter,

Às 06:02 de 16/02/21, Peter Zijlstra escreveu:
On Mon, Feb 15, 2021 at 12:23:52PM -0300, André Almeida wrote:
+static int __futex_wait(struct futexv_head *futexv, unsigned int nr_futexes,
+ struct hrtimer_sleeper *timeout)
+{
+ int ret;
+
+ while (1) {
+ int awakened = -1;
+

Might be easier to understand if the set_current_state() is here,
instead of squirreled away in futex_enqueue().


I placed set_current_state() inside futex_enqueue() because we need to set RUNNING and then INTERRUPTIBLE again for the retry path.

+ ret = futex_enqueue(futexv, nr_futexes, &awakened);
+
+ if (ret) {
+ if (awakened >= 0)
+ return awakened;
+ return ret;
+ }
+
+ /* Before sleeping, check if someone was woken */
+ if (!futexv->hint && (!timeout || timeout->task))
+ freezable_schedule();
+
+ __set_current_state(TASK_RUNNING);

This is typically after the loop.


Sorry, which loop?

+
+ /*
+ * One of those things triggered this wake:
+ *
+ * * We have been removed from the bucket. futex_wake() woke
+ * us. We just need to dequeue and return 0 to userspace.
+ *
+ * However, if no futex was dequeued by a futex_wake():
+ *
+ * * If the there's a timeout and it has expired,
+ * return -ETIMEDOUT.
+ *
+ * * If there is a signal pending, something wants to kill our
+ * thread, return -ERESTARTSYS.
+ *
+ * * If there's no signal pending, it was a spurious wake
+ * (scheduler gave us a change to do some work, even if we

chance?

Indeed, fixed.


+ * don't want to). We need to remove ourselves from the
+ * bucket and add again, to prevent losing wakeups in the
+ * meantime.
+ */

Anyway, doing a dequeue and enqueue for spurious wakes is a bit of an
anti-pattern that can lead to starvation. I've not actually looked at
much detail yet as this is my first read-through, but did figure I'd
mention it.


So we could just leave everything enqueued for spurious wake? I was expecting that we would need to do all the work again (including rechecking *uaddr == val) to see if we didn't miss a futex_wake() between the kernel thread waking (spuriously) and going to sleep again.

+
+ ret = futex_dequeue_multiple(futexv, nr_futexes);
+
+ /* Normal wake */
+ if (ret >= 0)
+ return ret;
+
+ if (timeout && !timeout->task)
+ return -ETIMEDOUT;
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ /* Spurious wake, do everything again */
+ }
+}

Thanks,
André