POSIX Timers: Additional Information (siginfo_t)#
siginfo_t: A Bag Of Further Information#
Look into man -s 2 sigaction
That structure contains a whole lot of information across all signals (for example,
SIGSEGVpopulates a number of hardware specific fields)What remains for our purposes:
union sigvalcontaining either anintor avoid*Specified in
timer_create(..., struct sigevent*, ...)Echoed back in signal handler
sigaction:SA_SIGINFOTogether with a different handler
#include <signal.h>
siginfo_t {
...
union sigval si_value;
...
};
union sigval {
int sival_int;
void *sival_ptr;
};
Code: Pass Additional Expiry Information#
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <print>
static void handler(int signal,
siginfo_t *info, // <-- signal *parameter*
void *ucontext) // <-- unused
{
char msg[64] = {0};
sprintf(msg, "signal handler: %d\n", info->si_value.sival_int);
write(STDOUT_FILENO, msg, strlen(msg));
}
int main()
{
timer_t timer;
sigevent event = {0};
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGRTMIN;
event.sigev_value.sival_int = 42; // <-- additional info to be echoed back at expiration
int rv = timer_create(CLOCK_MONOTONIC, &event, &timer);
if (rv == -1) {
perror("timer_create");
return 1;
}
struct sigaction sa = { 0 };
sa.sa_flags = SA_SIGINFO; // <-- request additional info with signal
sa.sa_sigaction = handler; // <-- different handler!
rv = sigaction(SIGRTMIN, &sa, nullptr);
if (rv == -1) {
perror("sigaction");
return 1;
}
struct itimerspec sp = {
.it_interval = {.tv_sec=0, .tv_nsec=0},
.it_value = {.tv_sec=3, .tv_nsec=0},
};
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;
}
Use Case: Multiple Timers, Single Signal Handler#
Can create more timers than signals available
⟶ Use one signal for multiple timers
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <print>
#include <iostream>
static timer_t timer1, timer2; // <-- global (to share with handler)
static void handler(int signal, siginfo_t* info, void* ctx)
{
const timer_t* timer = (const timer_t*)info->si_value.sival_ptr;
const char* msg;
if (timer == &timer1) // <-- passed via event1 below
msg = "timer1 expired\n";
else if (timer == &timer2) // <-- passed via event2 below
msg = "timer2 expired\n";
else
abort();
write(STDOUT_FILENO, msg, strlen(msg));
}
int main()
{
/* timer creation */ // <-- create two timers
sigevent event1 = {0};
event1.sigev_notify = SIGEV_SIGNAL;
event1.sigev_signo = SIGRTMIN;
event1.sigev_value.sival_ptr = &timer1; // <-- pass timer1 into handler
int rv = timer_create(CLOCK_MONOTONIC, &event1, &timer1);
if (rv == -1) {
perror("timer_create (1)");
return 1;
}
sigevent event2 = {0};
event2.sigev_notify = SIGEV_SIGNAL;
event2.sigev_signo = SIGRTMIN;
event2.sigev_value.sival_ptr = &timer2; // <-- pass timer2 into handler
rv = timer_create(CLOCK_MONOTONIC, &event2, &timer2);
if (rv == -1) {
perror("timer_create (2)");
return 1;
}
/* timer signal handling */
struct sigaction sa = { 0 };
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
rv = sigaction(SIGRTMIN, &sa, nullptr);
if (rv == -1) {
perror("sigaction");
return 1;
}
/* timer1 activation */
struct itimerspec sp1 = {
{1,0}, // <-- 1s period
{3,0}, // <-- initial expiration in 3s
};
rv = timer_settime(timer1, 0 /*relative*/,
&sp1,
nullptr);
if (rv == -1) {
perror("timer_settime (1)");
return 1;
}
/* timer2 activation */
struct itimerspec sp2 = {
{1,500*1000*1000}, // <-- 1.5s period
{1,0}, // <-- initial expiration in 1s
};
rv = timer_settime(timer2, 0 /*relative*/,
&sp2,
nullptr);
if (rv == -1) {
perror("timer_settime (2)");
return 1;
}
while (true) {
rv = pause();
if (rv == -1) {
if (errno != EINTR) {
perror("pause");
return 1;
}
}
}
return 0;
}