Applying C - Interrupts & Polling
Written by Harry Fairhead   
Monday, 26 December 2022
Article Index
Applying C - Interrupts & Polling
Event Driven Socket Server

Interrupts and polling are mysterous and the source of many difficult to find bugs. This extract is from my  book on using C in an IoT context.

Now available as a paperback or ebook from Amazon.

Applying C For The IoT With Linux

  2. Kernel Mode, User Mode & Syscall
  3. Execution, Permissions & Systemd
    Extract Running Programs With Systemd
  4. Signals & Exceptions
    Extract  Signals
  5. Integer Arithmetic
    Extract: Basic Arithmetic As Bit Operations
  6. Fixed Point
    Extract: Simple Fixed Point Arithmetic
  7. Floating Point
  8. File Descriptors
    Extract: Simple File Descriptors 
    Extract: Pipes 
  9. The Pseudo-File System
    Extract: The Pseudo File System
    Extract: Memory Mapped Files ***NEW
  10. Graphics
    Extract: framebuffer
  11. Sockets
    Extract: Sockets The Client
    Extract: Socket Server
  12. Threading
    Extract:  Pthreads
    Extract:  Condition Variables
    Extract:  Deadline Scheduling
  13. Cores Atomics & Memory Management
    Extract: Applying C - Cores 
  14. Interupts & Polling
    Extract: Interrupts & Polling 
  15. Assembler
    Extract: Assembler

Also see the companion book: Fundamental C





Asynchronous programming is very much a part of interfacing with the real world. Things that happen in the real world happen much slower than the processor can obey instructions. When you initiate an external task such are reading a file or waiting for a switch to close, you cannot afford to keep the processor idle waiting for something to happen. The usual solution is to associate an interrupt with the completion of the event. When the interrupt occurs the processor stops what it is doing and attends to whatever caused the interrupt – it generally runs an interrupt routine.

Interrupts are common in low level programming but under Linux they are less common. It is also true that it is often better to keep the processor waiting in a loop to service the external world event in as short a time as possible. Interrupts are also very prone to the same sort of problems that a multi-threaded program has. As a result many organizations ban the use of any sort of interrupt so that the behavior of the processor is fully deterministic.

However, there are times when an interrupt is a good way to approach a problem, and in this chapter we look at the facilities that Linux provides for handling user space interrupts.

Interrupts and Poll

The first thing to make clear is that Linux/POSIX doesn’t support anything that looks like a hardware interrupt in user space. To find true hardware interrupts you have to write code for the kernel.

There are two sorts of features that are often interpreted as interrupts in user space – signals which we have already met, and select/poll on file descriptors. In many ways this is an area that is evolving and it is far from solved. However, you need to know a little about how select/poll works.

The basic idea is that a user mode program can wait for a file operation to complete. Linux will suspend the thread concerned and restart it only when the file operation is complete. This is a completely general mechanism and you can use it to wait for any file based operation to complete, including file operations in sysfs and this means we can wait for hardware that is packaged as a file or socket or a pipe or a… Recall that in Linux/Unix everything is a file.

The function we need is poll and we need to include poll.h to use it:

int poll(fdset[],n,timeout)

where fdset is a struct that specifies the file descriptor and the event you want to wait for, n is the size of the fdset array and timeout is the timeout in milliseconds. You can specify a negative timeout if you want to wait indefinitely or a zero timeout if you don't want to wait at all.

A return value of zero indicates a timeout, otherwise the return value is the number of file descriptors that fired the event specified.

The format of the struct is:

struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */

The fd field is just the file descriptor you want to wait for, and events specifies what sort of event you want to wait for. There is a range of possible events but the ones you use most often are:

POLLIN There is data to read

POLLOUT Ready to accept data

POLLPRI There is some exceptional condition.

The revents field returns the event that occurred which can be any of the above plus:

POLLERR Error condition


POLLNVAL Invalid request.

Notice that in general the fdset array can contain more than one file descriptor and poll will wait until the specified events occur on one of them. This makes it possible to start multiple transfers in progress and service each one as it becomes ready. In the following example we will only poll a single file descriptor, but the extension to multiple descriptors is obvious. To find which descriptors have triggered the event you simply scan the fdset array and examine each revents field to see if it returned the value you are looking for.

If you call poll then it will wait for the specified event on the file descriptors until the timeout is up when it returns. In fact what actually happens is a little more complicated. The thread that called poll is suspended until the event occurs and then the system restarts it. This is not really an interrupt, as in a true interrupt the thread would continue to execute until the interrupt occurred when it would run the ISR specified. This may not be an interrupt proper, but with a little more work it can provide more or less the same behavior. Notice that poll is badly named because it isn’t implemented as a polling loop.

When you poll on a set of file descriptors the call only returns when:

  • any file descriptor is ready

  • the call is interrupted by a signal handler


  • the timeout occurs.

Notice that this means that when the poll returns there is a possibility that the event that you are waiting for has not occurred.



Last Updated ( Wednesday, 28 December 2022 )