Blocking I/O: On A Timer? WTF?

Setup A Timer

  • Configure timer interrupt

  • Write to timer chip’s registers

  • Hm? How many timer chips do I have?

    • Can I run out of timers chips?

    • Do I need to write my own “virtualized timer” library where I can multiplex many abstract timers onto a number of physical/hardware timers?

    • Architectural differences?

  • ⟶ a job for an Operating System

Abstractions

  • What do we read?

    • Number of expirations (a uint64_t) ⟶ timer intervals can be very short, so we could miss one expiration

  • How do we read that?

    • I don’t know, I just want read()` to work on timers.

Simplicity

  • System call: timerfd_create()

  • System call: timerfd_settime()

  • System call: read()

  • System call: close()

#include <sys/timerfd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>


int main(void)
{
    // allocate space (in kernel) for a timer. the handle to it is a
    // FILE DESCRIPTOR, again.
    int fd = timerfd_create(CLOCK_MONOTONIC, 0);

    // configure timer chip, setup an interrupt service routine, blah,
    // and start timer. the timer is a periodic timer.
    {
        int error;
        struct itimerspec ts = {
            // interval
            { 
                1,             // 1 second
                0              // 0 nanoseconds
            },
            // initial expiration
            {
                3,             // 3 seconds
                500*1000*1000, // 0.5 seconds
            }
        };

        error = timerfd_settime(fd, 0, &ts, NULL);

        // error handling
        if (error == -1) {
            perror("timerfd_settime()");
            exit(1);
        }
    }        
    
    // allocate buffer, and *read* in a loop until done. reading from
    // a timer is defined as reading an uint64_t - the number of
    // expirations since the last wakeup.
    while (1) {
        uint64_t expirations;
        ssize_t nbytes_read = read(fd, &expirations, sizeof(expirations));
        assert(nbytes_read == sizeof(expirations));  // no way seeing
                                                     // end-of-file
        printf("expired\n");
    }

    // free resources (won't get here though)
    close(fd);

    return 0;
}

Build, Run, Look

$ gcc -o read-timer read-timer.c
$ ./read-timer
expired
expired
...