diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-04-27 15:44:14 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2011-04-28 07:01:38 -0400 |
commit | 943df1485a8ff0e600729e082e568ece04d4de9e (patch) | |
tree | d2d4b7b41f163e011cb7a373376c9ae87e5941be /kernel | |
parent | fe0faa005d43bc44c357631d51c273806086caa4 (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.c | 41 | ||||
-rw-r--r-- | kernel/signal.c | 110 |
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(¤t->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(¤t->blocked, ¤t->blocked, &s); | ||
921 | recalc_sigpending(); | ||
922 | spin_unlock_irq(¤t->sighand->siglock); | ||
923 | |||
924 | timeout = schedule_timeout_interruptible(timeout); | ||
925 | |||
926 | spin_lock_irq(¤t->sighand->siglock); | ||
927 | sig = dequeue_signal(current, &s, &info); | ||
928 | current->blocked = current->real_blocked; | ||
929 | siginitset(¤t->real_blocked, 0); | ||
930 | recalc_sigpending(); | ||
931 | } | ||
932 | spin_unlock_irq(¤t->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 | */ | ||
2512 | int 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(¤t->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(¤t->blocked, ¤t->blocked, &these); | ||
2557 | recalc_sigpending(); | ||
2558 | spin_unlock_irq(¤t->sighand->siglock); | ||
2559 | |||
2560 | timeout = schedule_timeout_interruptible(timeout); | ||
2561 | |||
2562 | spin_lock_irq(¤t->sighand->siglock); | ||
2563 | sig = dequeue_signal(current, &these, &info); | ||
2564 | current->blocked = current->real_blocked; | ||
2565 | siginitset(¤t->real_blocked, 0); | ||
2566 | recalc_sigpending(); | ||
2567 | } | ||
2568 | spin_unlock_irq(¤t->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; |