mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: Darren Hart <dvhltc@us.ibm.com>
Cc: "lkml, " <linux-kernel@vger.kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Steven Rostedt <rostedt@goodmis.org>, Ingo Molnar <mingo@elte.hu>,
	Eric Dumazet <eric.dumazet@gmail.com>,
	Dinakar Guniguntala <dino@in.ibm.com>,
	John Stultz <johnstul@us.ibm.com>
Subject: Re: futex: wakeup race and futex_q woken state definition
Date: Thu, 17 Sep 2009 10:11:55 +0200 (CEST)	[thread overview]
Message-ID: <alpine.LFD.2.00.0909170939080.2889@localhost.localdomain> (raw)
In-Reply-To: <4AB17A08.50008@us.ibm.com>

Darren,

On Wed, 16 Sep 2009, Darren Hart wrote:

> 2) futex_wait_queue_me() (recently refactored from futex_wait())
>   performs the following test:
> 
> 	/*
> 	 * !plist_node_empty() is safe here without any lock.
> 	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
> 	 */
> 	if (likely(!plist_node_empty(&q->list))) {
> 		/*
> 		 * If the timer has already expired, current will already be
> 		 * flagged for rescheduling. Only call schedule if there
> 		 * is no timeout, or if it has yet to expire.
> 		 */
> 		if (!timeout || timeout->task)
> 			schedule();
> 	}
> 
> As I understand it, this is to avoid a missed wakeup when a FUTEX_WAKE
> call occurs after the queue_me() but before the futex_wait() call has
> had a chance to call schedule() (via futex_wait_queue_me()).  However,
> as no locks are taken, I don't see what prevents the futex_q from being
> removed from the hash list after the plist_node_empty() test and before
> the call to schedule().  In this scenario, the futex_q will not be found
> on the hash list by subsequent wakers, and it will remain in schedule()
> until a timeout or signal occurs.
> 
> This leads me to the question on the comment: "!plist_node_empty() is
> safe here without any lock." - Why is that safe?
> 
> Secondly, why is the q.lock_ptr test not safe? "q.lock_ptr != 0 is not
> safe, because of ordering against wakeup."
> 
> I understand the definition of the woken state to be
> "plist_node_empty(&q->list) || q->lock_ptr == 0".  So testing the plist
> will detect a woken futex sooner than testing for a null lock_ptr, but I
> don't see how one is more "safe" than the other when no locks are held
> to prevent the futex_q from vanishing off the list before the call to
> schedule().

Much of this are historic leftovers.

futex_wait_queue_me()
{
	queue_me(q, hb);

	/*
	 * There might have been scheduling since the queue_me(), as we
	 * cannot hold a spinlock across the get_user() in case it
	 * faults, and we cannot just set TASK_INTERRUPTIBLE state when
	 * queueing ourselves into the futex hash. This code thus has to
	 * rely on the futex_wake() code removing us from hash when it
	 * wakes us up.
	 */

This comment is stale and patently wrong today. There is no get_user()
while we hold a spinlock. So we should move set_current_state() before
queue_me()

	set_current_state(TASK_INTERRUPTIBLE);

	/*
	 * !plist_node_empty() is safe here without any lock.
	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
	 */
	if (likely(!plist_node_empty(&q->list))) {

If we move set_current_state() before the queue_me() this check is
still an optimization to avoid the schedule call in case we have been
woken up already. But the comment is still wrong as the wakeup code
has changed:

The old version did:

     plist_del(&q->list);
     wake_up_all(&q->waiters);
     q->lock_ptr = NULL;

Today we do:

     p = q->task;
     get_task_struct(p);
     plist_del(&q->list);
     q->lock_ptr = NULL;
     wake_up_state(p);
     put_task_struct(p);

We changed this because it makes no sense to use a waitqueue for a
single task.

So the whole commentry is stale and needs to be updated.

Thanks,

	tglx

  reply	other threads:[~2009-09-17  8:12 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-16 23:51 Darren Hart
2009-09-17  8:11 ` Thomas Gleixner [this message]
2009-09-17 15:06   ` Darren Hart
2009-09-17 15:23     ` Thomas Gleixner
2009-09-21  6:39       ` Darren Hart

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

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.LFD.2.00.0909170939080.2889@localhost.localdomain \
    --to=tglx@linutronix.de \
    --cc=dino@in.ibm.com \
    --cc=dvhltc@us.ibm.com \
    --cc=eric.dumazet@gmail.com \
    --cc=johnstul@us.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    /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

all inboxes | Powered by JetHome®