POSIX Timers: Threaded Notification#

Signals Unwanted#

Threaded Timer Expiry Notification#

  • Async signal safety is rather limiting

  • POSIX threads run in a context that is easier

  • Locking and communication primitives

  • Came much later in history (around year 2000, long after epoch)

  • ⟶ Much easier communication from “callback function” into the rest of the process

sigevent event = {0};
event.sigev_notify = SIGEV_THREAD;                     // <-- threaded delivery
event.sigev_notify_function = handler;                 // <-- callback function
// event.sigev_notify_attributes = ...;                // <-- (optional) thread attributes

Code: Periodic Timer, Threaded#

#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <print>

static void handler(union sigval v)                    // <-- callback-data
{
    static const char msg[] = "timer expired\n";
    write(STDOUT_FILENO, msg, sizeof(msg));
}

int main()
{
    timer_t timer;
    sigevent event = {0};
    event.sigev_notify = SIGEV_THREAD;                 // <-- threaded notification
    event.sigev_notify_function = handler;             // <-- function to be called in thread context

    int rv = timer_create(CLOCK_MONOTONIC, &event, &timer);
    if (rv == -1) {
        perror("timer_create");
        return 1;
    }

    /* timer activation */
    struct itimerspec sp = {
        {1,0},
        {3,0},
    };
    rv = timer_settime(timer, 0 /*relative*/,
                       &sp,
                       nullptr);
    if (rv == -1) {
        perror("timer_settime");
        return 1;
    }

    while (true) {
        rv = pause();
        if (rv == -1) { 
            if (errno == EINTR)
                std::println("interrupted");
            else {
                perror("pause");
                return 1;
            }
        }
    }

    return 0;
}

Drawback: Thread Creation#

SIGEV_THREAD
       Notify the process by invoking sigev_notify_function "as  if"  it
       were  the start function of a new thread.  (Among the implementa‐
       tion possibilities here are that each  timer  notification  could
       result  in  the creation of a new thread, or that a single thread
       is created to receive all notifications.)  The  function  is  in‐
       voked with sigev_value as its sole argument.  If sigev_notify_at‐
       tributes  is not NULL, it should point to a pthread_attr_t struc‐
       ture  that  defines  attributes   for   the   new   thread   (see
       pthread_attr_init(3)).
  • “each timer notification could result in the creation of a new thread”

  • Exactly that is the case

  • Thread creation is not free

  • ⟶ Might impose performance problems for high frequency timers

$ strace -f ./sysprog-timers-threaded-periodic
...
[pid 1235513] clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f270ba0d990, parent_tid=0x7f270ba0d990, exit_signal=0, stack=0x7f270b20d000, stack_size=0x7fff40, tls=0x7f270ba0d6c0} => {parent_tid=[1235530]}, 88) = 1235530
...