Applying C - Interrupts & Polling |
Written by Harry Fairhead | |||
Monday, 26 December 2022 | |||
Page 1 of 2 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
Also see the companion book: Fundamental C <ASIN:1871962609> <ASIN:1871962617> 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 PollThe 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 POLLHUP Hang up 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:
or
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 ) |