-3

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.

George Sp
  • 553
  • 5
  • 20
  • 1
    Linux, debian in particular. – George Sp Apr 12 '19 at 18:19
  • For either _`select()` and `poll()`_ there are variants to wait with specific timeouts specified by you. Also see [1](https://stackoverflow.com/questions/9494626/c-select-not-waiting-for-timeout-period), – πάντα ῥεῖ Apr 12 '19 at 18:23
  • Please provide at least some example of your code and also explain what exactly isn't working. – r3mus n0x Apr 12 '19 at 18:24
  • @πάνταῥεῖ I know, but I can not figure out how to do it. Can you provide an example? – George Sp Apr 12 '19 at 18:24
  • Show us the code which doesn't work for you, and explain what is not up to your liking. – SergeyA Apr 12 '19 at 18:25
  • So what happens when you run this code? – SergeyA Apr 12 '19 at 18:34
  • It just waits on open() and poll never returns. – George Sp Apr 12 '19 at 18:38
  • @GeorgeSp Yup, you need to timeout `open` too or it'll block indefinitely, waiting for a writing to open it too. Signals+timer are the way to go in that regard. See my answer. – Petr Skocik Apr 12 '19 at 18:45
  • @GeorgeSp Maybe tag it C also? POSIX functions are C APIs and even in your example you're not using a lot of the ++. (You might get a friendlier reception with C programmers too.) – Petr Skocik Apr 12 '19 at 18:48
  • @PSkocik indeed I could use C tag probably. I will go with your approach on the answer below and see what happens. It is a clever workaround that I haven't seen before, I wish I have thought of it too. – George Sp Apr 12 '19 at 19:32

1 Answers1

1

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).

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142