日期:2014-05-16 浏览次数:20774 次
linux内核中的信号机制--信号处理
Kernel version:2.6.14
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
当进程被调度时,会调用do_notify_resume()来处理信号队列中的信号。信号处理主要就是调用sighand_struct结构中对应的信号处理函数。do_notify_resume()(arch/arm/kernel/signal.c)函数的定义如下:
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) { if (thread_flags & _TIF_SIGPENDING) do_signal(¤t->blocked, regs, syscall); }_TIF_SIGPENDING标志是在signal_wake_up()函数中设置的,检查该标志后,接下来就调用do_signal()函数,我们来看看do_signal()(arch/arm/kernel/signal.c)的具体定义:
/* * 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. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) { struct k_sigaction ka; siginfo_t info; int signr; /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (!user_mode(regs))//regs保存的是进入内核态之前的寄存器现场,必须为用户模式,否则直接返回 return 0; if (try_to_freeze()) goto no_signal; if (current->ptrace & PT_SINGLESTEP) ptrace_cancel_bpt(current);//和调试相关,我们在后面的文章中会具体分析 signr = get_signal_to_deliver(&info, &ka, regs, NULL);//取出等待处理的信号 if (signr > 0) { handle_signal(signr, &ka, &info, oldset, regs, syscall);//处理信号 if (current->ptrace & PT_SINGLESTEP) ptrace_set_bpt(current); return 1; } no_signal: /* * No signal to deliver to the process - restart the syscall. */ if (syscall) { if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { if (thumb_mode(regs)) { regs->ARM_r7 = __NR_restart_syscall; regs->ARM_pc -= 2; } else { u32 __user *usp; regs->ARM_sp -= 12; usp = (u32 __user *)regs->ARM_sp; put_user(regs->ARM_pc, &usp[0]); /* swi __NR_restart_syscall */ put_user(0xef000000 | __NR_restart_syscall, &usp[1]); /* ldr pc, [sp], #12 */ put_user(0xe49df00c, &usp[2]); flush_icache_range((unsigned long)usp, (unsigned long)(usp + 3)); regs->ARM_pc = regs->ARM_sp + 4; } } if (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTA