The proper sequence for using /dev/pit is as follows:

1. Open /dev/pit.

    pit_fd = open("/dev/pit", O_RDONLY);

  - Be sure to check for errors!  If open fails, pit_fd will be set to -1, and
    errno will contain the specific error code.

2. If using asynchronous notification, enable SIGIO ahead of time.

    signal(SIGIO, input_handler);
    fcntl(pit_fd, F_SETOWN, getpid());
    fcntl(pit_fd, F_SETFL, fcntl(pit_fd, F_GETFL) | FASYNC);

  - Whenever /dev/pit becomes readable (i.e. has a tick), this program will get
    a SIGIO signal, resulting in an asynchronous call to the input_handler
    function.

  - This is useful if the program needs to do long-running yet low-priority
    calculations and can't afford to spend any time waiting for user input or
    timer ticks.

3. Set the divisor and start the clock.

    ioctl(pit_fd, PIT_SET_DIVISOR, &divisor);

  - The timer now starts ticking, but the computer will ignore any ticks
    until...

4. Enable timer interrupts.

    ioctl(pit_fd, PIT_ENABLE_TICKS);

  - Now timer ticks are registered by the computer.

5. To wait for a timer tick:

    read(pit_fd, &tick_count, sizeof(tick_count));
  
  - This will return sizeof(tick_count) and store the number of ticks since the
    previous read in tick_count.

  - If no ticks have taken place since the previous read, and pit_fd has
    O_NONBLOCK set (non-blocking I/O), this will instead return -1 and errno
    will be set to EAGAIN ("try again").

  - If no ticks have happened and O_NONBLOCK is not set (default), then this
    call won't return until a tick occurs, and tick_count will (probably) be
    set to 1.

  - or -

    FD_ZERO(&read_fds); FD_SET(pit_fd, &read_fds);
    select(pit_fd + 1, &read_fds, NULL, NULL, NULL);

  - If a tick happened since the last read, select will return immediately.  If
    not, select will wait for a tick.

  - If the program really has nothing better to do than wait for timer ticks,
    it's better to just use blocking reads.  But if the program needs to watch
    keyboard input, network traffic, etc. while watching for timer ticks, then
    select (or better yet, poll) is the way to go.

  - or -

    struct pollfd ufds = {pit_fd, POLLIN};
    poll(&ufds, 1, 0);

  - This is a more civilized version of select.  See poll(2) for information on
    how to use it effectively.

6. Loop.

  - Your program probably wants to wait for more than just one tick, right? :^)

7. Close /dev/pit.

    close(pit_fd);

  - Again, check for errors.  In this specific case, I'm not sure what can go
    wrong, but nevertheless, checking the return values of all library
    functions is a good habit.