I/O Multiplexing The role of the ‘poll()’ method in Linux device-driver operations struct file_operations fops; • • • • • • • read: write: open: close: llseek: … poll: // what is this function for? Recall ‘watchtsc.cpp’ demo • After some initializations, this application entered an endless loop, rereading from the ‘/dev/tsc’ device special file. • But it also checked for user input from the keyboard, so a user could break out of the endless loop in order to quit the program. Illustrates I/O Multiplexing Read from /dev/tsc redraw display Read from keyboard maybe quit More than just one source for input Remember ‘read()’ semantics • If device-driver’s ‘read()’ function is called before the device has any data available, then the calling task is expected to ‘sleep’ on a wait-queue until the device has at least one byte of data ready to return. • The keyboard’s device-driver behaves in exactly that expected way: it ‘blocks’ if we try to read when there are no keystrokes. Blocking versus Multiplexing • If we want to read from multiple devices, we are not able to do it properly with the read() system-call • If one device has no data, our task will be blocked, and so can’t read data that may become available from some other device Idea: use ‘nonblocking’ i/o • When we ‘open()’ a device-file, we could specify the ‘O_NONBLOCK’ i/o mode • For the keyboard: two problems with this: – The ‘stdin’ device is already open by default – If a task tries to do multiplexing with devices that have been opened in non-blocking mode, it will likely consume way too much cpu time! Better idea: use ‘select()’ • The ‘select()’ system-call was designed to allow applications to efficiently perform i/o multiplexing • With ‘select()’ the application informs the kernel as to which system devices it is interested in • The kernel then ‘polls’ those devices, to see if any of them is ready to do i/o without blocking • If not, it puts the process to sleep until at least one device is ready to do i/o without blocking Calling ‘select()’ • • • • Application needs an ‘fd_set’ structure For reading, for writing, and for errors And maybe also a ‘timeout’ structure In our ‘watchtsc.cpp’ demo: – We only were interested in reading – Not interested in writing or in errors – And not concerned about ‘timeouts’ • Full details on the ‘man’ page for ‘select()’ Driver needs ‘poll()’ method • To support the ‘select()’ system-call, our ‘tsc.c’ driver needs to implement ‘poll()’ • Our textbook tells what we need to do • Just two things: – Need to call the kernel ‘poll_wait()’ function – Return a bitmap indicating device readiness prototype for ‘poll()’ method #include <linux/poll.h> // for ‘poll_table’ static int ready; // kernel-timer’s flag DECLARE_WAIT_QUEUE_HEAD( wq ); static unsigned long my_poll( struct file *file, poll_table *wait ); Actions in our ‘poll()’ function static unsigned long my_poll( sruct file *file, poll_table *wait ) { unsigned long mask = 0; poll_wait( file, &wq, wait ); if ( ready ) // our kernel-timer’s flag mask |= ( POLLIN | POLLRDNORM ); return mask; } An experiment with ‘poll()’ • • • • • • • Modify the ‘tsc.c’ device-driver code Include ‘poll()’ in ‘file_operations’ struct Use a kernel software timer in ‘read()’ Use 5-second delay between ‘reads’ Run ‘watchtsc’ with polling implemented And run ‘watchtsc’ with polling ommitted Note responsiveness to keyboard input! Does ‘ram.c’ need ‘poll()’? • • • • • • • The system memory is ‘volatile’ Contents of memory continually changing For example, the ‘jiffies’ variable And lots of other examples as well Our ‘fileview.cpp’ tool doesn’t show this It ‘blocks’ until the user presses a key Would be much better to use ‘select()’