Search code examples
c++linuxnamed-pipespolling

How can I wait for n seconds for a named pipe to open?


I have a program that I want to exit when I can not open a pipe for read, after N (lets say 30) seconds.

My code works with blocking name pipes and I can not change this.

I know about select() and poll() but I can not get them to work without turning my pipes into non-blocking.

This is my code so far:

struct pollfd fds[1];
int pol_ret;

fds[0].fd = open(pipe_name, O_RDONLY /* | O_NONBLOCK */);

if (fds[0].fd < 0)
{
    // send_signal_to_parent();
    std::cout << "error while opening the pipe for read, exiting!" << '\n';
    return -1;
}

fds[0].events = POLLIN;

int timeout_msecs = 30000;    //  (30 seconds)
pol_ret = poll(fds, 1, timeout_msecs);

std::cout << "poll returned: "<< pol_ret << '\n';
 if (pol_ret == 0)
 {
     std::cout << "im leaving" << '\n';
     return -1;    
 }

How can I wait only for 30 seconds for a pipe to open for read?

I'm running Linux, debian in particular.


Solution

  • Setup up a timer with a signal handler and wait call open on the fifo. If the open fails with errno=EINTR and your handler ran, the open call was interrupted by your timer, i.e., it timed out.

    Example code:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <signal.h>
    #include <unistd.h>
    #include <errno.h>
    #include <fcntl.h>
    
    volatile sig_atomic_t abort_eh;
    void handler(int Sig)
    {
        abort_eh = 1;
    }
    
    int main()
    {
        struct sigaction sa;
        sa.sa_flags = 0;
        sa.sa_handler = handler;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGALRM,&sa,0);
    
        //try to ensure the fifo exists
        (void)mkfifo("fifo",0600);
    
        //open with a timeout of 1s
        alarm(1);
    
        int fd;
        do{
            if (0>(fd=open("fifo",O_RDONLY)))
                if(errno==EINTR){
                    if(abort_eh) return puts("timed out"),1;
                    else continue; //another signal interrupted it, so retry
                }else return perror("open"),1;
        }while(0);
    
        alarm(0); //cancel timer
        printf("sucessfully opened at fd=%d\n", fd);
    
    }
    

    setitimer or timer_create/timer_settime provide better more fine grained timers than alarm. They also have the possibility of setting the timer to repeat which allows you to resignal in case the first signal "missed" (i.e., ran just before the open call was entered and so failed to break the potentially indefinitely blocking syscall).