linux信号机制

linux信号机制
 
 
信号提供了一种通知进程系统事件发生的机制,它也是作为用户进程之间通信和同步的
一种原始机制。在进程迁移的情况下,如何处理信号呢?这部分介绍了MOSIX系统对信号
机制的处理。
LINUX信号机制

信号是异步的进程间通讯机制,是在软件层次上对中断机制的一种模拟。LINUX内核的信
号机制符合POSIX.4的规定,这是POSIX.1标准的一个超集。

每个进程的task_struct结构中都有个指针sig,指向一个singal_struct结构,结构中的
数组action[]相当于一个信号向量表,每个元素确定了进程接收到一个具体的信号时应
该采取的行动。


struct signal_struct {
    atomic_t        count;
    struct k_sigaction  action[_NSIG];
    spinlock_t      siglock;
};




那么系统如何判断一个进程是否有信号在等待处理呢?这是通过task_struct结构中的si
gpending成员。task_struct结构中的blocked成员则为屏蔽信号的集合,pending成员则
为信号队列,每产生一个信号则把它挂入这个队列,信号位图signal也保存在其中。

用户常常要自己定义对信号的处理程序,并且用户的处理函数是位于用户空间的。LINUX
提供了系统调用signal(sys_signal)和sigaction(sys_sigaction 或sys_rt_sigacti
on)为信号设置处理向量。用户设置信号处理的时机我们是不能确定的,可以在进程迁
移前,也可以在进程迁移之后,进程可以在不同的节点间多次迁移,因此,如何保证信
号不被丢失并且都能被正确处理就很重要。并且我们注意到,进程在迁移时,并不将信
号向量表迁移到目标进程,而只是将进程的异步信号和强制信号信息传送到目标进程【
参见mig_send_misc()和mig_do_receive_misc()】。


struct asig_h
{
    unsigned int sigs;/*信号*/
    int nforced;/*内核发送的强制信号的个数*/
};
struct mosix_task
{。。。。。。。
uint32_t asig;      /*到达REMOTE的信号 */
siginfo_t *forced_sigs; /* REMOTE强制信号信息*/
int nforced_sigs;   /* REMOTE强制信号的个数 */
short sigmig;       /* 迁移时接收的信号 */
}




int  mig_send_misc(int credit)
{ struct mig_misc_h m;
register struct task_struct *p = current;
………………..
m.asig.sigs = p->mosix.asig;
m.asig.nforced = p->mosix.nforced_sigs;
forced_sigs = p->mosix.forced_sigs;
sti();
if(comm_send(MIG_MISC, &m, sizeof(m), forced_sigs,
                    m.asig.nforced * sizeof(siginfo_t), 0))
        ………………
}





因此,我们可以说进程信号处理的状态是保留在DEPUTY方的。这样做也是很自然的。首
先在MOSIX中,对于REMOTE进程,几乎所有的系统调用都是请求DEPUTY来处理,和信号相
关的一些系统调用也不了例外。例如,sigprocmask()改变本进程得信号屏蔽位图,sigp
ending()检查有哪些信号已到达而未被处理,signal()和sigaction()安装信号处
理程序。其次,在不少内核操作中,进程进入睡眠以后刚被唤醒时,都会检测信号的存
在从而提前返回到用户空间。而DEPUTTY和REMOTE可以分别看作对系统上下文和用户上下
文的抽象,所以DEPUTY保留着信号处理的状态。

信号响应

对信号的检测和响应总是发生在系统空间,通常发生在两种情况下:第一,当前进程由
于系统调用、中断或异常而进入系统空间以后,从系统空间返回到用户空间的前夕。第
二,当前进程在内核中进入睡眠以后刚被唤醒时,由于信号的存在而提前返回到用户空
间。

