aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-04-27 15:44:14 -0400
committerOleg Nesterov <oleg@redhat.com>2011-04-28 07:01:38 -0400
commit943df1485a8ff0e600729e082e568ece04d4de9e (patch)
treed2d4b7b41f163e011cb7a373376c9ae87e5941be /kernel
parentfe0faa005d43bc44c357631d51c273806086caa4 (diff)
signal: introduce do_sigtimedwait() to factor out compat/native code
Factor out the common code in sys_rt_sigtimedwait/compat_sys_rt_sigtimedwait to the new helper, do_sigtimedwait(). Add the comment to document the extra tick we add to timespec_to_jiffies(ts), thanks to Linus who explained this to me. Perhaps it would be better to move compat_sys_rt_sigtimedwait() into signal.c under CONFIG_COMPAT, then we can make do_sigtimedwait() static. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Tejun Heo <tj@kernel.org> Reviewed-by: Matt Fleming <matt.fleming@linux.intel.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/compat.c41
-rw-r--r--kernel/signal.c110
2 files changed, 72 insertions, 79 deletions
diff --git a/kernel/compat.c b/kernel/compat.c
index 06cbb0619531..9214dcd087b7 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -890,10 +890,9 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
890{ 890{
891 compat_sigset_t s32; 891 compat_sigset_t s32;
892 sigset_t s; 892 sigset_t s;
893 int sig;
894 struct timespec t; 893 struct timespec t;
895 siginfo_t info; 894 siginfo_t info;
896 long ret, timeout; 895 long ret;
897 896
898 if (sigsetsize != sizeof(sigset_t)) 897 if (sigsetsize != sizeof(sigset_t))
899 return -EINVAL; 898 return -EINVAL;
@@ -901,45 +900,19 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
901 if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) 900 if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
902 return -EFAULT; 901 return -EFAULT;
903 sigset_from_compat(&s, &s32); 902 sigset_from_compat(&s, &s32);
904 sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP));
905 signotset(&s);
906 903
907 timeout = MAX_SCHEDULE_TIMEOUT;
908 if (uts) { 904 if (uts) {
909 if (get_compat_timespec (&t, uts)) 905 if (get_compat_timespec(&t, uts))
910 return -EFAULT; 906 return -EFAULT;
911 if (!timespec_valid(&t))
912 return -EINVAL;
913 timeout = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
914 } 907 }
915 908
916 spin_lock_irq(&current->sighand->siglock); 909 ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
917 sig = dequeue_signal(current, &s, &info);
918 if (!sig && timeout) {
919 current->real_blocked = current->blocked;
920 sigandsets(&current->blocked, &current->blocked, &s);
921 recalc_sigpending();
922 spin_unlock_irq(&current->sighand->siglock);
923
924 timeout = schedule_timeout_interruptible(timeout);
925
926 spin_lock_irq(&current->sighand->siglock);
927 sig = dequeue_signal(current, &s, &info);
928 current->blocked = current->real_blocked;
929 siginitset(&current->real_blocked, 0);
930 recalc_sigpending();
931 }
932 spin_unlock_irq(&current->sighand->siglock);
933 910
934 if (sig) { 911 if (ret > 0 && uinfo) {
935 ret = sig; 912 if (copy_siginfo_to_user32(uinfo, &info))
936 if (uinfo) { 913 ret = -EFAULT;
937 if (copy_siginfo_to_user32(uinfo, &info))
938 ret = -EFAULT;
939 }
940 } else {
941 ret = timeout?-EINTR:-EAGAIN;
942 } 914 }
915
943 return ret; 916 return ret;
944 917
945} 918}
diff --git a/kernel/signal.c b/kernel/signal.c
index c734619554f6..1ab89f677424 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2504,6 +2504,66 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
2504#endif 2504#endif
2505 2505
2506/** 2506/**
2507 * do_sigtimedwait - wait for queued signals specified in @which
2508 * @which: queued signals to wait for
2509 * @info: if non-null, the signal's siginfo is returned here
2510 * @ts: upper bound on process time suspension
2511 */
2512int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
2513 const struct timespec *ts)
2514{
2515 struct task_struct *tsk = current;
2516 long timeout = MAX_SCHEDULE_TIMEOUT;
2517 sigset_t mask = *which;
2518 int sig;
2519
2520 if (ts) {
2521 if (!timespec_valid(ts))
2522 return -EINVAL;
2523 timeout = timespec_to_jiffies(ts);
2524 /*
2525 * We can be close to the next tick, add another one
2526 * to ensure we will wait at least the time asked for.
2527 */
2528 if (ts->tv_sec || ts->tv_nsec)
2529 timeout++;
2530 }
2531
2532 /*
2533 * Invert the set of allowed signals to get those we want to block.
2534 */
2535 sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
2536 signotset(&mask);
2537
2538 spin_lock_irq(&tsk->sighand->siglock);
2539 sig = dequeue_signal(tsk, &mask, info);
2540 if (!sig && timeout) {
2541 /*
2542 * None ready, temporarily unblock those we're interested
2543 * while we are sleeping in so that we'll be awakened when
2544 * they arrive.
2545 */
2546 tsk->real_blocked = tsk->blocked;
2547 sigandsets(&tsk->blocked, &tsk->blocked, &mask);
2548 recalc_sigpending();
2549 spin_unlock_irq(&tsk->sighand->siglock);
2550
2551 timeout = schedule_timeout_interruptible(timeout);
2552
2553 spin_lock_irq(&tsk->sighand->siglock);
2554 sig = dequeue_signal(tsk, &mask, info);
2555 tsk->blocked = tsk->real_blocked;
2556 siginitset(&tsk->real_blocked, 0);
2557 recalc_sigpending();
2558 }
2559 spin_unlock_irq(&tsk->sighand->siglock);
2560
2561 if (sig)
2562 return sig;
2563 return timeout ? -EINTR : -EAGAIN;
2564}
2565
2566/**
2507 * sys_rt_sigtimedwait - synchronously wait for queued signals specified 2567 * sys_rt_sigtimedwait - synchronously wait for queued signals specified
2508 * in @uthese 2568 * in @uthese
2509 * @uthese: queued signals to wait for 2569 * @uthese: queued signals to wait for
@@ -2515,11 +2575,10 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
2515 siginfo_t __user *, uinfo, const struct timespec __user *, uts, 2575 siginfo_t __user *, uinfo, const struct timespec __user *, uts,
2516 size_t, sigsetsize) 2576 size_t, sigsetsize)
2517{ 2577{
2518 int ret, sig;
2519 sigset_t these; 2578 sigset_t these;
2520 struct timespec ts; 2579 struct timespec ts;
2521 siginfo_t info; 2580 siginfo_t info;
2522 long timeout; 2581 int ret;
2523 2582
2524 /* XXX: Don't preclude handling different sized sigset_t's. */ 2583 /* XXX: Don't preclude handling different sized sigset_t's. */
2525 if (sigsetsize != sizeof(sigset_t)) 2584 if (sigsetsize != sizeof(sigset_t))
@@ -2528,55 +2587,16 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
2528 if (copy_from_user(&these, uthese, sizeof(these))) 2587 if (copy_from_user(&these, uthese, sizeof(these)))
2529 return -EFAULT; 2588 return -EFAULT;
2530 2589
2531 /*
2532 * Invert the set of allowed signals to get those we
2533 * want to block.
2534 */
2535 sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));
2536 signotset(&these);
2537
2538 timeout = MAX_SCHEDULE_TIMEOUT;
2539 if (uts) { 2590 if (uts) {
2540 if (copy_from_user(&ts, uts, sizeof(ts))) 2591 if (copy_from_user(&ts, uts, sizeof(ts)))
2541 return -EFAULT; 2592 return -EFAULT;
2542 if (!timespec_valid(&ts))
2543 return -EINVAL;
2544 timeout = timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec);
2545 } 2593 }
2546 2594
2547 spin_lock_irq(&current->sighand->siglock); 2595 ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL);
2548 sig = dequeue_signal(current, &these, &info);
2549 if (!sig && timeout) {
2550 /*
2551 * None ready -- temporarily unblock those we're
2552 * interested while we are sleeping in so that we'll
2553 * be awakened when they arrive.
2554 */
2555 current->real_blocked = current->blocked;
2556 sigandsets(&current->blocked, &current->blocked, &these);
2557 recalc_sigpending();
2558 spin_unlock_irq(&current->sighand->siglock);
2559
2560 timeout = schedule_timeout_interruptible(timeout);
2561
2562 spin_lock_irq(&current->sighand->siglock);
2563 sig = dequeue_signal(current, &these, &info);
2564 current->blocked = current->real_blocked;
2565 siginitset(&current->real_blocked, 0);
2566 recalc_sigpending();
2567 }
2568 spin_unlock_irq(&current->sighand->siglock);
2569 2596
2570 if (sig) { 2597 if (ret > 0 && uinfo) {
2571 ret = sig; 2598 if (copy_siginfo_to_user(uinfo, &info))
2572 if (uinfo) { 2599 ret = -EFAULT;
2573 if (copy_siginfo_to_user(uinfo, &info))
2574 ret = -EFAULT;
2575 }
2576 } else {
2577 ret = -EAGAIN;
2578 if (timeout)
2579 ret = -EINTR;
2580 } 2600 }
2581 2601
2582 return ret; 2602 return ret;