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

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-11-02 08:22:52

信号产生

当进程产生信号时,调用函数specific_send_sig_info函数来向指定的进程发送信号,原型如下:

  1. static int
  2. specific_send_sig_info(int sig,struct siginfo *info,struct task_struct *t)
  3. {
  4.     int ret = 0;
  5.     //必须关中断,获取该进程处理的自旋锁
  6.     BUG_ON(!irqs_disabled());
  7.     assert_spin_locked(&t->sighand->siglock);
  8.     //如果忽略信号直接返回
  9.     if(sig_ignored(t,sig))
  10.         goto out;
  11.     //非实时信号且挂起队列中已存在该信号未被处理,就直接返回
  12.     if(LEAGCY_QUEUE(&t->pending,sig))
  13.         goto out;
  14.     //否则直接发送到该进程的挂起队列中
  15.     ret = send_signal(sig,info,t,&t->pending)
  16.     //信号没有被阻塞,则唤醒该进程
  17.     if(!ret && !sigismember(&t->blocked,sig))
  18.         signal_wake_up(t,sig==SIGKILL);
  19. out:
  20.     return ret;
  21. }

send_signal函数定义如下:

  1. //send_signal(sig,info,t,&t->pendings)
  2. static int send_signal(int sig,struct siginfo *info,struct task_struct *t,
  3.             struct sigpending *signals)
  4. {
  5.     struct sigqueue *q = NULL;
  6.     int ret = 0;
  7.     signalfd_notify(t,sig);
  8.     //如果是SIGKILL或SIGSTOP信号则不用添加至队列,
  9.     //内核会强制执行与这些信号相关的操作
  10.     if(info == SEND_SIG_FORCED)
  11.         goto out_set;
  12.     //否则开始分配空间,进行初始化数据结构,添加到队列上
  13.     //增加用户悬挂信号的个数,判断创建信号的个数是否超出限制,分配内存等等
  14.     q = __sigqueue_alloc(t,GFP_ATOMIC,(sig<SIGRTMIN
  15.             && is_si_special(info)|| info->si_code>=0));
  16.     if(q) {
  17.         list_add_tail(&q->list,&signals->list);
  18.         switch((unsigned long)info) {
  19.             case (unsigned long)SEND_SIG_NOINFO://用户态进程发送的信号
  20.             q->info.si_signo = sig;
  21.             q->info.si_errno = 0;
  22.             q->info.si_code = SI_USER;
  23.             q->info.si_pid = task_pid_vnr(current);
  24.             q->info.si_uid = current->tid;
  25.             break;
  26.         case (unsigned long) SEND_SIG_PRIV://内核态进程发送的信号
  27.             q->info.si_signo = sig;
  28.             q->info.si_errno = 0;
  29.             q->info.si_code = SI_KERNEL;
  30.             q->info.si_pid = 0;
  31.             q->info.si_uid = 0;
  32.             break;
  33.         defualt:
  34.             copy_siginfo(&q->info,info);//向调用者传递siginfo_t表
  35.             break;
  36.         }
  37.     } else if(!is_si_special(info)) {//NOINFO,PRIV,FORCED只能由内核发出
  38.         if( sig>= SIGRTMIN && info->si_code != SI_USER)    
  39.             return -EAGAIN;
  40.     }
  41. out_set://设置队列的位掩码与信号相关的位
  42.     sigaddset(&signals->signal,sig);
  43.     return ret;
  44. }

signal_wake_up函数定义如下:

  1. void signal_wake_up(struct taks_struct *t,int resume)
  2. {
  3.     unsigned int mask;
  4.     //设置进程表示位
  5.     set_tsk_thread_flag(t,TIF_SIGPENDING);
  6.     mask = TAKS_INTERRUPTIBLE;
  7.     if(resume)//如果是SIGKILL信号则标记该进程停止或等待调试
  8.         mask |= TASK_STOPPED | TASK_TRACED;
  9.     //唤醒该进程,返回0表明已经是可运行状态的,强制重新调度,返回1,则可以让其进行重调度
  10.     //只要调用调度函数schedule(),则就能进行信号处理
  11.     if(!wake_up_state(t,mask))
  12.         kick_process(t);
  13. }

向特定的线程组发送信号

group_send_sig_info()原型如下

  1. int group_send_sig_info(int sig,struct siginfo *info,struct task_struct *p)
  2. {
  3.     unsigned long flags;
  4.     int ret;
  5.     //核查进程发送的权限
  6.     ret = check_kill_permission(sig,info,p);
  7.     if(!ret && sig) {
  8.         ret = -ESRCH;
  9.         //关闭本地中断
  10.         if(lock_task_sighand(p,&flags))
  11.         {
  12.             ret = __group_send_sig_info(sig,info,p);
  13.             unlock_task_sighand(p,&flags);
  14.         }
  15.     }
  16.     return ret;
  17. }
  18. int __group_send_sig_info(int sig,struct siginfo *info,struct task_struct *p)
  19. {
  20.     int ret = 0;
  21.     assert_spin_locked(&p->sighand->siglock);
  22.     //检查信号类型,这些类型可能使目标线程组的其他信号无效
  23.     handle_stop_signal(sig,p);
  24.     //如果是忽略信号(SIGCONT,SIGCHLD,SIGWINCH,SIGURG),则直接忽略
  25.     if(sig_ignored(p,sig))
  26.         return ret;
  27.     //如果是非实时信号,而且已经在悬挂队列中,就直接返回
  28.     if(LEGACY_QUEUE(&p->signal->shared_pending,sig))
  29.         return ret;
  30.     //向进程共享队列发送信号
  31.     ret = send_signal(sig,info,p,&p->signal->shared_pending);
  32.     if(unlikely(ret))
  33.         return ret;
  34.     //找到一个合适的进程并唤醒它
  35.     __group_complete_signal(sig,p);
  36.     return 0;
  37. }

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

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

下一篇:进程与信号(三)

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