信号产生
当进程产生信号时,调用函数specific_send_sig_info函数来向指定的进程发送信号,原型如下:
- static int
-
specific_send_sig_info(int sig,struct siginfo *info,struct task_struct *t)
-
{
-
int ret = 0;
-
//必须关中断,获取该进程处理的自旋锁
-
BUG_ON(!irqs_disabled());
-
assert_spin_locked(&t->sighand->siglock);
-
//如果忽略信号直接返回
-
if(sig_ignored(t,sig))
-
goto out;
-
//非实时信号且挂起队列中已存在该信号未被处理,就直接返回
-
if(LEAGCY_QUEUE(&t->pending,sig))
-
goto out;
-
//否则直接发送到该进程的挂起队列中
-
ret = send_signal(sig,info,t,&t->pending)
-
//信号没有被阻塞,则唤醒该进程
-
if(!ret && !sigismember(&t->blocked,sig))
-
signal_wake_up(t,sig==SIGKILL);
-
out:
-
return ret;
-
}
send_signal函数定义如下:
- //send_signal(sig,info,t,&t->pendings)
-
static int send_signal(int sig,struct siginfo *info,struct task_struct *t,
-
struct sigpending *signals)
-
{
-
struct sigqueue *q = NULL;
-
int ret = 0;
-
signalfd_notify(t,sig);
-
//如果是SIGKILL或SIGSTOP信号则不用添加至队列,
-
//内核会强制执行与这些信号相关的操作
-
if(info == SEND_SIG_FORCED)
-
goto out_set;
-
//否则开始分配空间,进行初始化数据结构,添加到队列上
-
//增加用户悬挂信号的个数,判断创建信号的个数是否超出限制,分配内存等等
-
q = __sigqueue_alloc(t,GFP_ATOMIC,(sig<SIGRTMIN
-
&& is_si_special(info)|| info->si_code>=0));
-
if(q) {
-
list_add_tail(&q->list,&signals->list);
-
switch((unsigned long)info) {
-
case (unsigned long)SEND_SIG_NOINFO://用户态进程发送的信号
-
q->info.si_signo = sig;
-
q->info.si_errno = 0;
-
q->info.si_code = SI_USER;
-
q->info.si_pid = task_pid_vnr(current);
-
q->info.si_uid = current->tid;
-
break;
-
case (unsigned long) SEND_SIG_PRIV://内核态进程发送的信号
-
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;
-
defualt:
-
copy_siginfo(&q->info,info);//向调用者传递siginfo_t表
-
break;
-
}
-
} else if(!is_si_special(info)) {//NOINFO,PRIV,FORCED只能由内核发出
-
if( sig>= SIGRTMIN && info->si_code != SI_USER)
-
return -EAGAIN;
-
}
-
out_set://设置队列的位掩码与信号相关的位
-
sigaddset(&signals->signal,sig);
-
return ret;
-
}
signal_wake_up函数定义如下:
- void signal_wake_up(struct taks_struct *t,int resume)
-
{
-
unsigned int mask;
-
//设置进程表示位
-
set_tsk_thread_flag(t,TIF_SIGPENDING);
-
mask = TAKS_INTERRUPTIBLE;
-
if(resume)//如果是SIGKILL信号则标记该进程停止或等待调试
-
mask |= TASK_STOPPED | TASK_TRACED;
-
//唤醒该进程,返回0表明已经是可运行状态的,强制重新调度,返回1,则可以让其进行重调度
-
//只要调用调度函数schedule(),则就能进行信号处理
-
if(!wake_up_state(t,mask))
-
kick_process(t);
-
}
向特定的线程组发送信号
group_send_sig_info()原型如下
- int group_send_sig_info(int sig,struct siginfo *info,struct task_struct *p)
-
{
-
unsigned long flags;
-
int ret;
-
//核查进程发送的权限
-
ret = check_kill_permission(sig,info,p);
-
if(!ret && sig) {
-
ret = -ESRCH;
-
//关闭本地中断
-
if(lock_task_sighand(p,&flags))
-
{
-
ret = __group_send_sig_info(sig,info,p);
-
unlock_task_sighand(p,&flags);
-
}
-
}
-
return ret;
-
}
-
int __group_send_sig_info(int sig,struct siginfo *info,struct task_struct *p)
-
{
-
int ret = 0;
-
assert_spin_locked(&p->sighand->siglock);
-
//检查信号类型,这些类型可能使目标线程组的其他信号无效
-
handle_stop_signal(sig,p);
-
//如果是忽略信号(SIGCONT,SIGCHLD,SIGWINCH,SIGURG),则直接忽略
-
if(sig_ignored(p,sig))
-
return ret;
-
//如果是非实时信号,而且已经在悬挂队列中,就直接返回
-
if(LEGACY_QUEUE(&p->signal->shared_pending,sig))
-
return ret;
-
//向进程共享队列发送信号
-
ret = send_signal(sig,info,p,&p->signal->shared_pending);
-
if(unlikely(ret))
-
return ret;
-
//找到一个合适的进程并唤醒它
-
__group_complete_signal(sig,p);
-
return 0;
-
}
阅读(2369) | 评论(0) | 转发(0) |