Linux被中断的系统调用
慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的accept、无输入时的read都属于慢速系统调用。
在Linux中,当阻塞于某个慢系统调用的进程捕获一个信号,则该系统调用就会被中断,转而执行信号处理函数,这就是被中断的系统调用。
然而,当信号处理函数返回时,有可能发生以下的情况:
- 如果信号处理函数是用signal注册的,系统调用会自动重启,函数不会返回
- 如果信号处理函数是用sigaction注册的
- 默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR
- 只有中断信号的SA_RESTART标志有效时,系统调用才会自动重启
下面我们编写代码,分别验证上述几种情形,其中系统调用选择read,中断信号选择SIGALRM,中断信号由alarm产生。
使用signal
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
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;
}

使用sigaction + 默认情况
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
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;
}

使用sigaction + 指定SA_RESTART标志
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
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;
}

由于对被中断系统调用处理方式的差异性,因此对应用程序来说,与被中断的系统调用相关的问题是:
- 应用程序无法保证总是知道信号处理函数的注册方式,以及是否设置了SA_RESTART标志
- 可移植的代码必须显式处理关键函数的出错返回,当函数出错且errno等于EINTR时,可以根据实际需求进行相应处理,比如重启该函数
int nread = read(fd, buf, 1024);
if (nread < 0)
{
if (errno == EINTR)
{
//read被中断,其实不应该算作失败,可以根据实际需求进行处理,比如重写调用read,也可以忽略它
}
else
{
//read真正的读错误
}
}
Linux被中断的系统调用的更多相关文章
- Linux的中断和系统调用 & esp、eip等寄存器
http://www.linuxidc.com/Linux/2012-11/74486.htm 一共三篇 中断一般分为三类: 1.由计算机硬件异常或故障引起的中断,称为内部异常中断: 2.由程序中执行 ...
- Linux中断的系统调用
早期UNIX系统的一个特性是:如果在进程执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就被中断不再继续执行.该系统调用返回出错,其errno设置为EINTR.这样处理的理由是:因为一个信号 ...
- linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式
一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是 ...
- linux内核分析——扒开系统调用的三层皮
万子惠 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验部分 选择2 ...
- Linux 内核中断内幕
转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html#resources Linux 内核中断内幕 ...
- linux内核--中断处理程序
一个设备的中断处理程序是它设备驱动程序的一部分--设备驱动程序是用于对设备进行管理的内核代码.中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断 ...
- XV6操作系统代码阅读心得(一):启动加载、中断与系统调用
XV6操作系统是MIT 6.828课程中使用的教学操作系统,是在现代硬件上对Unix V6系统的重写.XV6总共只有一万多行,非常适合初学者用于学习和实践操作系统相关知识. MIT 6.828的课程网 ...
- Linux kernel中断子系统之(五):驱动申请中断API【转】
转自:http://www.wowotech.net/linux_kenrel/request_threaded_irq.html 一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的 ...
- 中断与系统调用深度分析(以网络编程接口SocketAPI为例)
1.从计算机CPU与I/O设备的交互方式谈起 计算机CPU与I/O设备的交互方式有最早的程序查询(也叫轮询)方式,发展到后来的程序中断方式,DMA方式等.简单来说,最早的程序查询方式的机制是,CPU若 ...
随机推荐
- HDU 4396More lumber is required 过至少K条边的最短路
/* ** 题目要求过最少k条边的最短路 */ #include <iostream> #include <cstdio> #include <cstring> # ...
- POJ 1077 Eight (BFS+康托展开)详解
本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...
- CQ18阶梯赛第二场
H国的身份证号码I HihoCoder - 1558 只要单纯的判断一下前后的乘积就好了, 因为不是很想处理倍数的关系, 所以我这里是用 string去处理. 代码: #include<bits ...
- CF989B A Tide of Riverscape 思维 第七题
A Tide of Riverscape time limit per test 1 second memory limit per test 256 megabytes input standard ...
- MariaDB数据库自学一
在CentOS下安装Mariadb 数据库,命令: yum -y mariadb mariadb.server 等待几分钟后就可以自动完成安装了,然后启动对应的服务: systemctl start ...
- linux常用命令二
linux常用命令一 常用指令 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(all ...
- linux下tomcat无法远程访问(开放8080端口)
我们在linux下配置了tomcat后发现,无法访问除了linux(如果是虚拟机的话,宿主机子根本无法访问tomcat),解决下吧 原因是我们的tomcat访问需要8080端口,但是从外部访问,我们的 ...
- 数据库高级:SQL-CREATE-TABLE语句
作者:松软科技(www.sysoft.net.cn) 发布时间:2019/3/17 9:34:51 CREATE TABLE 语句 CREATE TABLE 语句用于创建数据库中的表. SQL CRE ...
- Scala 系列(十三)—— 隐式转换和隐式参数
一.隐式转换 1.1 使用隐式转换 隐式转换指的是以implicit关键字声明带有单个参数的转换函数,它将值从一种类型转换为另一种类型,以便使用之前类型所没有的功能.示例如下: // 普通人 clas ...
- Windows Docker 部署 Spring Boot 项目
目录 Docker Configuration Config IDEA Plugin Create Spring Boot Project Containerize It Use Dockerfile ...