Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1951205
  • 博文数量: 383
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 4061
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-24 18:53
文章分类

全部博文(383)

文章存档

2011年(1)

2010年(9)

2009年(276)

2008年(97)

我的朋友

分类: LINUX

2008-11-26 15:13:14

    Linux 内核中不存在任何机制用来区分不同信号的优先级。也就是说,当同时有多个信号发出时,进程可能会以任意顺序接收到信号并进行处理。另外,如果进程在处理某个信号之前,又有相同的信号发出,则进程只能接收到一个信号。产生上述现象的原因与内核对信号的实现有关。


   
系统在 task_struct 结构中利用两个域分别记录当前挂起的信号(signal)以及当前阻塞的信号(blocked)。挂起的信号指尚未进行处理的信号。阻塞的信号指进程当前 不处理的信号,如果产生了某个当前被阻塞的信号,则该信号会一直保持挂起,直到该信号不再被阻塞为止。除了 SIGKILL 和 SIGSTOP信号外,所有的信号均可以被阻塞,信号的阻塞可通过系统调用sigprocmask()实现。每个进程的 task_struct 结构中还包含了一个指向 sigaction 结构数组的指针,该结构数组中的信息实际指定了进程处理所有信号的方式。如果某个 sigaction 结构中包含有处理信号的例程地址,则由该处理例程处理该信号;反之,则根据结构中的一个标志或者由内核进行默认处理,或者只是忽略该信号。通过系统调用 sigaction(),进程可以修改 sigaction 结构数组的信息,从而指定进程处理信号的方式。

    进程不能向系统中所有的进程发送信号,一般而言,除系统和超级用户外,普通进程只能向具有相同 uid 和 gid 的进程,或者处于同一进程组的进程发送信号。当有信号产生时,内核将进程 task_struct 的 signal 字中的相应位设置为 1。系统不对置位之前该位已经为 1的情况进行处理,因而进程无法接收到前一次信号。如果进程当前没有阻塞该信号,并且进程正处于可中断的等待状态(INTERRUPTIBLE),则内核 将该进程的状态改变为运行(RUNNING),并放置在运行队列中。这样,调度程序在进行调度时,就有可能选择该进程运行,从而可以让进程处理该信号。

    发送给某个进程的信号并不会立即得到处理,相反,只有该进程再次运行时,才有机会处理该信号。每次进程从系统调用中退出时,内核会检查它的signal 和 block 字段,如果有任何一个未被阻塞的信号发出,内核就根据 sigaction 结构数组中的信息进行处理。处理过程如下:

1. 检查对应的 sigaction 结构,如果该信号不是 SIGKILL 或 SIGSTOP 信号,且被忽略,则不处理该信号。

2. 如果该信号利用默认的处理程序处理,则由内核处理该信号,否则转向第 3 步。

3. 该信号由进程自己的处理程序处理,内核将修改当前进程的调用堆栈,并将进程的程序计数寄存器修改为信号处理程序的入口地址。此后,指令将跳转到信号处理程序,当从信号处理程序中返回时,实际就返回了进程的用户模式部分。


    Linux
是 POSIX 兼容的,因此,进程在处理某个信号时,还可以修改进程的 blocked 掩码。但是,当信号处理程序返回时,blocked 值必须恢复为原有的掩码值,这一任务由内核的sigaction()函数完成。Linux 在进程的调用堆栈帧中添加了对清理程序的调用,该清理程序可以恢复原有的 blocked 掩码值。当内核在处理信号时,可能同时有多个信号需要由用户处理程序处理,这时,Linux 内核可以将所有的信号处理程序地址推入堆栈中,而当所有的信号处理完毕后,调用清理程序恢复原先的 blocked 值。


信号举例


一、signal       系统调用
      1.系统调用signal用来设定某个信号的处理方法。            
      该调用声明的格式如下:            
      void       (*signal(int signum, void (*handler)(int)))(int);            
        在调用中,参数signum指出要设置处理方法的信号。第二个参数handler是一个处理函数,或者是            
      
  •           SIG_IGN:忽略参数signum所指的信号。
  •           SIG_DFL:恢复参数signum所指信号的处理方法为默认值。
      传递给信号处理例程的整数参数是信号值,这样可以使得一个信号处理例程处理多个信号。系统调用signal返回值是指定信号signum前一次的处理例程或者错误时返回错误代码SIG_ERR            
      2.程序清单            
      

#include             

      

#include             

      

#include             

      

void sigroutine(int dunno)            

      

{
/*       信号处理例程,其中dunno将会得到信号的值 */            

      

switch(dunno){            

      case 1:          
   printf("Get a signal--SIGHUP\n");                  

   break;            

      case  2:                  

printf("Get a signal--SIGINT\n");            

      break;                  

case  3:            

     printf("Get a signal--SIGQUIT\n");                  

break;            

      }                  

return;            

      

}            

      

int main()            

      

int pi;          
pi=getpid();                  

printf("process id is %d\n",pi);            

signal(SIGHUP,sigroutine);                  

signal(SIGINT,sigroutine);            

signal(SIGQUIT,sigroutine);                  


for(;;);            

      }

其中信号SIGINT由按下Ctrl-C发出,信号SIGQUIT由按下Ctrl-\ (back       slash)发出,另外一个信号由CTRL-Z发出。
阅读(730) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~