Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

make open() return when signal is caught

Tags:

c

linux

signals

When I call open("./fifo",O_RDONLY), the syscall will block because no one is writing to the fifo ./fifo. If a signal is received during that time that has no signal handler, the process ends instantly. So far so good. But when a signal is received that has a signal handler, the signal handler is executed and the open() syscall is still blocking.

How can I make open() return when I catch the signal?

I tried to block the signal, that does not work because there is no sigmask argument for open() like there is for pselect(). Using O_NONBLOCK does not work either, because then open() will return with an error, whether there is a signal or not. Removing the signal handler is also no good because I want to be able to react to the signal.

My test code:

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static volatile bool end=0;

static void catchSignal(int signal)
{
  (void)signal;
  const char *s="Catched Signal\n";
  write(STDERR_FILENO,s,strlen(s));
  end=1;
}

static int openFile(void)
{
  int fd=open("./in",O_RDONLY);
  if(fd<0)
  {
    perror("can't open file");
    exit(1);
  }
  return fd;
}


int main()
{
  if(SIG_ERR==signal(SIGTERM,catchSignal))
  {
    perror("cant set up signal handler");
    return -1;
  }
  int fd = openFile();
  while(end==0)
  {
    puts("Still running");
    usleep(300UL*1000);
  }
  puts("End now");
  if(fd>0)
  {
    close(fd);
  }
  return 0;
}
like image 602
12431234123412341234123 Avatar asked Oct 24 '25 05:10

12431234123412341234123


1 Answers

The signal() function is problematic because of a history of implementations with different details. According to its Linux manual page:

The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal() to establish a signal handler vary across systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.

(Emphasis in the original)

Instead of signal(), you should be using sigaction():

  struct sigaction sa = { .sa_handler = catchSignal };

  if (SIG_ERR == sigaction(SIGTERM, &sa, NULL))

Note that among the fields of a struct sigaction is sa_flags, a bitmask with which you can select among the various behaviors historically implemented by different versions of signal(). In particular, if you do not include the SA_RESTART flag, as the above indeed does not, then you should not see system calls automatically resume when interrupted by a signal (except for those few that are explicitly specified to do so).

like image 161
John Bollinger Avatar answered Oct 26 '25 20:10

John Bollinger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!