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é

Reply via email to