当进程由于中断进入系统空间以后,中断处理程序服务完后,将会转到入口ret_from_in
tr 。当进程由于异常而进入系统空间后,将会跳到error_code从而最终转到ret_from_e
xception处理【参见entry.S】。如果中断或异常发生于用户空间,则转移到ret_check_
reschedule,否则发生于内核空间,则到达restore_all。当进程由于系统调用进入系统
空间,将最终走到ret_from_sys_call。


ENTRY(ret_from_sys_call)
。。。。。
ret_check_reschedule:
        cli                       # need_resched and signals atomic test
        cmpl $0,need_resched(%ebx)/*判断是否需要调度*/
        jne reschedule
        cmpl $0,sigpending(%ebx)  /*判断是否有悬挂的信号/
        jne signal_return        /*如果有信号待处理,则跳到signal_return */
  straight_to_mosix:
        call SYMBOL_NAME(mosix_pre_usermode_actions)
        testl %eax,%eax
        jne ret_from_sys_call
restore_all:
        RESTORE_ALL
  ALIGN
signal_return:
        sti                             # 开中断
handler
        testl $(VM_MASK),EFLAGS(%esp)/*是否处于VM86模式*/
        movl %esp,%eax
        jne v86_signal_return  /*是VM86模式的话,则转到v86_signal_return */
call SYMBOL_NAME(do_signal) /* do_signal 对信号进行处理*/
        jmp straight_to_mosix




从代码中我们可以看到,如果有信号待处理,则在退出系统空间前,会跳到signal_retu
rn,调用do_signal处理信号。

我们看看do_signal ,它对信号作出具体的反应。如果当前进程是REMOTE,它只是简单
的返回0。否则,该函数根据当前进程的signal域,确定进程收到了那些信号。对进程收
到的每一个信号,从进程的信号等待队列中找到该信号对应的附加信息,从进程的sig域
的action数组中找到信号的处理程序及其相关的信息。于是,如果用户设置了信号处理
程序(在用户空间中),则最终会通过函数handle_signal()准备好对处理程序的执行


用户提供的信号处理程序是在用户空间执行的,而且执行完毕以后还还要回到系统空间
。LINUX实现的机制如下:


用户空间堆栈中为信号处理程序的执行预先创建一个框架,框架中包括一个作为局部量
的数据结构,并把系统空间的"原始框架"保存在这个数据结构中
在信号处理程序中插入对系统调用sigreturn()的调用
将系统空间堆栈中"原始框架"修改成为执行信号处理程序所需的框架
"返回"到用户空间,但是却执行信号处理程序
信号处理程序执行完毕后,通过系统调用sigreturn()重返系统空间
在系统调用sigreturn()中从用户空间恢复"原始框架"
最后再返回到用户空间,继续执行原先的用户程序

对于本地进程,这是在handle_signal()中由setup_rt_frame()或setup_frame()作出安
排的。但是,对于DEPUTY进程,则是通过mosix_deputy_setup_frame()实现的。因为,
我们已经知道,DEPUTY是永远运行在核心态中的;进程迁移后,代码段和数据段等都完
全迁移到远程REMOTE进程。因此,信号处理程序必然是在REMOTE进程上运行的。那么,
这又是如何实现的呢。

mosix_deputy_setup_frame()通过deputy_request()函数向REMOTE发送DEP_SETUPFRAM
E请求,REMOTE将在remote_wait()函数中接收到该请求,调用remote_setup_frame()
来响应该请求。REMOTE进程在remote_setup_frame()中,根据DEPUTY传来的参数,通
过setup_rt_frame()或setup_frame()安排好一个框架。

这样,当REMOTE进程从系统空间返回到用户空间时,将执行信号处理程序。然后,将通
过sigreturn()系统调用重返系统空间。sys_sigreturn()的作用就是从用户空间执行信
号处理程序的框架中恢复当初系统空间中的原始框架。它通过restore_sigcontext()
恢复框架的。但是对于DEPUTY进程,则是通过mosix_deputy_restore_sigcontext()函
数来恢复系统空间的原始框架的【参见sys_sigreturn()】。这里,因为是REMOTE进程调
用sigreturn()系统调用,因此根据我们前面对系统调用的分析,REMOTE进程向DEPUTY进
程发送REM_SYSCALL请求,DEPUTY将在通过deputy_syscall()函数中调用sys_sigretur
n()来响应该请求。

