慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的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被中断的系统调用的更多相关文章

  1. Linux的中断和系统调用 & esp、eip等寄存器

    http://www.linuxidc.com/Linux/2012-11/74486.htm 一共三篇 中断一般分为三类: 1.由计算机硬件异常或故障引起的中断,称为内部异常中断: 2.由程序中执行 ...

  2. Linux中断的系统调用

    早期UNIX系统的一个特性是:如果在进程执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就被中断不再继续执行.该系统调用返回出错,其errno设置为EINTR.这样处理的理由是:因为一个信号 ...

  3. linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式

        一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是 ...

  4. linux内核分析——扒开系统调用的三层皮

    万子惠 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验部分 选择2 ...

  5. Linux 内核中断内幕

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html#resources Linux 内核中断内幕 ...

  6. linux内核--中断处理程序

    一个设备的中断处理程序是它设备驱动程序的一部分--设备驱动程序是用于对设备进行管理的内核代码.中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断 ...

  7. XV6操作系统代码阅读心得(一):启动加载、中断与系统调用

    XV6操作系统是MIT 6.828课程中使用的教学操作系统,是在现代硬件上对Unix V6系统的重写.XV6总共只有一万多行,非常适合初学者用于学习和实践操作系统相关知识. MIT 6.828的课程网 ...

  8. Linux kernel中断子系统之(五):驱动申请中断API【转】

    转自:http://www.wowotech.net/linux_kenrel/request_threaded_irq.html 一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的 ...

  9. 中断与系统调用深度分析(以网络编程接口SocketAPI为例)

    1.从计算机CPU与I/O设备的交互方式谈起 计算机CPU与I/O设备的交互方式有最早的程序查询(也叫轮询)方式,发展到后来的程序中断方式,DMA方式等.简单来说,最早的程序查询方式的机制是,CPU若 ...

随机推荐

  1. UVA - 10480 Sabotage 最小割,输出割法

    UVA - 10480 Sabotage 题意:现在有n个城市,m条路,现在要把整个图分成2部分,编号1,2的城市分成在一部分中,拆开每条路都需要花费,现在问达成目标的花费最少要隔开那几条路. 题解: ...

  2. hdu 5969 最大的位或(贪心)

    Problem Description B君和G君聊天的时候想到了如下的问题.给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大.其中|表示 ...

  3. hdu 2844 Coins 多重背包(模板) *

    Coins                                                                             Time Limit: 2000/1 ...

  4. 深入浅出理解EdgeBoard中NHWC数据格式

    摘要: 在深度学习中,为了提升数据传输带宽和计算性能,经常会使用NCHW.NHWC和CHWN数据格式,它们代表Image或Feature Map等的逻辑数据格式(可以简单理解为数据在内存中的存放顺序) ...

  5. 【Offer】[49] 【丑数】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 我们把只包含因子2.3和5的数称作丑数( Ugly Number).求按从小到大的顺序的第1500个丑数.例如,6.8都是丑数,但14不 ...

  6. 009 Python基本图形绘制

    目录 一.概论 二.方法论 三.实践能力 一.概论 深入理解Python语言 实例2: Python蟒蛇绘制 模块1: turtle库的使用 turtle程序语法元素分析 二.方法论 Python语言 ...

  7. jsp页面直接输出了html代码

    可能出现的情况: 1.修改web.xml中springMVC的过滤器路径如下: "/"与"/*区别" 其实/和/*都可以匹配所有的请求资源,但其匹配的优先顺序是 ...

  8. FreeSql (六)批量插入数据

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  9. 剖析nsq消息队列(二) 去中心化代码源码解析

    在上一篇帖子剖析nsq消息队列(一) 简介及去中心化实现原理中,我介绍了nsq的两种使用方式,一种是直接连接,还有一种是通过nslookup来实现去中心化的方式使用,并大概说了一下实现原理,没有什么难 ...

  10. Hbase 统计表行数的3种方式总结

    有些时候需要我们去统计某一个Hbase表的行数,由于hbase本身不支持SQL语言,只能通过其他方式实现.可以通过一下几种方式实现hbase表的行数统计工作: 1.count命令 最直接的方式是在hb ...