← Back to context

Comment by tlsalmin

1 month ago

First nitpick:

   static int pipe_fd[2] = {0};

0 is valid fd, so I recommend initializing fds to -1.

signalfd was just off-hand mentioned, but for writing anything larger, like lets say a daemon process, it keeps things close to all the other events being reacted to. E.g.

  #include <signal.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <sys/timerfd.h>
  #include <sys/signalfd.h>
  #include <sys/epoll.h>

  static int signalfd_init(void)
    {
      sigset_t sigs, oldsigs;
      int sfd = -1;

      sigemptyset(&sigs);
      sigemptyset(&oldsigs);
      sigaddset(&sigs, SIGCHLD);
      if (!sigprocmask(SIG_BLOCK, &sigs, &oldsigs))
        {
          sfd = signalfd(-1, &sigs, SFD_CLOEXEC | SFD_NONBLOCK);
          if (sfd != -1)
            {
              // Success
              return sfd;
            }
          else
            {
              perror("signalfd");
            }
          sigprocmask(SIG_SETMASK, &oldsigs, NULL);
        }
      else
        {
          perror("sigprocmask");
        }
      return -1;
    }

  static int timerfd_init(void)
    {
      int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);

      if (tfd != -1)
        {
          struct itimerspec tv =
            {
              .it_value = 
                {
                  .tv_sec = 5
                }
            };
          if (!timerfd_settime(tfd, 0, &tv, NULL))
            {
              return tfd;
            }
          else
            {
              perror("timerfd_settime");
            }
          close(tfd);
        }
      else
        {
          perror("timerfd_create");
        }
      return -1;
    }

  static int epoll_init(int sfd, int tfd)
    {
      int efd;

      if (!sfd || !tfd)
        {
          return -1;
        }

      efd = epoll_create1(EPOLL_CLOEXEC);
      if (efd != -1)
        {
          struct epoll_event ev[2] =
            {
                {
                  .events = EPOLLIN,
                  .data =
                    {
                      .fd = sfd,
                    }
                },
                {
                  .events = EPOLLIN,
                  .data = 
                    {
                      .fd = tfd
                    }
                }
            };
          if (!epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &ev[0]) &&
              !epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev[1]))
            {
              return efd;
            }
          else
            {
              perror("epoll_ctl");
            }
          close(efd);
        }
      else
        {
          perror("epoll_create1");
        }
      return -1;
    }

  int main(int argc, char *argv[])
    {
      int exit_value = EXIT_FAILURE;
      int sfd = signalfd_init(),
          tfd = timerfd_init(),
          efd = epoll_init(sfd, tfd);

      if (sfd != -1 && tfd != -1 && efd != -1)
        {
          int child_pid = fork();

          if (child_pid != -1)
            {
              if (!child_pid)
                {
                  argv += 1;
                  if (-1 == execvp(argv[0], argv)) {
                      exit(EXIT_FAILURE);
                  }
                  __builtin_unreachable();
                }
              else
                {
                  int err;
                  struct epoll_event ev;

                  while ((err = epoll_wait(efd, &ev, 1, -1)) > 0)
                    {
                      if (ev.data.fd == tfd)
                        {
                          // Read the signalfd for the possible SIGCHLD and
                          exit_value = EXIT_SUCCESS;
                        }
                      else if (ev.data.fd == tfd)
                        {
                          // Timer triggered, kill the child process.
                        }
                    }
                  if (err == -1)
                    {
                      perror("epoll_wait");
                    }
                }
            }
          else
            {
              perror("fork");
            }
        }
      close(sfd);
      close(tfd);
      close(efd);
      exit(exit_value);
    }