mosix_deputy_restore_sigcontext()则向REMOTE进程发送DEP_RESTORESIGCONTEXT请
求。REMOTE在向DEPUTY发送REM_SYSCALL请求后,将处于remote_wait()循环中等待REM_S
YSCALL请求的应答【参见remote_standard_system_call()】。REMOTE在remote_wait()
中接收到DEP_RESTORESIGCONTEXT请求后,则通过remote_restore_sigcontext()函数调
用restore_sigcontext()真正恢复核心空间的原始框架。此后,当REMOTE进程从系统
空间返回后,将回到信号处理前原先的用户空间处继续往下执行。

信号发送

发送一个信号给进程可以在用户空间通过系统调用发送,如通过sys_kill和
syr_rt_sigqueueinfo调用发送。内核也可以通过force_sig()和force_sig_info()向进
程强制发送信号,将屏蔽位强制清除,不允许目标进程忽略该信号。

在用户空间向一个进程发送信号由系统调用sys_kill()实现。该函数调用函数kill_some
thing_info(),它根据情况,或者向单个进程发送信号(kill_proc_info()),或者向一
个进程组中的所有进程发送信号(kill_pg_info()), 最终都会调用函数send_sig_info(
)来完成真正的信号发送。kill_pg_info()中,通过for_each_local_task(p)来查找属于
同组的进程。这是因为MOSIX中, 信号只会发给本地进程,而不会发送给REMOTE进程的
。对于REMOTE进程,当通过kill()发送信号时,根据我们前面对系统调用的分析,我
们知道最终将是由DEPUTY来调用sys_kill()。因此,信号是被挂入DEPUTY的task_struct
结构中的pending队列里。

异步和强制信号的处理

内核也会向进程发送信号,例如当页面异常而又无法恢复时,do_page_fault()页面异
常处理程序会通过force_sig()zx向当前进程发送一个SIGBUS信号。内核发送的信号一般
都是需要立即作出反应的。MOSIX对系统发送信号的处理方式也和用户发送信号有所不同
,内核发送的"强制"信号都保存在mosix_task的forced_sigs指针中。

我们首先看看函数force_sig_info()。如果信号的目的地为REMOTE进程,则:


如果处于中断服务中,则系统panic
得到进程已有的强制信号数(n= t->mosix.nforced_sigs)并试图分配内存(x =
kmalloc((n + 1) * sizeof(siginfo_t), GFP_KERNEL))用于保存这n+1个信号信息
如果内存分配失败,则尽量再次发送该信号send_sig(sig, t, 0);返回0
因为分配内存返回时,可能已经处理了一部分信号,因此要进行检测。如果是,则释放
刚刚申请的内存,跳到第二步
将保存的siginfo_t和新的info拷贝到分配的内存中,保存在mosix结构的forced_sigs中
,并增加强制信号计数t->mosix.forced_sigs = x; t->mosix.nforced_sigs++;

我们前面已经分析过,REMOTE进程从系统空间返回到用户态之前,将会调用remote_pre_
usermode_actions()函数。remote_pre_usermode_actions()函数将会检测当前进程是否
有异步或"强制"信号待处理。如果有,它会通过函数transfer_signals_to_deputy()
发送REM_ASIG请求将信号传递给DEPUTY处理【参见remote_pre_usermode_actions()】。
DEPUTY则会通过函数deputy_analyse_remote_signals()来处理REM_ASIG请求。它首先
从连接中获得"强制"信号信息,通过force_sig_info()向当前进程(即DEPUTY本身)
发送强制信息。然后得到每个信号,依次处理,一般都是通过send_sig发给当前进程。

转自:http://blog.chinaunix.net/u/14053/showart_82160.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值