Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493095
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-11-02 08:28:05

传递及捕获信号

该函数在返回用户态时才会被调用

  1. static void fastcall do_signal(struct pt_regs *reg)
  2. {
  3.     siginfo_t info;
  4.     int signr;
  5.     struct k_sigaction ka;
  6.     sigset_t *oldset;
  7.     if(!user_mode(regs))    
  8.         return;
  9.     //修复信号栈,保存阻塞信号的位掩码
  10.     if(test_thread_flags(TIF_RESTORE_SIGMASK))
  11.         oldset = &current->saved_sigmask;
  12.     else
  13.         oldset = &current->blocked;
  14.     //获取信号的处理函数
  15.     signr = get_signal_to_deliver(&info,&ka,regs,NULL);
  16.     if(signr > 0) {
  17.         if(unlikely(current->thread.debugreg[7]))
  18.             set_debugreg(current->thread.debugreg[7],7);
  19.         //具体调用信号处理函数执行
  20.         if(handle_signal(signr,&info,&ka,oldset,regs) == 0)
  21.         {
  22.             if(test_thread_flag(TIF_RESOTRE_SIGMASK))
  23.                 clear_thread_flag(TIF_RESTORE_SIGMASK);
  24.         }
  25.         return;
  26.     }
  27.     if(regs->orig_eax >= 0) {
  28.         switch(regs->eax) {
  29.             case -ERESTARTNOHAND:
  30.             case -ERESTARTSYS:
  31.             case -ERESTARTNOINTR:
  32.                 regs->eax = regs->orig_eax;
  33.                 regs->eip -= 2;
  34.             break;
  35.             case -ERESTART_RESTARTBLOCK:
  36.                 regs->eax = __NR_restart_syscall;//对该系统调用进行重启
  37.                 regs->eip -= 2;
  38.                 break;
  39.         }
  40.     }
  41.     if(test_thread_flag(TIF_RESTORE_SIGMASK)) {
  42.         clear_thread_flag(TIF_RESTORE_SIGMASK);
  43.         sigprocmask(SIG_SETMASK,&current->saved_sigmask,NULL);
  44.     }
  45. }

get_signal_to_deliver源代码如下:

  1. int get_signal_to_deliver(siginfo_t *info,struct k_sigaction *return_ka,struct pt_regs *regs,void *cookie)
  2. {
  3.     …..
  4. relock:
  5.     spin_lock_irq(&current->sighand->siglock);
  6.     for(;;)
  7.     {
  8.         struct k_sigaction *ka;
  9.         if(unlikely(current->signal->group_stop_count > 0)
  10.             && handle_group_stop())
  11.             goto relock;
  12.         //从私有悬挂队列或共享队列中摘下一个信号
  13.         signr = dequeue_signal(current,mask,info);
  14.         if(signr) break;
  15.         …....
  16.         ka = &current->sighand->action[signr-1];
  17.          if(ka->sa.sa_handler == SIG_IGN)//如果信号被忽略,直接丢弃
  18.             continue;
  19.         if(ka->sa.sa_handler != SIG_DFL)//返回该信号的处理函数
  20.         {
  21.             *return_ka = *ka;
  22.             if(ka->sa.sa_flags & SA_ONESHOT)
  23.                 ka->sa.sa_handler = SIG_DFL;
  24.             break;
  25.         }
  26.         //接受进程为其他进程,但为内核缺省进程,主要
  27.         //:SIGCONT,SIGCHILD,SIGWINCH,SIGURG
  28.         if(sig_kernel_ignore(signr))
  29.             continue;
  30.         //如果接受进程为init时
  31.         if(is_global_init(current))
  32.             continue;
  33.         //信号为:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
  34.         //SIGSTOP:发送进程停止信号(不能捕获或忽略)
  35.         //SIGTSTP:交互式停止信号
  36.         //SIGTTIN/SIGTTOU:后台进程组的进程从终端读/写内容
  37.         if(sig_kernel_stop(signr)) {
  38.             if(signr != SIGSTOP) {
  39.                 spin_unlock_irq(&current->sighand->siglock);
  40.                 //只要和父进程处于同一回话中就不为孤儿进程
  41.                 if(is_current_pgrp_orphaned())
  42.                     goto relock;
  43.                 spin_lock_irq(&current->sighand->siglock);
  44.             }
  45.         //停止整个线程组    
  46.         if(likely(do_signal_stop(signr))) {
  47.             goto relock;
  48.         }
  49.         continue;
  50.         }
  51.         .....
  52.         }}

系统调用的重新执行

如果进程处于TASK_INTERRUPTIBLE状态,并且某个进程向它发送了一个信号,那么内核不完成系统调用就把进程设置为TASK_RUNNING状态,当切换回用户态时信号被传递给进程.当出现这种情况,系统没有完成它的工作,但返回EINTR,ERESTARTNOHAND,

ERESTART_RESTARTBLOCK,ERESTARTSYSERESTARTNOINTR错误码

  1. static int handle_signal(unsigned long sig,siginfo_t *info,
  2.     struct k_sigaction *ka,sigset_t *oldset,struct pt_regs *regs)
  3. {
  4.     int ret;
  5.     //在最初系统调用时,eax保存系统调用号,执行完成返回系统调用结果
  6.     if(regs->orig_eax >=0) {
  7.         switch(regs->eax) {//根据系统调用返回结果,进行重启调用前的恢复
  8.             case -ERESTART_RESTARTBLOCK:
  9.             case -ERESTARTNOHAND:
  10.                 regs->eax = -EINTR;
  11.                 break;
  12.             case -ERESTARTSYS:
  13.                 if(!(ka->sa.sa_flags & SA_RESTART)) {
  14.                     regs->eax = -EINTR;
  15.                     break;
  16.                 }
  17.             case -ERESTARTNOINTR:
  18.                 regs->eax = regs->orig_eax;
  19.                 regs->eip -= 2;
  20.         }
  21.     }
  22.     …...
  23.     //创建用户态调用栈
  24.     if(ka->sa.sa_flags & SA_SIGINFO)
  25.         ret = setup_rt_frame(sig,ka,info,oldset,regs);
  26.     else ret = setup_frame(sig,ka,oldset,,regs);
  27.     if(ret == 0) {
  28.         spin_lock_irq(&current->sighand->siglock);
  29.         sigorsets(&current->blocked,&current->blocked,
  30.             &ka->sa.sa_mask);
  31.         if(!(ka->sa.sa_flags & SA_NODEFER))
  32.             sigaddset(&current->blocked,sig);
  33.         recalc_sigpending();
  34.         spin_unlock_irq(&current->sighand->siglock);
  35.     }
  36.     return ret;
  37. }

参考资料

1.linux-2.24.3内核源码

2.深入理解Linux内核(第三版)

3.APUE

阅读(1976) | 评论(0) | 转发(0) |
0

上一篇:进程与信号(二)

下一篇:Linux中的等待队列

给主人留下些什么吧!~~