Signal Value Action Comment──────────────────────────────────────────────────────────────────────SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling processSIGINT 2 Term Interrupt from keyboardSIGQUIT 3 Core Quit from keyboardSIGILL 4 Core Illegal InstructionSIGABRT 6 Core Abort signal from abort(3)SIGFPE 8 Core Floating point exceptionSIGKILL 9 Term Kill signalSIGSEGV 11 Core Invalid memory referenceSIGPIPE 13 Term Broken pipe: write to pipe with no readersSIGALRM 14 Term Timer signal from alarm(2)SIGTERM 15 Term Termination signalSIGUSR1 30,10,16 Term User-defined signal 1SIGUSR2 31,12,17 Term User-defined signal 2……
intdo_send_sig_info(int sig,struct kernel_siginfo *info,struct task_struct *p,enum pid_type type){...... ret =send_signal(sig, info, p, type);......}staticintsend_signal(int sig,struct kernel_siginfo *info,struct task_struct *t,enum pid_type type){......return__send_signal(sig, info, t, type, from_ancestor_ns);}staticint__send_signal(int sig,struct kernel_siginfo *info,struct task_struct *t,enum pid_type type,int from_ancestor_ns){struct sigpending *pending;struct sigqueue *q;...... pending = (type != PIDTYPE_PID) ?&t->signal->shared_pending :&t->pending;......if (legacy_queue(pending, sig))goto ret;...... /* * Real-time signals must be queued if sent by sigqueue, or * some other real-time mechanism. It is implementation * defined whether kill() does so. We attempt to do so, on * the principle of least surprise, but since kill is not * allowed to fail with EAGAIN when low on memory we just * make sure at least one signal gets delivered and don't * pass on the info struct. */if (sig < SIGRTMIN) override_rlimit = (is_si_special(info)||info->si_code >=0);else override_rlimit =0; q =__sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit);if (q) {list_add_tail(&q->list,&pending->list);switch ((unsignedlong) info) {case (unsignedlong) SEND_SIG_NOINFO:clear_siginfo(&q->info);q->info.si_signo = sig;q->info.si_errno =0;q->info.si_code = SI_USER;q->info.si_pid =task_tgid_nr_ns(current,task_active_pid_ns(t));q->info.si_uid =from_kuid_munged(current_user_ns(),current_uid());break;case (unsignedlong) SEND_SIG_PRIV:clear_siginfo(&q->info);q->info.si_signo = sig;q->info.si_errno =0;q->info.si_code = SI_KERNEL;q->info.si_pid =0;q->info.si_uid =0;break;default:copy_siginfo(&q->info, info);if (from_ancestor_ns)q->info.si_pid =0;break; }userns_fixup_signal_uid(&q->info, t); }......out_set:signalfd_notify(t, sig);sigaddset(&pending->signal, sig);......complete_signal(sig, t, type);ret:trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result);return ret;}
staticvoidcomplete_signal(int sig,struct task_struct *p,enum pid_type type){struct signal_struct *signal =p->signal;struct task_struct *t; /* * Now find a thread we can wake up to take the signal off the queue. * * If the main thread wants the signal, it gets first crack. * Probably the least surprising to the average bear. */if (wants_signal(sig, p)) t = p;elseif ((type == PIDTYPE_PID) ||thread_group_empty(p)) /* * There is just one thread and it does not need to be woken. * It will dequeue unblocked signals before it runs again. */return;else { /* * Otherwise try to find a suitable thread. */ t =signal->curr_target;while (!wants_signal(sig, t)) { t =next_thread(t);if (t ==signal->curr_target) /* * No thread needs to be woken. * Any eligible threads will see * the signal in the queue soon. */return; }signal->curr_target = t; } /* * Found a killable thread. If the signal will be fatal, * then start taking the whole group down immediately. */if (sig_fatal(p, sig)&&!(signal->flags & SIGNAL_GROUP_EXIT) &&!sigismember(&t->real_blocked, sig)&& (sig == SIGKILL ||!p->ptrace)) { /* * This signal will be fatal to the whole group. */if (!sig_kernel_coredump(sig)) { /* * Start a group exit and wake everybody up. * This way we don't have other threads * running and doing things after a slower * thread has the fatal signal pending. */signal->flags = SIGNAL_GROUP_EXIT;signal->group_exit_code = sig;signal->group_stop_count =0; t = p;do {task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK);sigaddset(&t->pending.signal, SIGKILL);signal_wake_up(t,1); } while_each_thread(p, t);return; } } /* * The signal is already in the shared-pending queue. * Tell the chosen thread to wake up and dequeue it. */signal_wake_up(t, sig == SIGKILL);return;}
staticinlinevoidsignal_wake_up(struct task_struct *t,bool resume){signal_wake_up_state(t, resume ? TASK_WAKEKILL :0);}voidsignal_wake_up_state(struct task_struct *t,unsignedint state){set_tsk_thread_flag(t, TIF_SIGPENDING); /* * TASK_WAKEKILL also means wake it up in the stopped/traced/killable * case. We don't check t->state here because there is a race with it * executing another processor and just now entering stopped state. * By using wake_up_state, we ensure the process will wake up and * handle its death signal. */if (!wake_up_state(t, state | TASK_INTERRUPTIBLE))kick_process(t);}
/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */voiddo_signal(struct pt_regs *regs){struct ksignal ksig;if (get_signal(&ksig)) { /* Whee! Actually deliver the signal. */handle_signal(&ksig, regs);return; } /* Did we come from a system call? */if (syscall_get_nr(current, regs)>=0) { /* Restart the system call - no handlers present */switch (syscall_get_error(current, regs)) {case-ERESTARTNOHAND:case-ERESTARTSYS:case-ERESTARTNOINTR:regs->ax =regs->orig_ax;regs->ip -=2;break;case-ERESTART_RESTARTBLOCK:regs->ax =get_nr_restart_syscall(regs);regs->ip -=2;break; } } /* * If there's no signal to deliver, we just put the saved sigmask * back. */restore_saved_sigmask();}
staticintsetup_rt_frame(struct ksignal *ksig,struct pt_regs *regs){......return__setup_rt_frame(ksig->sig, ksig, set, regs);......}staticint__setup_rt_frame(int sig,struct ksignal *ksig,sigset_t*set,struct pt_regs *regs){struct rt_sigframe __user *frame;void __user *fp =NULL;int err =0; frame =get_sigframe(&ksig->ka, regs,sizeof(struct rt_sigframe),&fp);...... put_user_try {...... /* Set up to return from userspace. If provided, use a stub already in userspace. */ /* x86-64 should always use SA_RESTORER. */if (ksig->ka.sa.sa_flags & SA_RESTORER) {put_user_ex(ksig->ka.sa.sa_restorer,&frame->pretcode); } else { /* could use a vstub here */ err |=-EFAULT; } } put_user_catch(err); err |=setup_sigcontext(&frame->uc.uc_mcontext, fp, regs,set->sig[0]); err |=__copy_to_user(&frame->uc.uc_sigmask, set,sizeof(*set));if (err)return-EFAULT; /* Set up registers for signal handler */regs->di = sig; /* In case the signal handler was declared without prototypes */regs->ax =0; /* This also works for non SA_SIGINFO handlers because they expect the next argument after the signal number on the stack. */regs->si = (unsignedlong)&frame->info;regs->dx = (unsignedlong)&frame->uc;regs->ip = (unsignedlong) ksig->ka.sa.sa_handler;regs->sp = (unsignedlong)frame; /* * Set up the CS and SS registers to run signal handlers in * 64-bit mode, even if the handler happens to be interrupting * 32-bit or 16-bit code. * * SS is subtle. In 64-bit mode, we don't need any particular * SS descriptor, but we do need SS to be valid. It's possible * that the old SS is entirely bogus -- this can happen if the * signal we're trying to deliver is #GP or #SS caused by a bad * SS value. We also have a compatbility issue here: DOSEMU * relies on the contents of the SS register indicating the * SS value at the time of the signal, even though that code in * DOSEMU predates sigreturn's ability to restore SS. (DOSEMU * avoids relying on sigreturn to restore SS; instead it uses * a trampoline.) So we do our best: if the old SS was valid, * we keep it. Otherwise we replace it. */regs->cs = __USER_CS;if (unlikely(regs->ss != __USER_DS))force_valid_ss(regs);return0;}
asmlinkage intsys_rt_sigreturn(struct pt_regs *regs){struct rt_sigframe __user *frame; /* Always make any pending restarted system calls return -EINTR */current->restart_block.fn = do_no_restart_syscall; /* * Since we stacked the signal on a 64-bit boundary, * then 'sp' should be word aligned here. If it's * not, then the user is trying to mess with us. */if (regs->ARM_sp &7)goto badframe; frame = (struct rt_sigframe __user *)regs->ARM_sp;if (!access_ok(frame,sizeof (*frame)))goto badframe;if (restore_sigframe(regs,&frame->sig))goto badframe;if (restore_altstack(&frame->sig.uc.uc_stack))goto badframe;returnregs->ARM_r0;badframe:force_sig(SIGSEGV, current);return0;}
总结
信号的发送与处理是一个复杂的过程,这里来总结一下。
假设我们有一个进程 A会从tap 网卡中读取数据,main 函数里面调用系统调用通过中断陷入内核。
按照系统调用的原理,将用户态栈的信息保存在 pt_regs 里面,也即记住原来用户态是运行到了 line A 的地方。