📄 signal.c
字号:
}inline intkill_proc_info(int sig, struct siginfo *info, pid_t pid){ int error; struct task_struct *p; read_lock(&tasklist_lock); p = find_task_by_pid(pid); error = -ESRCH; if (p) error = send_sig_info(sig, info, p); read_unlock(&tasklist_lock); return error;}/* * kill_something_info() interprets pid in interesting ways just like kill(2). * * POSIX specifies that kill(-1,sig) is unspecified, but what we have * is probably wrong. Should make it like BSD or SYSV. */static int kill_something_info(int sig, struct siginfo *info, int pid){ if (!pid) { return kill_pg_info(sig, info, current->pgrp); } else if (pid == -1) { int retval = 0, count = 0; struct task_struct * p; read_lock(&tasklist_lock); for_each_task(p) { if (p->pid > 1 && p != current) { int err = send_sig_info(sig, info, p); ++count; if (err != -EPERM) retval = err; } } read_unlock(&tasklist_lock); return count ? retval : -ESRCH; } else if (pid < 0) { return kill_pg_info(sig, info, -pid); } else { return kill_proc_info(sig, info, pid); }}/* * These are for backward compatibility with the rest of the kernel source. */intsend_sig(int sig, struct task_struct *p, int priv){ return send_sig_info(sig, (void*)(long)(priv != 0), p);}voidforce_sig(int sig, struct task_struct *p){ force_sig_info(sig, (void*)1L, p);}intkill_pg(pid_t pgrp, int sig, int priv){ return kill_pg_info(sig, (void *)(long)(priv != 0), pgrp);}intkill_sl(pid_t sess, int sig, int priv){ return kill_sl_info(sig, (void *)(long)(priv != 0), sess);}intkill_proc(pid_t pid, int sig, int priv){ return kill_proc_info(sig, (void *)(long)(priv != 0), pid);}/* * Joy. Or not. Pthread wants us to wake up every thread * in our parent group. */static void wake_up_parent(struct task_struct *parent){ struct task_struct *tsk = parent; do { wake_up_interruptible(&tsk->wait_chldexit); tsk = next_thread(tsk); } while (tsk != parent);}/* * Let a parent know about a status change of a child. */void do_notify_parent(struct task_struct *tsk, int sig){ struct siginfo info; int why, status; info.si_signo = sig; info.si_errno = 0; info.si_pid = tsk->pid; info.si_uid = tsk->uid; /* FIXME: find out whether or not this is supposed to be c*time. */ info.si_utime = hz_to_std(tsk->times.tms_utime); info.si_stime = hz_to_std(tsk->times.tms_stime); status = tsk->exit_code & 0x7f; why = SI_KERNEL; /* shouldn't happen */ switch (tsk->state) { case TASK_STOPPED: /* FIXME -- can we deduce CLD_TRAPPED or CLD_CONTINUED? */ if (tsk->ptrace & PT_PTRACED) why = CLD_TRAPPED; else why = CLD_STOPPED; break; default: if (tsk->exit_code & 0x80) why = CLD_DUMPED; else if (tsk->exit_code & 0x7f) why = CLD_KILLED; else { why = CLD_EXITED; status = tsk->exit_code >> 8; } break; } info.si_code = why; info.si_status = status; send_sig_info(sig, &info, tsk->p_pptr); wake_up_parent(tsk->p_pptr);}/* * We need the tasklist lock because it's the only * thing that protects out "parent" pointer. * * exit.c calls "do_notify_parent()" directly, because * it already has the tasklist lock. */voidnotify_parent(struct task_struct *tsk, int sig){ read_lock(&tasklist_lock); do_notify_parent(tsk, sig); read_unlock(&tasklist_lock);}EXPORT_SYMBOL(dequeue_signal);EXPORT_SYMBOL(flush_signals);EXPORT_SYMBOL(force_sig);EXPORT_SYMBOL(force_sig_info);EXPORT_SYMBOL(kill_pg);EXPORT_SYMBOL(kill_pg_info);EXPORT_SYMBOL(kill_proc);EXPORT_SYMBOL(kill_proc_info);EXPORT_SYMBOL(kill_sl);EXPORT_SYMBOL(kill_sl_info);EXPORT_SYMBOL(notify_parent);EXPORT_SYMBOL(recalc_sigpending);EXPORT_SYMBOL(send_sig);EXPORT_SYMBOL(send_sig_info);EXPORT_SYMBOL(block_all_signals);EXPORT_SYMBOL(unblock_all_signals);/* * System call entry points. *//* * We don't need to get the kernel lock - this is all local to this * particular thread.. (and that's good, because this is _heavily_ * used by various programs) */asmlinkage longsys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize){ int error = -EINVAL; sigset_t old_set, new_set; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) goto out; if (set) { error = -EFAULT; if (copy_from_user(&new_set, set, sizeof(*set))) goto out; sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); spin_lock_irq(¤t->sigmask_lock); old_set = current->blocked; error = 0; switch (how) { default: error = -EINVAL; break; case SIG_BLOCK: sigorsets(&new_set, &old_set, &new_set); break; case SIG_UNBLOCK: signandsets(&new_set, &old_set, &new_set); break; case SIG_SETMASK: break; } current->blocked = new_set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (error) goto out; if (oset) goto set_old; } else if (oset) { spin_lock_irq(¤t->sigmask_lock); old_set = current->blocked; spin_unlock_irq(¤t->sigmask_lock); set_old: error = -EFAULT; if (copy_to_user(oset, &old_set, sizeof(*oset))) goto out; } error = 0;out: return error;}long do_sigpending(void *set, unsigned long sigsetsize){ long error = -EINVAL; sigset_t pending; if (sigsetsize > sizeof(sigset_t)) goto out; spin_lock_irq(¤t->sigmask_lock); sigandsets(&pending, ¤t->blocked, ¤t->pending.signal); spin_unlock_irq(¤t->sigmask_lock); error = -EFAULT; if (!copy_to_user(set, &pending, sigsetsize)) error = 0;out: return error;} asmlinkage longsys_rt_sigpending(sigset_t *set, size_t sigsetsize){ return do_sigpending(set, sigsetsize);}asmlinkage longsys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *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->sigmask_lock); sig = dequeue_signal(&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. */ sigset_t oldblocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &these); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); current->state = TASK_INTERRUPTIBLE; timeout = schedule_timeout(timeout); spin_lock_irq(¤t->sigmask_lock); sig = dequeue_signal(&these, &info); current->blocked = oldblocked; recalc_sigpending(current); } } spin_unlock_irq(¤t->sigmask_lock); 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->pid; info.si_uid = current->uid; return kill_something_info(sig, &info, pid);}asmlinkage longsys_rt_sigqueueinfo(int pid, int sig, siginfo_t *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);}intdo_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact){ struct k_sigaction *k; if (sig < 1 || sig > _NSIG || (act && (sig == SIGKILL || sig == SIGSTOP))) return -EINVAL; k = ¤t->sig->action[sig-1]; spin_lock(¤t->sig->siglock); if (oact) *oact = *k; if (act) { *k = *act; sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); /* * 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" * * Note the silly behaviour of SIGCHLD: SIG_IGN means that the * signal isn't actually ignored, but does automatic child * reaping, while SIG_DFL is explicitly said by POSIX to force * the signal to be ignored. */ if (k->sa.sa_handler == SIG_IGN || (k->sa.sa_handler == SIG_DFL && (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH))) { spin_lock_irq(¤t->sigmask_lock); if (rm_sig_from_queue(sig, current)) recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } } spin_unlock(¤t->sig->siglock); return 0;}int do_sigaltstack (const stack_t *uss, stack_t *uoss, unsigned long sp){ stack_t oss; int error; if (uoss) { oss.ss_sp = (void *) current->sas_ss_sp; oss.ss_size = current->sas_ss_size; oss.ss_flags = sas_ss_flags(sp); } if (uss) { void *ss_sp; size_t ss_size; int ss_flags; error = -EFAULT; if (verify_area(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;}asmlinkage longsys_sigpending(old_sigset_t *set){ return do_sigpending(set, sizeof(*set));}#if !defined(__alpha__)/* Alpha has its own versions with special arguments. */asmlinkage longsys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *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->sigmask_lock); 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(current); spin_unlock_irq(¤t->sigmask_lock); 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;}#ifndef __sparc__asmlinkage longsys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *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 /* __sparc__ */#endif#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__)/* * 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->sigmask_lock); old = current->blocked.sig[0]; siginitset(¤t->blocked, newmask & ~(sigmask(SIGKILL)| sigmask(SIGSTOP))); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return old;}#endif /* !defined(__alpha__) */#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && \ !defined(__arm__)/* * 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; ret = do_sigaction(sig, &new_sa, &old_sa); return ret ? ret : (unsigned long)old_sa.sa.sa_handler;}#endif /* !alpha && !__ia64__ && !defined(__mips__) && !defined(__arm__) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -