POSIX Timers: Introduction#

Overview#

  • One-shot and periodic variants

  • Nanosecond granularity

  • Parameterizable clock (see Clocks, And Points In Time)

  • Absolute time-points and relative time-intervals

  • Dynamically created (timer_t, see here)

  • Notification using freely choosable signals (which can be waited for synchronously for that matter; see Synchronous Signal Handling)

  • Notification using threads (see POSIX Threads)

Creation And Deletion#

#include <time.h>

int timer_create(clockid_t clockid,
                 struct sigevent *_Nullable restrict sevp,
                 timer_t *restrict timerid);
int timer_delete(timer_t timerid);
  • “Callback” configuration via struct sigevent

  • Optional callback parameter

“Arming” A Timer#

#include <time.h>

int timer_settime(timer_t timerid, int flags,
                  const struct itimerspec *restrict new_value,
                  struct itimerspec *_Nullable restrict old_value);

struct sigevent#

  • struct sigevent - timer “callback” specification

  • A bit convoluted

  • Not all fields are valid in all circumstances

Notification type

  • sigev_notify == SIGEV_SIGNAL

    • sigev_signo: signal number - user selectable, e.g. SIGRTMIN+7, or SIGUSR1

    • Important: even when a realtime signal is chosen (see here), multiple expirations are not queued

  • sigev_notify == SIGEV_THREAD

    • sigev_notify_function: callback function called in a separate thread

    • sigev_notify_attributes: attributes for thread creation (see here)

  • sigev_notify == SIGEV_NONE: must poll using timer_gettime()

More callback information

  • sigev_value, of type

    union sigval {
        int sival_int;
        void *sival_ptr;
    };
    
  • SIGEV_SIGVAL: passed to signal handler when installed as SA_SIGINFO (see later)

  • SIGEV_THREAD: passed as argument to thread callback function, sigev_notify_function (see later)

Limits, Anywhere?#

  • From man -s 2 timer_create

    NOTES section#
    The kernel preallocates a "queued real-time signal" for each
    timer created using timer_create().  Consequently, the number of
    timers is limited by the RLIMIT_SIGPENDING resource limit (see
    setrlimit(2)).
    
  • A-ha

  • Limit of pending signals

    $ ulimit -a
    ...
    pending signals                     (-i) 62209
    ...
    
  • Reality check

    #include <signal.h>
    #include <time.h>
    #include <print>
    
    int main()
    {
        int ntimers = 0;
        while (true) {
            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");
                break;
            }
            ntimers++;
        }
        std::println("{} timers created", ntimers);
        return 0;
    }
    
    $ ./sysprog-timers-maxtimers
    timer_create: Resource temporarily unavailable
    62207 timers created