📄 signal.c
字号:
#endif break; case __SI_CHLD: err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); break; case __SI_RT: /* This is not generated by the kernel as of now. */ case __SI_MESGQ: /* But this is */ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_ptr, &to->si_ptr); break; default: /* this is just in case for now ... */ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; } return err;}#endifasmlinkage longsys_rt_sigtimedwait(const sigset_t __user *uthese, siginfo_t __user *uinfo, const struct timespec __user *uts, size_t sigsetsize){ int ret, sig; sigset_t these; struct timespec ts; siginfo_t info; long timeout = 0; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&these, uthese, sizeof(these))) return -EFAULT; /* * Invert the set of allowed signals to get those we * want to block. */ sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); signotset(&these); if (uts) { if (copy_from_user(&ts, uts, sizeof(ts))) return -EFAULT; if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 || ts.tv_sec < 0) return -EINVAL; } spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); if (!sig) { timeout = MAX_SCHEDULE_TIMEOUT; if (uts) timeout = (timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec)); if (timeout) { /* None ready -- temporarily unblock those we're * interested while we are sleeping in so that we'll * be awakened when they arrive. */ current->real_blocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &these); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); current->blocked = current->real_blocked; siginitset(¤t->real_blocked, 0); recalc_sigpending(); } } spin_unlock_irq(¤t->sighand->siglock); if (sig) { ret = sig; if (uinfo) { if (copy_siginfo_to_user(uinfo, &info)) ret = -EFAULT; } } else { ret = -EAGAIN; if (timeout) ret = -EINTR; } return ret;}asmlinkage longsys_kill(int pid, int sig){ struct siginfo info; info.si_signo = sig; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->tgid; info.si_uid = current->uid; return kill_something_info(sig, &info, pid);}static int do_tkill(int tgid, int pid, int sig){ int error; struct siginfo info; struct task_struct *p; error = -ESRCH; info.si_signo = sig; info.si_errno = 0; info.si_code = SI_TKILL; info.si_pid = current->tgid; info.si_uid = current->uid; read_lock(&tasklist_lock); p = find_task_by_pid(pid); if (p && (tgid <= 0 || p->tgid == tgid)) { error = check_kill_permission(sig, &info, p); /* * The null signal is a permissions and process existence * probe. No signal is actually delivered. */ if (!error && sig && p->sighand) { spin_lock_irq(&p->sighand->siglock); handle_stop_signal(sig, p); error = specific_send_sig_info(sig, &info, p); spin_unlock_irq(&p->sighand->siglock); } } read_unlock(&tasklist_lock); return error;}/** * sys_tgkill - send signal to one specific thread * @tgid: the thread group ID of the thread * @pid: the PID of the thread * @sig: signal to be sent * * This syscall also checks the @tgid and returns -ESRCH even if the PID * exists but it's not belonging to the target process anymore. This * method solves the problem of threads exiting and PIDs getting reused. */asmlinkage long sys_tgkill(int tgid, int pid, int sig){ /* This is only valid for single tasks */ if (pid <= 0 || tgid <= 0) return -EINVAL; return do_tkill(tgid, pid, sig);}/* * Send a signal to only one task, even if it's a CLONE_THREAD task. */asmlinkage longsys_tkill(int pid, int sig){ /* This is only valid for single tasks */ if (pid <= 0) return -EINVAL; return do_tkill(0, pid, sig);}asmlinkage longsys_rt_sigqueueinfo(int pid, int sig, siginfo_t __user *uinfo){ siginfo_t info; if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) return -EFAULT; /* Not even root can pretend to send signals from the kernel. Nor can they impersonate a kill(), which adds source info. */ if (info.si_code >= 0) return -EPERM; info.si_signo = sig; /* POSIX.1b doesn't mention process groups. */ return kill_proc_info(sig, &info, pid);}int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact){ struct k_sigaction *k; sigset_t mask; if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) return -EINVAL; k = ¤t->sighand->action[sig-1]; spin_lock_irq(¤t->sighand->siglock); if (signal_pending(current)) { /* * If there might be a fatal signal pending on multiple * threads, make sure we take it before changing the action. */ spin_unlock_irq(¤t->sighand->siglock); return -ERESTARTNOINTR; } if (oact) *oact = *k; if (act) { sigdelsetmask(&act->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); *k = *act; /* * POSIX 3.3.1.3: * "Setting a signal action to SIG_IGN for a signal that is * pending shall cause the pending signal to be discarded, * whether or not it is blocked." * * "Setting a signal action to SIG_DFL for a signal that is * pending and whose default action is to ignore the signal * (for example, SIGCHLD), shall cause the pending signal to * be discarded, whether or not it is blocked" */ if (act->sa.sa_handler == SIG_IGN || (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) { struct task_struct *t = current; sigemptyset(&mask); sigaddset(&mask, sig); rm_from_queue_full(&mask, &t->signal->shared_pending); do { rm_from_queue_full(&mask, &t->pending); recalc_sigpending_and_wake(t); t = next_thread(t); } while (t != current); } } spin_unlock_irq(¤t->sighand->siglock); return 0;}int do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp){ stack_t oss; int error; if (uoss) { oss.ss_sp = (void __user *) current->sas_ss_sp; oss.ss_size = current->sas_ss_size; oss.ss_flags = sas_ss_flags(sp); } if (uss) { void __user *ss_sp; size_t ss_size; int ss_flags; error = -EFAULT; if (!access_ok(VERIFY_READ, uss, sizeof(*uss)) || __get_user(ss_sp, &uss->ss_sp) || __get_user(ss_flags, &uss->ss_flags) || __get_user(ss_size, &uss->ss_size)) goto out; error = -EPERM; if (on_sig_stack(sp)) goto out; error = -EINVAL; /* * * Note - this code used to test ss_flags incorrectly * old code may have been written using ss_flags==0 * to mean ss_flags==SS_ONSTACK (as this was the only * way that worked) - this fix preserves that older * mechanism */ if (ss_flags != SS_DISABLE && ss_flags != SS_ONSTACK && ss_flags != 0) goto out; if (ss_flags == SS_DISABLE) { ss_size = 0; ss_sp = NULL; } else { error = -ENOMEM; if (ss_size < MINSIGSTKSZ) goto out; } current->sas_ss_sp = (unsigned long) ss_sp; current->sas_ss_size = ss_size; } if (uoss) { error = -EFAULT; if (copy_to_user(uoss, &oss, sizeof(oss))) goto out; } error = 0;out: return error;}#ifdef __ARCH_WANT_SYS_SIGPENDINGasmlinkage longsys_sigpending(old_sigset_t __user *set){ return do_sigpending(set, sizeof(*set));}#endif#ifdef __ARCH_WANT_SYS_SIGPROCMASK/* Some platforms have their own version with special arguments others support only sys_rt_sigprocmask. */asmlinkage longsys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset){ int error; old_sigset_t old_set, new_set; if (set) { error = -EFAULT; if (copy_from_user(&new_set, set, sizeof(*set))) goto out; new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); spin_lock_irq(¤t->sighand->siglock); old_set = current->blocked.sig[0]; error = 0; switch (how) { default: error = -EINVAL; break; case SIG_BLOCK: sigaddsetmask(¤t->blocked, new_set); break; case SIG_UNBLOCK: sigdelsetmask(¤t->blocked, new_set); break; case SIG_SETMASK: current->blocked.sig[0] = new_set; break; } recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (error) goto out; if (oset) goto set_old; } else if (oset) { old_set = current->blocked.sig[0]; set_old: error = -EFAULT; if (copy_to_user(oset, &old_set, sizeof(*oset))) goto out; } error = 0;out: return error;}#endif /* __ARCH_WANT_SYS_SIGPROCMASK */#ifdef __ARCH_WANT_SYS_RT_SIGACTIONasmlinkage longsys_rt_sigaction(int sig, const struct sigaction __user *act, struct sigaction __user *oact, size_t sigsetsize){ struct k_sigaction new_sa, old_sa; int ret = -EINVAL; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) goto out; if (act) { if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) return -EFAULT; } ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); if (!ret && oact) { if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) return -EFAULT; }out: return ret;}#endif /* __ARCH_WANT_SYS_RT_SIGACTION */#ifdef __ARCH_WANT_SYS_SGETMASK/* * For backwards compatibility. Functionality superseded by sigprocmask. */asmlinkage longsys_sgetmask(void){ /* SMP safe */ return current->blocked.sig[0];}asmlinkage longsys_ssetmask(int newmask){ int old; spin_lock_irq(¤t->sighand->siglock); old = current->blocked.sig[0]; siginitset(¤t->blocked, newmask & ~(sigmask(SIGKILL)| sigmask(SIGSTOP))); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); return old;}#endif /* __ARCH_WANT_SGETMASK */#ifdef __ARCH_WANT_SYS_SIGNAL/* * For backwards compatibility. Functionality superseded by sigaction. */asmlinkage unsigned longsys_signal(int sig, __sighandler_t handler){ struct k_sigaction new_sa, old_sa; int ret; new_sa.sa.sa_handler = handler; new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; sigemptyset(&new_sa.sa.sa_mask); ret = do_sigaction(sig, &new_sa, &old_sa); return ret ? ret : (unsigned long)old_sa.sa.sa_handler;}#endif /* __ARCH_WANT_SYS_SIGNAL */#ifdef __ARCH_WANT_SYS_PAUSEasmlinkage longsys_pause(void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}#endif#ifdef __ARCH_WANT_SYS_RT_SIGSUSPENDasmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize){ sigset_t newset; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); set_thread_flag(TIF_RESTORE_SIGMASK); return -ERESTARTNOHAND;}#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma){ return NULL;}void __init signals_init(void){ sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -