linux中对errno是EINTR的处理
慢系统调用(slow system call):此术语适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。如:若没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。
EINTR错误的产生:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误。例如:在socket服务器端,设置了信号捕获机制,有子进程,当在父进程阻塞于慢系统调用时由父进程捕获到了一个有效信号时,内核会致使accept返回一个EINTR错误(被中断的系统调用)。
当碰到EINTR错误的时候,可以采取有一些可以重启的系统调用要进行重启,而对于有一些系统调用是不能够重启的。例如:accept、read、write、select、和open之类的函数来说,是可以进行重启的。不过对于套接字编程中的connect函数我们是不能重启的,若connect函数返回一个EINTR错误的时候,我们不能再次调用它,否则将立即返回一个错误。针对connect不能重启的处理方法是,必须调用select来等待连接完成。
在 linux 或者 unix 环境中, errno 是一个十分重要的部分。在调用的函 数出现问题的时候,我们可以通过 errno 的值来确定出错的原因,这就会 涉及到一个问题,那就是如何保证 errno 在多线程或者进程中安全?我们希望在多线程或者进程中,每个线程或者进程都拥有自己独立和唯一的一个 errno ,这样就能够保证不会有竞争条 件的出现。一般而言,编译器会自动保证 errno 的安全性,但是为了妥善期间,我们希望在写 makefile 的时 候把 _LIBC_REENTRANT 宏定义,比 如我们在检查 <bits/errno.h> 文件中发现如下的定义:
C代码
# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable. */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));
# if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value. */
# define errno (*__errno_location ())
# endif
# endif /* !__ASSEMBLER__ */
#endif /* _ERRNO_H */
也就是说,在没有定义 __LIBC 或者定义 _LIBC_REENTRANT 的时候, errno 是多线程 / 进程安全的。
一般而言, __ASSEMBLER__, _LIBC 和 _LIBC_REENTRANT 都不会被编译器定义,但是如果我们定义 _LIBC_REENTRANT 一次又何妨那?
为了检测一下你编译器是否定义上述变量,不妨使用下面一个简单程序。
C代码
#include <stdio.h>
#include <errno.h>
int main( void )
{
#ifndef __ASSEMBLER__
printf( "Undefine __ASSEMBLER__\n" );
#else
printf( "define __ASSEMBLER__\n" );
#endif
#ifndef __LIBC
printf( "Undefine __LIBC\n" );
#else
printf( "define __LIBC\n" );
#endif
#ifndef _LIBC_REENTRANT
printf( "Undefine _LIBC_REENTRANT\n" );
#else
printf( "define _LIBC_REENTRANT\n" );
#endif
return 0;
}
希望读者在进行移植的时候,读一下相关的 unix 版本的 <bits/errno.h> 文 件,来确定应该定义什么宏。不同的 unix 版本可能存在着一些小的差别!
有时候,在调用系统调用时,可能会接收到某个信号而导致调用退出。譬如使用system调用某个命令之后该进程会接收到SIGCHILD信号,然后如果这个进程的线程中有慢系统调用,那么接收到该信号的时候可能就会退出,返回EINTR错误码。
EINTR
linux中函数的返回状态,在不同的函数中意义不同:
1)write
表示:由于信号中断,没写成功任何数据。
The call was interrupted by a signal before any data was written.
2)read
表示:由于信号中断,没读到任何数据。
The call was interrupted by a signal before any data was read.
3)sem_wait
函数调用被信号处理函数中断
The call was interrupted by a signal handler.
4)recv
由于信号中断返回,没有任何数据可用。
function was interrupted by a signal that was caught, before any data was available.
调用系统调用的时候,有时系统调用会被中断.此时,系统调用会返回-1,并且错误码被置为EINTR.但是,有时并不将这样的情况作为错误.有两种处理方法:
1.如果错误码为EINTR则重新调用系统调用,例如Postgresql中有一段代码:
retry1:
if (send(port->sock, &SSLok, 1, 0) != 1)
{
if (errno == EINTR)
goto retry1; /* if interrupted, just retry */
}
2.重新定义系统调用,忽略错误码为EINTR的情况.例如,Cherokee中的一段代码:
int cherokee_stat (const char *restrict path, struct stat *buf)
{
int re;
do {
re = stat (path, buf);
} while ((re == -1) && (errno == EINTR));
return re;
}
今天使用select调用的时候总是出错,返回EINTR错误->Interrupted system call,主要是由于代码中调用了signal捕获子进程退出信号SIGCHLD的处理,故我采用忽略EINTR的策略,代码改为如下解决
signal(SIGCHLD,sig_wait);
while(1){
rdset=ctlset;
/* 如果可用处理子进程等于0个,那么select就暂时不再监听连接描述符,由listen函数的backlog控制连接数目队列
if(iavailable_child <= 0)
FD_CLR(ifdlisten, &rdset); // turn off if no available children
*/
iselectret=select(ifdmax+1, &rdset,NULL,NULL,NULL);
if(iselectret<0){
if(errno==EINTR){
// printf("Receives the interrupt signal\n");
continue;
}
else{
printf("select error,will be exit,error msg:%s \n",strerror(errno));
exit(-1);
}
}
---------------------
作者:奔跑吧,行者
来源:CSDN
原文:https://blog.csdn.net/hnlyyk/article/details/51444617
版权声明:本文为博主原创文章,转载请附上博文链接!
linux中对errno是EINTR的处理的更多相关文章
- linux中errno使用(转)
当linux中的C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因,在实际编程中用这一招解决了不少 ...
- Linux中errno使用 - [Linux]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.com/wzgyantai-logs/24470871.html 当linux中的C api函数发 ...
- linux中errno及perror的应用
1 perror 定义在头文件<stdlib.h>中 void perror(const char *s);函数说明 perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 ...
- Linux编程下EAGAIN和EINTR宏的含义及处理
Linux中的EAGAIN含义 在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中). linux下使用write\send ...
- LINUX 内核代码 errno 错误代码提示 /include/asm/errno.h
首先在自己的程序中#include<errno.h> 添加打印errno的语句 printf("errno is: %d\n",errno); 根据errno的值查错. ...
- Linux中的IO复用接口简介(文件监视?)
I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...
- Linux中线程使用详解
线程与进程为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题. 使用多线程的理由之一是和进程相比,它是一种非常"节俭&qu ...
- linux中脚本扑捉(trap)信号问题
扑捉ctrl+c信号: #!/bin/bash trap ; function trap() { echo "You press Ctrl+C."; echo "Exit ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
随机推荐
- BUAA软件工程个人作业-软件案例分析
BUAA个人博客作业-软件案例分析 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件案例分析 我在这个课程的目标是 学习开发软件的能力 这个作 ...
- 单片机stm32F103单片机晶振不起振的原因分析
这是我在做单片机最小系统板时候碰到的问题,之前虽然也做过相似的板子,可是未曾出现过无源晶振不起振的问题.下面是我在遇到问题后的一些检查,排除问题的过程.本人小菜鸟一个,文章中如有错误和不足,还望各位大 ...
- 洛谷 P5658 [CSP-S2019] 括号树
链接: P5658 分析: 显然我们应该在dfs树的同时维护每个点的答案. 注意到第 \(u\) 个点的答案可以分成两部分,不包含 \(u\) 点时的答案,和加入 \(u\) 点后新增的答案,前者可以 ...
- Spring:面向切面编程的AOP
一.前言 除了依赖注入(DI),Spring框架提供的另一个核心功能是对面向方面的编程(AOP)的支持. AOP通常被称为实现横切关注点的工具.横切关注点一词是指应用程序中的逻辑不能与应用程序的其余部 ...
- Verdi UVM Debug Mode 简单使用
转载:Verdi UVM Debug Mode 简单使用_Holden_Liu的博客-CSDN博客 文档与源码: User Guide: UVMDebugUserGuide.pdf in $VERD ...
- xiaoxiaole
common.cpp #include "common.h" common.h #ifndef COMMON_H_INCLUDED #define COMMON_H_INCLUDE ...
- 面试官:JavaScript如何实现数组拍平(扁平化)方法?
面试官:JavaScript如何实现数组拍平(扁平化)方法? 1 什么叫数组拍平? 概念很简单,意思是将一个"多维"数组降维,比如: // 原数组是一个"三维" ...
- sqlldr 导入有中文乱码问题
1.导入成功后,查看导入数据有乱码 2.查看字符集为uft8 select * from v$nls_parameters where PARAMETER like '%NLS_CHARACTERSE ...
- Firefox火狐浏览器提示您的链接并不安全(解决办法)
火狐浏览器不管访问什么,一直提示连接不安全 解决办法: 1.在Firefox地址栏输入"about:config",回车,进入如下图页面 点击"我了解此风险" ...
- es6使用场景
es6非空判断 示例1 es5 if(value !== null && value !== undefined && value !== ''){ //... } e ...