blj28

导航

select() 出现interrupted system call如何解决

select 出现 returns interrupted system call的报错处理方式

 

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

    一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?早期UNIX系统的做法是, 中断系统调用, 并让系统调用失败, 比如read返回 -1, 同时设置 errno 为 EINTR中断了的系统调用是没有完成的调用, 它的失败是临时性的, 如果再次调用则可能成功, 这并不是真正的失败, 所以要对这种情况进行处理, 典型的方式为:

复制代码
while (1) {

    n = read(fd, buf, BUFSIZ);

    if (n == -1 && errno != EINTR) {

        printf("read error\n");

        break;

    }

    if (n == 0) {

        printf("read done\n");

        break;

    }

}
复制代码

这样做逻辑比较繁琐, 事实上, 我们可以从信号的角度来解决这个问题,  安装信号的时候, 设置 SA_RESTART属性, 那么当信号处理函数返回后, 被该信号中断的系统调用将自动恢复.

示例程序:

复制代码
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <unistd.h>

void sig_handler(int signum)
{
    printf("in handler\n");
    sleep(1);
    printf("handler return\n");
}

int main(int argc, char **argv)
{
    char buf[100];
    int ret;
    struct sigaction action, old_action;

    action.sa_handler = sig_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    /* 版本1:不设置SA_RESTART属性
     * 版本2:设置SA_RESTART属性 */
    //action.sa_flags |= SA_RESTART;

    sigaction(SIGINT, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGINT, &action, NULL);
    }

    bzero(buf, 100);

    ret = read(0, buf, 100);
    if (ret == -1) {
        perror("read");
    }

    printf("read %d bytes:\n", ret);
    printf("%s\n", buf);

    return 0;
}
复制代码

当sa_flags不设置:SA_RESTART时:

结果:

QQ截图20130715193553

设置后:

当被中断后,重新执行

QQ截图20130715193845

man帮助说明:

Interruption of system calls and library functions by signal handlers
       If a signal handler is invoked while a system call or library
       function call is blocked, then either:

       * the call is automatically restarted after the signal handler
         returns; or

       * the call fails with the error EINTR.

       Which of these two behaviors occurs depends on the interface and
       whether or not the signal handler was established using the
       SA_RESTART flag (see sigaction(2)).  The details vary across UNIX
       systems; below, the details for Linux.

       If a blocked call to one of the following interfaces is interrupted
       by a signal handler, then the call will be automatically restarted
       after the signal handler returns if the SA_RESTART flag was used;
       otherwise the call will fail with the error EINTR:

           * read(2), readv(2), write(2), writev(2), and ioctl(2) calls on
             "slow" devices.  A "slow" device is one where the I/O call may
             block for an indefinite time, for example, a terminal, pipe, or
             socket.  (A disk is not a slow device according to this
             definition.)  If an I/O call on a slow device has already
             transferred some data by the time it is interrupted by a signal
             handler, then the call will return a success status (normally,
             the number of bytes transferred).

           * open(2), if it can block (e.g., when opening a FIFO; see
             fifo(7)).

* wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2). * Socket interfaces: accept(2), connect(2), recv(2), recvfrom(2), recvmsg(2), send(2), sendto(2), and sendmsg(2), unless a timeout has been set on the socket (see below). * File locking interfaces: flock(2) and fcntl(2) F_SETLKW. * POSIX message queue interfaces: mq_receive(3), mq_timedreceive(3), mq_send(3), and mq_timedsend(3). * futex(2) FUTEX_WAIT (since Linux 2.6.22; beforehand, always failed with EINTR). * POSIX semaphore interfaces: sem_wait(3) and sem_timedwait(3) (since Linux 2.6.22; beforehand, always failed with EINTR). The following interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler: * Socket interfaces, when a timeout has been set on the socket using setsockopt(2): accept(2), recv(2), recvfrom(2), and recvmsg(2), if a receive timeout (SO_RCVTIMEO) has been set; connect(2), send(2), sendto(2), and sendmsg(2), if a send timeout (SO_SNDTIMEO) has been set.
       * Interfaces used to wait for signals: pause(2), sigsuspend(2),
             sigtimedwait(2), and sigwaitinfo(2).

           * File descriptor multiplexing interfaces: epoll_wait(2),
             epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).

           * System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
             semtimedop(2).

           * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and
             usleep(3).

           * read(2) from an inotify(7) file descriptor.

           * io_getevents(2).

       The sleep(3) function is also never restarted if interrupted by a
       handler, but gives a success return: the number of seconds remaining
       to sleep.



