Home > Mobile >  libuv signal handling in multithreaded programs
libuv signal handling in multithreaded programs

Time:11-11

In a multithreaded C program where the main thread is executing a libuv event loop, is it guaranteed that this event loop thread is executing signal handlers registered using uv_signal_start?

Background information:

From http://docs.libuv.org/en/v1.x/design.html

The I/O (or event) loop is [...] meant to be tied to a single thread.

But as we are in a multithreaded program, signal handlers can be executed by other threads

According to POSIX.1, a process-directed signal (sent using kill(2), for example) should be handled by a single, arbitrarily selected thread within the process.

So my question is basically whether libuv signal handling works as advertised

Signal handles implement Unix style signal handling on a per-event loop bases.

even in multithreaded programs.

CodePudding user response:

TLDR: Yes, should work as advertised.

From my understanding of libuv's source code unix/signal.c there is a generic signal handler

static void uv__signal_handler(int signum) {
  uv__signal_msg_t msg;
  uv_signal_t* handle;
  int saved_errno;

  saved_errno = errno;
  memset(&msg, 0, sizeof msg);

  if (uv__signal_lock()) {
    errno = saved_errno;
    return;
  }

  for (handle = uv__signal_first_handle(signum);
       handle != NULL && handle->signum == signum;
       handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
    int r;

    msg.signum = signum;
    msg.handle = handle;

    /* write() should be atomic for small data chunks, so the entire message
     * should be written at once. In theory the pipe could become full, in
     * which case the user is out of luck.
     */
    do {
      r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
    } while (r == -1 && errno == EINTR);

    assert(r == sizeof msg ||
           (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));

    if (r != -1)
      handle->caught_signals  ;
  }

  uv__signal_unlock();
  errno = saved_errno;
}

in which a pipe handle->loop->signal_pipefd[1] is used to tell the handle's associated loop abount the incoming signal. Indeed, this generic signal handler can be called from any thread, however the libuv thread will then call the user's specific signal handler registered with uv_signal_start in the event loop thread (main thread in my setting) when it reads the signal_pipefd[1] in the next loop iteration.

This was for the unix source code and the windows win/signal.c source has a similar mechanism.

So the answer should be yes, it should also work as advertised in a multithreaded setting, i.e. the registered handler will be executed by the loop thread.

  • Related