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