Does anyone know what this means? I mean short of the works, how can
this happen and what do I do when I receive this error. What state am
I in. Can I select() again? I get this error from strerror() on errno.
I look at the man page for select and it doesnt even say it returns
this error. The man page is pretty old though. I would appreciate
any help.
 

I got great help from a lot of you and I really appreciate it. What
I understand now is that the timeout that I am giving select is the
absolute longest time it will check for date. If some signal happens
the select() could fail and cut the timeout short. Not a problem, I
can work with it.

 

: > Does anyone know what this means?: It means that a signal arrived while select() was waiting, and

interrupted it, causing select() to return -1 and set errno to EINTR.

: > I mean short of the works, how can this happen and what do I do when I receive this error. What state am I in. Can I select() again?

 

 

You can avoid that when you setup the signal handlers with
sigaction() and set the SA_RESTART flag bit. Then these signals won't interrupt it
(you could block the others with sigsetmask() if you want)

-Andi

 I just thought I'd point out that using SA_RESTART isn't as portable as doing the restarting yourself. Keeping this sort of thing in mind helps you write Unix software as opposed to Linux software.

--
Doug DeJulio | mailto:d...@hks.net
HKS, Incorporated | http://www.hks.net/

 Hmm? SA_RESTART is defined by POSIX and Unix95/98. I doubt that you can find any Unix or Unix like system delivered in the last few years that

won't support it.On older BSD systems (or Linux with -lbsd) signal() defaults to SA_RESTART.I think POSIX.1 is to use as the minimal common subset for portable Unix

programs.

Or do you write C in K&R C instead of ISO/ANSI C89 too?


-Andi

 

No, SA_RESTART is not defined by POSIX.1.

It's defined by SVR4 and 4.3+BSD, so it's fairly common, but it's not
part of POSIX.1. Further, whether a given system's default is to
restart system calls or not isn't defined by POSIX.

(Source: "Advanced Programming in the UNIX Environment", by Stevens,
pages 277 and 297.)

 

 

 
 
In article <m3iul1j...@fred.muc.de>, <a...@muc.de> wrote:
>
>You can avoid that when you setup the signal handlers with
>sigaction() and set the SA_RESTART flag bit. Then these signals won't interrupt it
>(you could block the others with sigsetmask() if you want)

Actually, with select(), SA_RESTART won't help. Select will _always_
cause an EINTR even with re-startable signals if you have a signal
handler..

Why? BSD behaviour. And BSD is where both select() and restartable
system calls came from.

(Linux doesn't guarantee the same sort of restartability as BSD, but we
try to have a "least surprises" kind of behaviour. POSIX specifies that
some systems may have ways of making system calls restartable, but also
specifies that behaviour is not defined or uniform..).

Linus

 

>
> It's defined by SVR4 and 4.3+BSD, so it's fairly common, but it's not
> part of POSIX.1. Further, whether a given system's default is to
> restart system calls or not isn't defined by POSIX.
>
> (Source: "Advanced Programming in the UNIX Environment", by Stevens,
> pages 277 and 297.)

Stevens got this wrong. The Posix.1 book put out by the IEEE ~1991
definitely specified the behavior of SA_RESTART.

I believe the book I am remembering is:

"Information Technology-Portable Operating System Interface (Posix :
Part 1 : System Application Program Interface)"
Technical Committee on Operating Systems and Operational Environments;
Paperback;

(Unfortunately it is apparently out of print. Or has it been superceded
by a new book?)

In any event HP-UX, AIX, Solaris, Linux, SYSVR4 and *BSD all implement
it.

-Rob

posted on 2023-02-10 09:29  bailinjun  阅读(2231)  评论(0编辑  收藏  举报