Commit d58e6576b0deec6f0b9ff8450fe282da18c50883

Authored by Thomas Gleixner
1 parent c7cedb125b

futex: Handle spurious wake up

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>

Showing 1 changed file with 15 additions and 3 deletions Side-by-side Diff

... ... @@ -1791,6 +1791,7 @@
1791 1791 current->timer_slack_ns);
1792 1792 }
1793 1793  
  1794 +retry:
1794 1795 /* Prepare to wait on uaddr. */
1795 1796 ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
1796 1797 if (ret)
1797 1798  
... ... @@ -1808,9 +1809,14 @@
1808 1809 goto out_put_key;
1809 1810  
1810 1811 /*
1811   - * We expect signal_pending(current), but another thread may
1812   - * have handled it for us already.
  1812 + * We expect signal_pending(current), but we might be the
  1813 + * victim of a spurious wakeup as well.
1813 1814 */
  1815 + if (!signal_pending(current)) {
  1816 + put_futex_key(fshared, &q.key);
  1817 + goto retry;
  1818 + }
  1819 +
1814 1820 ret = -ERESTARTSYS;
1815 1821 if (!abs_time)
1816 1822 goto out_put_key;
1817 1823  
... ... @@ -2118,9 +2124,11 @@
2118 2124 */
2119 2125 plist_del(&q->list, &q->list.plist);
2120 2126  
  2127 + /* Handle spurious wakeups gracefully */
  2128 + ret = -EAGAIN;
2121 2129 if (timeout && !timeout->task)
2122 2130 ret = -ETIMEDOUT;
2123   - else
  2131 + else if (signal_pending(current))
2124 2132 ret = -ERESTARTNOINTR;
2125 2133 }
2126 2134 return ret;
... ... @@ -2198,6 +2206,7 @@
2198 2206 debug_rt_mutex_init_waiter(&rt_waiter);
2199 2207 rt_waiter.task = NULL;
2200 2208  
  2209 +retry:
2201 2210 key2 = FUTEX_KEY_INIT;
2202 2211 ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
2203 2212 if (unlikely(ret != 0))
... ... @@ -2292,6 +2301,9 @@
2292 2301 out_key2:
2293 2302 put_futex_key(fshared, &key2);
2294 2303  
  2304 + /* Spurious wakeup ? */
  2305 + if (ret == -EAGAIN)
  2306 + goto retry;
2295 2307 out:
2296 2308 if (to) {
2297 2309 hrtimer_cancel(&to->timer);