From: Nick Piggin This uses absolute timeouts for futex restarts, so that we never lose a jiffy during the restart. Can be folded with the other futex patch. Cc: Ulrich Drepper Cc: Rusty Russell Cc: Roland McGrath Cc: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton --- kernel/futex.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff -puN kernel/futex.c~futex-restartable-futex_wait-fix kernel/futex.c --- a/kernel/futex.c~futex-restartable-futex_wait-fix +++ a/kernel/futex.c @@ -981,12 +981,14 @@ static void unqueue_me_pi(struct futex_q } static long futex_wait_restart(struct restart_block *restart); -static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) +static int futex_wait_abstime(u32 __user *uaddr, u32 val, + int timed, unsigned long abs_time) { struct task_struct *curr = current; DECLARE_WAITQUEUE(wait, curr); struct futex_hash_bucket *hb; struct futex_q q; + unsigned long time_left = 0; u32 uval; int ret; @@ -1066,8 +1068,21 @@ static int futex_wait(u32 __user *uaddr, * !list_empty() is safe here without any lock. * q.lock_ptr != 0 is not safe, because of ordering against wakeup. */ - if (likely(!list_empty(&q.list))) - time = schedule_timeout(time); + time_left = 0; + if (likely(!list_empty(&q.list))) { + unsigned long rel_time; + + if (timed) { + unsigned long now = jiffies; + if (time_after(now, abs_time)) + rel_time = 0; + else + rel_time = abs_time - now; + } else + rel_time = MAX_SCHEDULE_TIMEOUT; + + time_left = schedule_timeout(rel_time); + } __set_current_state(TASK_RUNNING); /* @@ -1078,14 +1093,14 @@ static int futex_wait(u32 __user *uaddr, /* If we were woken (and unqueued), we succeeded, whatever. */ if (!unqueue_me(&q)) return 0; - if (time == 0) + if (time_left == 0) return -ETIMEDOUT; /* * We expect signal_pending(current), but another thread may * have handled it for us already. */ - if (time == MAX_SCHEDULE_TIMEOUT) + if (time_left == MAX_SCHEDULE_TIMEOUT) return -ERESTARTSYS; else { struct restart_block *restart; @@ -1093,7 +1108,8 @@ static int futex_wait(u32 __user *uaddr, restart->fn = futex_wait_restart; restart->arg0 = (unsigned long)uaddr; restart->arg1 = (unsigned long)val; - restart->arg2 = time; + restart->arg2 = (unsigned long)timed; + restart->arg3 = abs_time; return -ERESTART_RESTARTBLOCK; } @@ -1105,14 +1121,21 @@ static int futex_wait(u32 __user *uaddr, return ret; } +static int futex_wait(u32 __user *uaddr, u32 val, unsigned long rel_time) +{ + int timed = (rel_time != MAX_SCHEDULE_TIMEOUT); + return futex_wait_abstime(uaddr, val, timed, jiffies+rel_time); +} + static long futex_wait_restart(struct restart_block *restart) { u32 __user *uaddr = (u32 __user *)restart->arg0; u32 val = (u32)restart->arg1; - unsigned long time = restart->arg2; + int timed = (int)restart->arg2; + unsigned long abs_time = restart->arg3; restart->fn = do_no_restart_syscall; - return (long)futex_wait(uaddr, val, time); + return (long)futex_wait_abstime(uaddr, val, timed, abs_time); } _