Re: [RFC PATCH 01/13] futex2: Implement wait and wake functions
From: André Almeida <hidden>
Date: 2021-02-18 20:12:26
Also in:
linux-kselftest, lkml
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:quoted
+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.
quoted
+ 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?
quoted
+ + /* + * 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 wechance?
Indeed, fixed.
quoted
+ * 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.
quoted
+ + 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é