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 wechance?
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é