系统调用与信号重启,好

这篇写的很好

http://blog.chinaunix.net/uid-24774106-id-3065234.html

UNIX系统编程,这本书中有大量的重启系统调用,例如下面的例子:选自P50,

pid_t r_wait(int *stat_loc)
{
    int retval;
    while(((retval = wait(stat_loc)) ==-1 && (errno == EINTR));
    return retval;
}

还有对read,write的重启操作。

UNP volume1中提到slow system call,UNP中的例子是accept系统调用,accept是服务器端接受网络客户端的连接,connect,将完成三次握手协议的连接返回。如果服务器打开了监听listen,但是始终没有客户端来连接connect,可以想见,accept就阻塞在此。这是一种比较好理解的阻塞型系统调用。

wait也是一种阻塞性的调用。

但是linux世界上还有另外一种东东,叫做信号,来处理突发事件。

一般来讲,一个系统调用,要么成功,要么失败,但是由于为了及时处理信号,出现了第三种情况,系统调用被信号中断,为了标识这种情况,错误码errno置为EINTR。

我们可以看到这种方式并不优美,程序员需要自己判断errno,如果被信号终端,那么还需要自己来重启系统调用。这是System V UNIX的实现方式。

BSD 内核想程序员之所想,急程序员之所急,采用了另外一种实现,就是如果中断系统调用,切换到用户态来执行信号处理程序,那么系统调用没有返回值,内核在信号处理函数结束后,自动重启系统调用。这种方式很贴心阿,程序员再也不用自己判断errno,然后重启系统调用了。

LINUX不愧是UNIX世界的杰出新秀,他通过SA_RESTART 就可以支持BSD方案。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
#include<string.h>

pid_t r_wait(int *stat_loc)
{
    int ret;
        while(((ret = wait(stat_loc)) == -1) )
        {
                /*if(errno == EINTR)
                {
                     fprintf(stderr,"may be interrupted by a signal,let wait again \n");
                }
                else*/
                {
                        break;
                }
        }

        return ret;
}

void sig_alrm_func()
{
    printf("catch an alarm signal\n");
    return;
}

int main(int argc,char** argv)
{
    pid_t childpid;
        int i,n;
        struct sigaction act;

        if(argc != 2)
        {
         fprintf(stderr,"usage : test n \n",argv[0]);
             return -1;
        }

        n = atoi(argv[1]);

        act.sa_handler = sig_alrm_func;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        // act.sa_flags |= SA_RESTART;
        sigaction(SIGALRM,&act,NULL);
        for(i = 0;i<n;i++)
        {
         if((childpid = fork()) <= 0)
                                break;
        }

       if(childpid == 0 )
        {
               sleep(50);
        }
        while(r_wait(NULL) >0) ;
        fprintf(stderr," i :%d process ID : %ld,\t parent ID :%ld \tchild ID : %ld\n",
                                        i,(long)getpid(),(long)getppid(),(long)childpid);

        return 0;
}

原文中对比了三种方案。

第一种,是不判断EINTR.

第二种,是判断EINTR,然后重启。

第三种,是对于信号处理函数,sigaction,里面sa_flags 加上对 SA_RESTART的支持,这样被中断的系统调用就能够自动重启了。

注意,和sleep是不一样的。sleep是返回的秒数可能不足。

http://www.cnblogs.com/charlesblc/p/6434213.html

返回剩余的秒数,而不是errno=EINTR。

sleep的例子应该是,SIGALARM,因为本身sleep就是用SIGALARM实现的。

时间: 2024-08-07 16:59:16

系统调用与信号重启,好的相关文章

慢系统调用 与 信号

慢系统调用(Slow system call) 该术语适用于那些可能永远阻塞的系统调用.永远阻塞的系统调用是指调用永远无法返回,多数网络支持函数都属于这一类.如:若没有客户连接到服务器上,那么服务器的accept调用就会一直阻塞. 慢系统调用可以被永久阻塞,包括以下几个类别: (1)读写‘慢’设备(包括pipe,终端设备,网络连接等).读时,数据不存在,需要等待:写时,缓冲区满或其他原因,需要等待.读写磁盘文件一般不会阻塞. (2)当打开某些特殊文件时,需要等待某些条件,才能打开.例如:打开中断

linux strace-跟踪进程的系统调用或是信号产生情况,lstrace-跟踪己丑年调用库函数情况,进程跟踪调试命令

本工具可以用来做大多数排除,比如mount一个NFS,很慢,找不出原因,我们可以使用strace命令来跟中mount这个经常所有的调用过程. strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用. strace 显示这些调用的参数并返回符号形式的值.strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核. 下面记录几个常用 option . 1 -f -F选项告诉strace同时跟踪fork和vfork出来的进程 2 -o xxx.txt 输出到某个文件.

strace命令_Linux strace 命令用法详解:跟踪系统调用和信号

strace常用来跟踪进程执行时的系统调用和所接收的信号. 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备.strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间. strace命令是一个集诊断.调试.统计与一体的工具,我们可以使用strace对应用的系统调用和信号传递的跟踪结果来对应用进行分析,以达到解决问题或者是了解应用工作过程的目的.当然stra

使用strace 工具跟踪系统调用和信号

使用strace来执行程序,它会记录程序执行过程中调用,接收到的信号,通过查看记录结果,就可以知道程序打开哪些文件,进行哪些读写,映射哪些内存,向系统申请多少内存等信息 strace 移植 下载strace源码:strace-4.5.15.tar.bz2 解压:tar xjf strace-4.5.15.tar.bz2, 如果想要在自己板子上运行,还需要进行配置,我使用的是韦东山制作的一个补丁 strace-fix-arm-bad-syscall.patch 进行打补丁: patch -pn <

信号中断与慢系统调用

Slow system call 该术语适用于那些可能永远阻塞的系统调用.永远阻塞的系统调用是指调用永远无法返回,多数网络支持函数都属于这一类.如:若没有客户连接到服务器上,那么服务器的accept调用就会一直阻塞. 慢系统调用可以被永久阻塞,包括以下几个类别: (1)读写‘慢’设备(包括pipe,终端设备,网络连接等).读时,数据不存在,需要等待:写时,缓冲区满或其他原因,需要等待.读写磁盘文件一般不会阻塞. (2)当打开某些特殊文件时,需要等待某些条件,才能打开.例如:打开中断设备时,需要等

APUE: 信号相关系统调用和库函数

信号就是软件中断,信号提供一种处理异步事件的方法. 信号出现时按照下列方式处理: 1.忽略此信号,有两个信号不能忽略. 2.捕捉此信号,有两个信号不能被捕捉. 3.默认处理,少数默认处理是忽略,大部分默认处理是终止. ctrl+D组合键,不是信号,只是EOF字符 linux中1-31为普通信号:34-64为实时信号. trap-l 命令查看所有信号,64个 信号从1开始,没有0. SIGHUP:终端接口检测到连接断开发出该信号, SIGINT:ctrl+c,终端中断符,一般用来停止一个失去控制的

Linux高性能服务器编程——信号及应用

 信号 信号是由用户.系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常.Linux信号可由如下条件产生: 对于前台进程,用户可以通过输入特殊的终端字符来给它发送信号.比如输入Ctrl+C通常会给进程发送一个终端信号. 2.系统异常 系统状态变化 运行kill命令或调用kill函数 Linux信号概述 发送信号 Linux下,一个进程给其他进程发送信号的API是kill函数.其定义如下: #include <sys/types.h> #include <sign

linux学习之信号

一.概述: 软中断信号(signal, 简称信号)是用来通知进程发生了异步事件.在软件层次上是对中断的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达.进程之间可以互相通过系统调用kill发送软中断信号.内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件.信号机制除了基本通知功能外,还可以传递附加信息. 收到信号的进程对各种信号的

linux 信号集 二 sigaction

sigaction函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作). 他是POSIX的信号接口,而signal()是标准C的信号接口(如果程序必须在非POSIX系统上运行,那么就应该使用这个接口) 给信号signum设置新的信号处理函数act, 同时保留该信号原有的信号处理函数oldact int sigaction(int signo,const struct sigaction *restrict act, struct sigaction *restrict oact);