中断系统调用

系统调用可分为两类:慢速系统调用和其它系统调用。

慢速系统调用:可能会使进程永远阻塞的一类的系统调用。如果在阻塞期间收到一个信号,该系统调用就被中断,不再继续执行(早期);也可以设定系统调用是否重启。如,read、write、pause、wait、waitpid等。read在读管道、读网络和读设备(如从键盘上读,标准输入设备)都可能会永久阻塞(只要数据不到达,read就会阻塞读),但是read读文件时不会阻塞。wait和waitpid阻塞等待回收子进程。

其它系统调用:getpid、getppid、fork等。

结合pause,回顾慢速系统调用。慢速系统调用被中断的相关行为,实际上就是pause的行为:如,read ① 想中断pause,信号不能被屏蔽;② 信号的处理方式必须是捕捉 (默认、忽略都不可以);③ 中断后返回-1, 设置errno为EINTR(表“被信号中断”)。此时在系统调用被中断后,由用户指定是否重启该系统调用(对于pause函数,不希望重启该系统调用;对于read函数,希望重启该系统调用,继续进行读操作),其具体方法就是:修改注册信号捕捉函数时的sa_flags参数来设置被信号中断后系统调用是否重启。SA_INTERRUPT不重启。 SA_RESTART重启。

在慢速系统调用被信号终结后,其返回值为-1,但是返回值为-1不仅仅是这一种情况,也可能是系统调用执行失败,出现了其它错误,如read系统调用。因此必须对慢速系统调用的返回值做进一步的判断,即也要同时判断errno是否为EINTR,然后进一步决定系统调用是否需要重启:

ret = pause();   

if( ret == -1 && errno == EINTR )

{

printf( "pause success\n" );

}   //对于该函数不需要重启     如果需要重启,可以手动调用的方式实现重启,即再次调用该函数即可。一般不支持这样做,直接用sa_flags来实现即可。

sa_flags参数总结:

  1. sa_flags为0,则默认属性:捕捉函数指定为sa_handler,信号本身被屏蔽;
  2. sa_flags为SA_SIGINFO,捕捉函数指定为sa_sigaction,信号本身被屏蔽;
  3. sa_flags为SA_NODEFER,信号本身不被屏蔽,捕捉到信号后,在执行捕捉函数期间,不希望自动阻塞该信号,除非sa_mask中包含该信号。即允许捕捉函数重入(当相同信号再次到来时,中断嵌套调用该函数),捕捉函数应该为可重入函数;
  4. sa_flags为SA_INTERRUPT,慢速系统调用被信号终结后,不重启;
  5. sa_flags为SA_RESTART,慢速系统调用被信号终结后,重启;

你可能感兴趣的:(Linxu系统编程)