,就会调用返回错误(一般为-1)&&设置errno为EINTR(相应的错误描述为“Interrupted system call”)。 如下表所示的系统调用就会产生EINTR错误,当然不同的函数意义也不同。 系统调用函数 errno为EINTR表征的意义 write 由于信号中断,没写成功任何数据。 EINTR(相应的错误描述为“Interrupted system call”)。 怎么看哪些系统条用会产生EINTR错误呢?man 7 signal,在ubuntu 10.04上可以查看,哪些系统调用会产生 EINTR错误。 此时msgsnd/msgrcv将返回-1,errno被设置为EINTR。且即使在插入信号时设置了SA_RESTART,也无效。
连接的过程中,可能会遇到以下errno:EAGAIN或EWOULDBLOCK:表示当前没有连接可以接受,非阻塞模式下可以继续尝试接受连接ECONNABORTED:表示连接因为某种原因被终止,可以重新尝试接受连接EINTR :表示系统调用被中断,可以重新尝试接受连接EINVAL:表示套接字不支持接受连接操作,需要检查套接字是否正确其中 EINTR、EAGAIN与EWOULDBLOCK,表示可能遇到了系统中断,需要对这些errno */#define EVUTIL_ERR_ACCEPT_RETRIABLE(e)\((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e) || (e) == ECONNABORTED */#define EVUTIL_ERR_CONNECT_RETRIABLE(e)\\((e) == EINTR || (e) == EINPROGRESS || (e) == EALREADY)// 连接的读写在 Linux 网络编程中,连接读写阶段可能会遇到以下 errno:EINTR:表示系统调用被中断,可以重新尝试读写EAGAIN 或 EWOULDBLOCK:表示当前没有数据可读或没有缓冲区可写
si_signo=SIGIO, si_code=SI_USER, si_pid=12771, si_uid=0} --- rt_sigreturn({mask=[]}) = -1 EINTR si_signo=SIGIO, si_code=SI_USER, si_pid=12850, si_uid=0} --- rt_sigreturn({mask=[]}) = -1 EINTR si_signo=SIGIO, si_code=SI_USER, si_pid=12905, si_uid=0} --- rt_sigreturn({mask=[]}) = -1 EINTR si_signo=SIGIO, si_code=SI_USER, si_pid=12925, si_uid=0} --- rt_sigreturn({mask=[]}) = -1 EINTR si_signo=SIGIO, si_code=SI_USER, si_pid=12956, si_uid=0} --- rt_sigreturn({mask=[]}) = -1 EINTR
} } void my_lock_release() { while (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) { if (errno == EINTR flags, mode_t mode) { int fd; while ( (fd = open(pathname, flags, mode)) < 0) { if (errno == EINTR ret; while ( (ret = select(nfds, readfds, writefds, exceptfds, timeout)) < 0) { if (errno == EINTR void *buf, size_t count) { int ret; while ( (ret = read(fd, buf, count)) < 0) { if (errno == EINTR return ret; } void Dup2(int oldfd, int newfd) { while (dup2(oldfd, newfd) < 0) { if (errno == EINTR
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应处理函数返回时,该系统调用可能返回一个EINTR错误。所以,我们必须对慢系统调用返回的EINTR有所准备。 accept,可以改成如下形式: for (...) { if((connfd=accept(listenfd,NULL, NULL)) < 0) { if (errno == EINTR 如果该函数返回EINTR,我们就不能再次调用它,否则将立即返回一个错误。当connect被一个捕获信号中断而且不自动重启时,我们必须调用select来等待连接完成。
again: if ((n = accept(fd, sa, salenptr)) < 0) { if ((errno == ECONNABORTED) || (errno == EINTR nbytes) { ssize_t n; again: if ((n = write(fd, ptr, nbytes)) == -1) { if (errno == EINTR while (nleft > 0) { if ((nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR ) { if ((nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR again: if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR
EINTR A signal was caught; see signal(7). ENOMEM unable to allocate memory for internal tables. select的答案是:会返回-1,并置EINTR=4(Interrupted system call 收到信号后,系统会跳转到信号处理函数,如果当前正在做一些IO相关的系统调用,例如上面的select,会直接失败返回EINTR。 所以在底层代码经常看到这样写的select: while ((ready = select(nfds, &readfds, NULL, NULL, pto)) == -1 && errno == EINTR } int ready; while ((ready = select(nfds, &readfds, NULL, NULL, pto)) == -1 && errno == EINTR
{ int n; again: if ( (n = accept(fd, sa, salenptr)) < 0 ) { if ((errno == ECONNABORTED) (errno == EINTR void* ptr, size_t nbytes) { ssize_t n; again: if ( (n = read(fd, ptr, nbytes)) == -1) { if (errno == EINTR ptr = vptr; nleft = n; while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0 ) { if (errno == EINTR n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0 ) { if (errno == EINTR
accept(sockfd, (struct sockaddr *)&client_addr, NULL); if(clientfd < 0) { if(error == EINTR accept(sockfd, (struct sockaddr *)&client_addr, NULL); if(clientfd < 0) { if(error == EINTR { print_dbg(0, "accept dumpt\n"); break; } } 从上面的代码可以看出,当错误号为EINTR buf, size_t len, int flag) { int size = recv(fd, buf, len, flag); if (size < 0) { if (errno == EINTR char *buf, size_t len, int flag) { int size = send(fd, buf, len, flag); if (size < 0) if (errno == EINTR
{ int n; again: if ( (n = accept(fd, sa, salenptr)) < 0 ) { if ((errno == ECONNABORTED) (errno == EINTR void* ptr, size_t nbytes) { ssize_t n; again: if ( (n = read(fd, ptr, nbytes)) == -1) { if (errno == EINTR ptr = vptr; nleft = n; while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0 ) { if (errno == EINTR n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0 ) { if (errno == EINTR
EINTR A signal was caught; see signal(7). ENOMEM unable to allocate memory for internal tables. select的答案是:会返回-1,并置EINTR=4(Interrupted system call 收到信号后,系统会跳转到信号处理函数,如果当前正在做一些IO相关的系统调用,例如上面的select,会直接失败返回EINTR。 所以在底层代码经常看到这样写的select: while ((ready = select(nfds, &readfds, NULL, NULL, pto)) == -1 && errno == EINTR } int ready; while ((ready = select(nfds, &readfds, NULL, NULL, pto)) == -1 && errno == EINTR
// accept阻塞的时候被信号中断, 处理信号对应的操作之后(比如子进程终止,收到信号后去回收子进程) // 回来之后不阻塞了, 直接返回-1, 这时候 errno==EINTR *)&client_addr, &cli_len); //解决方法就是,在一个循环中判断,如果accept阻塞过程中被信号打断 //也就是返回值-1且errno == EINTR /*这里的cfd虽然只定义了一个,但是在每个子进程中都会有一个拷贝,并且修改一个子进程的cfd不会影响其它子进程*/ while(cfd == -1 && errno == EINTR ((n = accept(fd, sa, salenptr)) < 0) { //ECONNABORTED 发生在重传(一定次数)失败后,强制关闭套接字 //EINTR 函数在阻塞时被信号打断,处理完信号 //返回时就不会在阻塞了,而是直接返回-1 if ((errno == ECONNABORTED) || (errno == EINTR
成功写入的数据长度(Byte); 等于0: 对端关闭连接; 等于-1: tcp窗口太小,数据暂时发不出去,也就是缓冲区满了,errno=EWOULDBLOCK或EAGIN 被信号中断,需要重试,errno=EINTR 函数返回值 大于0: 成功接收的数据长度(Byte); 等于0: 对端关闭连接; 等于-1: 再当前缓冲区无可读数据,errno=EWOULDBLOCK或EAGIN 被信号中断,需要重试,errno=EINTR
"ThreadingUnixStreamServer", "ThreadingUnixDatagramServer"]) # 出现 EINTR 则重新调用 def _eintr_retry(func, *args): """restart a system call interrupted by EINTR""" while = errno.EINTR: raise BaseServer RequestHandlerClass 注册 handle 函数。 __shutdown_request: # 调用 select 监视请求,处理 EINTR 异常 r, w, e = _eintr_retry = errno.EINTR: break # Now reap all defunct children.
while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0) {//循环读取 if (errno == EINTR { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR
= EINTR) break; } else if (ret == 0) { //select 函数超时 = EINTR) break; } else if (ret == 0) { //select函数超时 = EINTR) break; } else if (n == 0)
{ int n; again: if ( (n = accept(fd, sa, salenptr)) < 0 ) { if ((errno == ECONNABORTED) (errno == EINTR void* ptr, size_t nbytes) { ssize_t n; again: if ( (n = read(fd, ptr, nbytes)) == -1) { if (errno == EINTR ptr = vptr; nleft = n; while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0 ) { if (errno == EINTR n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0 ) { if (errno == EINTR
signal(SIGALRM, handler); alarm(5); int ret = read(fd, buf, sizeof(buf)); if (ret == -1 && errno == EINTR = select(fd + 1, NULL, &write_fdset, NULL, &timeout); } while (ret < 0 && errno == EINTR = select(fd + 1, &accept_fdset, NULL, NULL, &timeout); } while (ret < 0 && errno == EINTR select(fd + 1, NULL, &connect_fdset, NULL, &timeout); } while (ret < 0 && errno == EINTR 如果select返回-1且errno 为EINTR,说明是被信号中断,需要重启select;如果select返回0表示超时;如果select返回1表示检测到可读事件;否则select返回-1 表示出错。
当剩余需要读取的个数>0 { if((nread = read(fd,bufp,nleft)) < 0)//成功读取的个数小于0,则判断出错的原因 { //如果errno被设置为EINTR if(errno == EINTR) { continue; } perror("write"); exit(-1); } //如果写入成功的个数<0 判断是否是被信号打断 if((nwritten = write(fd,bufp,nleft)) < 0) { if(errno == EINTR if(errno == EINTR) { continue; } perror("write"); exit(-1); } //如果写入成功的个数<0 判断是否是被信号打断 if((nwritten = write(fd,bufp,nleft)) < 0) { if(errno == EINTR
需要注意的是:linux平台上connect()暂时不能完成返回-1,错误码可能是EINPROGRESS,也可能是由于被信号给中断了,这个时候错误码是:EINTR。 = WSAEWOULDBLOCK) return false; //linux下需要检测EINPROGRESS和EINTR /* if (ret = EINTR)) return false; */ fd_set writeset; FD_ZERO(&writeset); FD_SET 还有个区别上文也说过,就是windows下发数据的代码稍微有点不同的就是不需要检测错误码是EINTR,只需要检测是否是WSAEWOULDBLOCK。 对于很多linux网络函数,如connect、send、recv、epoll_wait等,当这些函数出错时,一定要检测错误是不是EINTR,因为如果是这种错误,其实只是被信号中断了,函数调用并没用出错,