Commit 943df1485a8ff0e600729e082e568ece04d4de9e

Authored by Oleg Nesterov
1 parent fe0faa005d

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>

Showing 3 changed files with 74 additions and 79 deletions Side-by-side Diff

include/linux/signal.h
... ... @@ -242,6 +242,8 @@
242 242 extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig,
243 243 siginfo_t *info);
244 244 extern long do_sigpending(void __user *, unsigned long);
  245 +extern int do_sigtimedwait(const sigset_t *, siginfo_t *,
  246 + const struct timespec *);
245 247 extern int sigprocmask(int, sigset_t *, sigset_t *);
246 248 extern void set_current_blocked(const sigset_t *);
247 249 extern int show_unhandled_signals;
... ... @@ -890,10 +890,9 @@
890 890 {
891 891 compat_sigset_t s32;
892 892 sigset_t s;
893   - int sig;
894 893 struct timespec t;
895 894 siginfo_t info;
896   - long ret, timeout;
  895 + long ret;
897 896  
898 897 if (sigsetsize != sizeof(sigset_t))
899 898 return -EINVAL;
900 899  
901 900  
902 901  
903 902  
904 903  
905 904  
906 905  
... ... @@ -901,45 +900,19 @@
901 900 if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
902 901 return -EFAULT;
903 902 sigset_from_compat(&s, &s32);
904   - sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP));
905   - signotset(&s);
906 903  
907   - timeout = MAX_SCHEDULE_TIMEOUT;
908 904 if (uts) {
909   - if (get_compat_timespec (&t, uts))
  905 + if (get_compat_timespec(&t, uts))
910 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);
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);
  909 + ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
923 910  
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();
  911 + if (ret > 0 && uinfo) {
  912 + if (copy_siginfo_to_user32(uinfo, &info))
  913 + ret = -EFAULT;
931 914 }
932   - spin_unlock_irq(&current->sighand->siglock);
933 915  
934   - if (sig) {
935   - ret = sig;
936   - if (uinfo) {
937   - if (copy_siginfo_to_user32(uinfo, &info))
938   - ret = -EFAULT;
939   - }
940   - } else {
941   - ret = timeout?-EINTR:-EAGAIN;
942   - }
943 916 return ret;
944 917  
945 918 }
... ... @@ -2504,6 +2504,66 @@
2504 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 2567 * sys_rt_sigtimedwait - synchronously wait for queued signals specified
2508 2568 * in @uthese
2509 2569 * @uthese: queued signals to wait for
2510 2570  
... ... @@ -2515,11 +2575,10 @@
2515 2575 siginfo_t __user *, uinfo, const struct timespec __user *, uts,
2516 2576 size_t, sigsetsize)
2517 2577 {
2518   - int ret, sig;
2519 2578 sigset_t these;
2520 2579 struct timespec ts;
2521 2580 siginfo_t info;
2522   - long timeout;
  2581 + int ret;
2523 2582  
2524 2583 /* XXX: Don't preclude handling different sized sigset_t's. */
2525 2584 if (sigsetsize != sizeof(sigset_t))
2526 2585  
2527 2586  
2528 2587  
... ... @@ -2528,55 +2587,16 @@
2528 2587 if (copy_from_user(&these, uthese, sizeof(these)))
2529 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 2590 if (uts) {
2540 2591 if (copy_from_user(&ts, uts, sizeof(ts)))
2541 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);
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);
  2595 + ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL);
2559 2596  
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   -
2570   - if (sig) {
2571   - ret = sig;
2572   - if (uinfo) {
2573   - if (copy_siginfo_to_user(uinfo, &info))
2574   - ret = -EFAULT;
2575   - }
2576   - } else {
2577   - ret = -EAGAIN;
2578   - if (timeout)
2579   - ret = -EINTR;
  2597 + if (ret > 0 && uinfo) {
  2598 + if (copy_siginfo_to_user(uinfo, &info))
  2599 + ret = -EFAULT;
2580 2600 }
2581 2601  
2582 2602 return ret;