Skip to content

Commit

Permalink
futex: Handle spurious wake up
Browse files Browse the repository at this point in the history
The futex code does not handle spurious wake up in futex_wait and
futex_wait_requeue_pi.

The code assumes that any wake up which was not caused by futex_wake /
requeue or by a timeout was caused by a signal wake up and returns one
of the syscall restart error codes.

In case of a spurious wake up the signal delivery code which deals
with the restart error codes is not invoked and we return that error
code to user space. That causes applications which actually check the
return codes to fail. Blaise reported that on preempt-rt a python test
program run into a exception trap. -rt exposed that due to a built in
spurious wake up accelerator :)

Solve this by checking signal_pending(current) in the wake up path and
handle the spurious wake up case w/o returning to user space.

Reported-by: Blaise Gassend <blaise@willowgarage.com>
Debugged-by: Darren Hart <dvhltc@us.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@kernel.org
LKML-Reference: <new-submission>
  • Loading branch information
Thomas Gleixner committed Oct 13, 2009
1 parent c7cedb1 commit d58e657
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
current->timer_slack_ns);
}

retry:
/* Prepare to wait on uaddr. */
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
if (ret)
Expand All @@ -1808,9 +1809,14 @@ static int futex_wait(u32 __user *uaddr, int fshared,
goto out_put_key;

/*
* We expect signal_pending(current), but another thread may
* have handled it for us already.
* We expect signal_pending(current), but we might be the
* victim of a spurious wakeup as well.
*/
if (!signal_pending(current)) {
put_futex_key(fshared, &q.key);
goto retry;
}

ret = -ERESTARTSYS;
if (!abs_time)
goto out_put_key;
Expand Down Expand Up @@ -2118,9 +2124,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
*/
plist_del(&q->list, &q->list.plist);

/* Handle spurious wakeups gracefully */
ret = -EAGAIN;
if (timeout && !timeout->task)
ret = -ETIMEDOUT;
else
else if (signal_pending(current))
ret = -ERESTARTNOINTR;
}
return ret;
Expand Down Expand Up @@ -2198,6 +2206,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL;

retry:
key2 = FUTEX_KEY_INIT;
ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
if (unlikely(ret != 0))
Expand Down Expand Up @@ -2292,6 +2301,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
out_key2:
put_futex_key(fshared, &key2);

/* Spurious wakeup ? */
if (ret == -EAGAIN)
goto retry;
out:
if (to) {
hrtimer_cancel(&to->timer);
Expand Down

0 comments on commit d58e657

Please sign in to comment.