POSIX Timers: Arming (Oneshot/Periodic)#
To show how to setup (“arm”) oneshot and periodic timers, this section uses signals as a timer expiration delivery mechanism. There is also a “threaded” delivery, this will be covered in POSIX Timers: Threaded Notification. The mechanism how timer are armed stays the same, no matter what delivery option is used.
Basics#
POSIX timers:
timer_create()(andtimer_delete(), mostly unused in examples)Highly configurable (via
struct sigevent)Choose signal to use
Signals that are used for timer expiry notification are never queued - not even realtime signals (see Realtime Signals)
event.sigev_notify = SIGEV_SIGNAL; // <-- notification type (SIGEV_THREAD?)
event.sigev_signo = SIGRTMIN; // <-- send SIGRTMIN at expiry
Setup handler for signal (see Asynchronous Signal Handling)
Arm timer using
timer_settime()
Arming: struct itimerspec#
#include <time.h>
struct timespec {
time_t tv_sec; /* Seconds */
/* ... */ tv_nsec; /* Nanoseconds [0, 999'999'999] */
};
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer */
struct timespec it_value; /* Initial expiration */
};
it_interval: periodic timer{0,0} for one-shot timer
Code: One-shot Timers#
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <print>
static void handler(int signal)
{
static const char msg[] = "signal handler\n";
write(STDOUT_FILENO, msg, sizeof(msg));
}
int main()
{
/* timer creation */
timer_t timer; // <-- timer handle
sigevent event = {0};
event.sigev_notify = SIGEV_SIGNAL; // <-- expiry by signal ...
event.sigev_signo = SIGRTMIN; // <-- ... namely SIGRTMIN
int rv = timer_create(CLOCK_MONOTONIC, &event, &timer);
if (rv == -1) {
perror("timer_create");
return 1;
}
/* timer signal handling */ // <-- (nothing new)
struct sigaction sa = { 0 };
sa.sa_handler = handler;
rv = sigaction(SIGRTMIN, &sa, nullptr);
if (rv == -1) {
perror("sigaction");
return 1;
}
/* timer activation */
struct itimerspec sp = {
.it_interval = {.tv_sec=0, .tv_nsec=0}, // <-- zero interval -> one-shot
.it_value = {.tv_sec=3, .tv_nsec=0}, // <-- expire after {sec,nsec}
};
rv = timer_settime(timer, 0 /*relative*/,
&sp,
nullptr);
if (rv == -1) {
perror("timer_settime");
return 1;
}
rv = pause();
if (rv == -1) {
if (errno == EINTR)
std::println("interrupted");
else {
perror("pause");
return 1;
}
}
return 0;
}
Code: Periodic Timers#
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <print>
static void handler(int signal)
{
static const char msg[] = "timer expired\n";
write(STDOUT_FILENO, msg, sizeof(msg));
}
int main()
{
/* timer creation */
timer_t timer;
sigevent event = {0};
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGRTMIN;
int rv = timer_create(CLOCK_MONOTONIC, &event, &timer);
if (rv == -1) {
perror("timer_create");
return 1;
}
/* timer signal handling */
struct sigaction sa = { 0 };
sa.sa_handler = handler;
rv = sigaction(SIGRTMIN, &sa, nullptr);
if (rv == -1) {
perror("sigaction");
return 1;
}
/* timer activation */
struct itimerspec sp = {
{1,0}, // <-- periodic interval
{3,0}, // <-- first expiration
};
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;
}