POSIX Timers: Threaded Notification#
Signals Unwanted#
Signal handling is hard (see Async-Signal-Safety)
Creative ways have been found around its peculiarities (Use Case: Self-Pipe Trick)
Historically, asynchronous delivery has been the only way to notify processes of something outside of their immediate control
Well understood though
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
...