futex: restartable futex_wait
PATCH 1/1 futex: restartable futex_wait
LTP test sigaction_16_24 fails, because it expects sem_wait to be restarted if SA_RESTART is set. sem_wait is implemented with futex_wait, that currently doesn't support being restarted. Ulrich confirms that the call should be restartable.
Implement a restart_block method to handle the relative timeout, and allow restarts.
kernel/futex.c +24 -1
@@ -978,6 +978,7 @@ static void unqueue_me_pi(struct futex_qdrop_futex_key_refs (&q->key); } +static long futex_wait_restart (struct restart_block *restart);static int futex_wait (u32 __user *uaddr,u32 val,unsigned long time) {struct task_struct *curr = current;
@@ -1077,11 +1078,22 @@ static int futex_wait(u32 __user *uaddr,return 0 ;if (time ==0 )return -ETIMEDOUT ; +/* * We expect signal_pending(current), but another thread may * have handled it for us already. */ -return -EINTR ; +if (time ==MAX_SCHEDULE_TIMEOUT ) +return -ERESTARTSYS ; +else { +struct restart_block *restart; + restart = ¤t_thread_info ()->restart_block; + restart->fn = futex_wait_restart; + restart->arg0 = (unsigned long )uaddr; + restart->arg1 = (unsigned long )val; + restart->arg2 = time; +return -ERESTART_RESTARTBLOCK ; + } out_unlock_release_sem:queue_unlock (&q, hb);
@@ -1091,6 +1103,17 @@ static int futex_wait(u32 __user *uaddr,return ret; } +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; + + restart->fn = do_no_restart_syscall; +return (long )futex_wait (uaddr, val, time); +} + +/* * Userspace tried a 0 -> TID atomic transition of the futex value * and failed. The kernel side here does the whole locking operation:
Quoted 9 lines · Nick Piggin
LTP test
sigaction_16_24fails, because it expectssem_waitto be restarted ifSA_RESTARTis set.sem_waitis implemented withfutex_wait, that currently doesn't support being restarted. Ulrich confirms that the call should be restartable.Implement a
restart_blockmethod to handle the relative timeout, and allow restarts.Signed-off-by Nick Piggin <[email protected]>
yeah:
i was totally confused and thought this was the original argument:
kernel/futex.c static int futex_wait(u32 __user *uaddr, · line 1095
Quoted 2 lines
kernel/futex.c +2
-0+ restart->arg2 = time; +return -ERESTART_RESTARTBLOCK ;
but it's indeed the 'new' relative timeout. (It can still be a tiny bit inaccurate because if there are many signals then the signals will delay the relative timeout - so absolute timeouts are still better - but your fix is correct and needed nevertheless)
Ingo