linux 中断系统调用代码,Linux被中断的系统调用

本文详细介绍了Linux中慢系统调用如read在遇到中断信号SIGALRM时的不同处理方式,包括使用signal和sigaction注册信号处理函数时的自动重启系统调用行为。通过示例代码展示了不同注册方式下,当read被中断时,errno如何判断以及如何处理EINTR错误。强调了编写可移植代码时,应对关键函数的出错返回进行显式处理。
摘要由CSDN通过智能技术生成

慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的accept、无输入时的read都属于慢速系统调用。 在Linux中,当阻塞于某个慢系统调用的进程捕获一个信号,则该系统调用就会被中断,转而执行信号处理函数,这就是被中断的系统调用。 然而,当信号处理函数返回时,有可能发生以下的情况:

如果信号处理函数是用signal注册的,系统调用会自动重启,函数不会返回

如果信号处理函数是用sigaction注册的

默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR

只有中断信号的SA_RESTART标志有效时,系统调用才会自动重启

下面我们编写代码,分别验证上述几种情形,其中系统调用选择read,中断信号选择SIGALRM,中断信号由alarm产生。

使用signal

#include

#include

#include

#include

void handler(int s)

{

printf("read is interrupt by signal handler\n");

return;

}

int main()

{

char buf[10];

int nread = 0;

signal(SIGALRM, handler);

alarm(2);

printf("read start\n");

nread = read(STDIN_FILENO, buf, sizeof(buf));

printf("read return\n");

if ((nread < 0) && (errno == EINTR))

{

printf("read return failed, errno is EINTR\n");

}

return 0;

}

ec2904817f9fd91069451537f020793a.png

使用sigaction + 默认情况

#include

#include

#include

#include

void handler(int s)

{

printf("read is interrupt by signal handler\n");

return;

}

int main()

{

char buf[10];

int nread = 0;

struct sigaction act;

sigemptyset(&act.sa_mask);

act.sa_handler = handler;

act.sa_flags = 0; //不给SIGALRM信号设置SA_RESTART标志,使用sigaction的默认处理方式

//act.sa_flag |= SA_INTERRUPT; //SA_INTERRUPT是sigaction的默认处理方式,即不自动重启被中断的系统调用

//实际上,不管act.sa_flags值为多少,只要不设置SA_RESTART,sigaction都是按SA_INTERRUPT处理的

sigaction(SIGALRM, &act, NULL);

alarm(2);

printf("read start\n");

nread = read(STDIN_FILENO, buf, sizeof(buf));

printf("read return\n");

if ((nread < 0) && (errno == EINTR))

{

printf("read return failed, errno is EINTR\n");

}

return 0;

}

78e45eba130ee3e635aab5fa9bf3df07.png

使用sigaction + 指定SA_RESTART标志

#include

#include

#include

#include

void handler(int s)

{

printf("read is interrupt by signal handler\n");

return;

}

int main()

{

char buf[10];

int nread = 0;

struct sigaction act;

sigemptyset(&act.sa_mask);

act.sa_handler = handler;

act.sa_flags = 0;

act.sa_flags |= SA_RESTART; //给SIGALRM信号设置SA_RESTART标志

sigaction(SIGALRM, &act, NULL);

alarm(2);

printf("read start\n");

nread = read(STDIN_FILENO, buf, sizeof(buf));

printf("read return\n");

if ((nread < 0) && (errno == EINTR))

{

printf("read return failed, errno is EINTR\n");

}

return 0;

}

67885d8d0c1be0305ac3506d3465f2fa.png

由于对被中断系统调用处理方式的差异性,因此对应用程序来说,与被中断的系统调用相关的问题是:

应用程序无法保证总是知道信号处理函数的注册方式,以及是否设置了SA_RESTART标志

可移植的代码必须显式处理关键函数的出错返回,当函数出错且errno等于EINTR时,可以根据实际需求进行相应处理,比如重启该函数

int nread = read(fd, buf, 1024);

if (nread < 0)

{

if (errno == EINTR)

{

//read被中断,其实不应该算作失败,可以根据实际需求进行处理,比如重写调用read,也可以忽略它

}

else

{

//read真正的读错误

}

}

原文出处:https://www.cnblogs.com/songhe364826110/p/11657198.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值