Wednesday, December 10, 2014

poll()

poll() is a userspace function which provides application to monitor I/O events on a set of file descriptors.


#include <poll.h>

int poll(struct pollfd
 fds[], nfds_t nfds, int timeout);// polls over an array of structures




The <poll.h> header shall define the pollfd structure, which shall include at least the following members:
int    fd       The following descriptor being polled. 
short  events   The input event flags 
short  revents  The output event flags  


nfds means the number of file descriptors on which polling is being done.
Timeout means the poll function will wait for this many milliseconds for the vent to occur.
If the value of timeout is 0 then the function return immediately.
if the vale of timeout is -1 then poll shall bloack untill a requested event has occured or untill the call is interrupted.

The poll function supports for regular files, terminal and pseudo-terminal devices, FIFOs, pipes, sockets and  STREAMS-based files.


The flags used for events and revents are-



POLLIN
Data other than high-priority data may be read without blocking.
POLLRDNORM
Normal data may be read without blocking.
POLLRDBAND
Priority data may be read without blocking.
POLLPRI
High priority data may be read without blocking.
POLLOUT
Normal data may be written without blocking.
POLLWRNORM
Equivalent to POLLOUT.
POLLWRBAND
Priority data may be written.
POLLERR
An error has occurred (revents only).
POLLHUP
Device has been disconnected (revents only).
POLLNVAL
Invalid fd member (revents only).



Return value of poll function


On successful return the poll functions returns a positive integer value which means the number of fds selected.0 means no fd seslected and the call timed out.
Upon failure, poll() shall return -1 and set errno to indicate the error.



ERRORS REPORTED:

[EAGAIN]
The allocation of internal data structures failed but a subsequent request may succeed.
[EINTR]
A signal was caught during poll().
[EINVAL]
The nfds argument is greater than {OPEN_MAX},or one of the fd members refers to a STREAM or multiplexer that is linked (directly or indirectly) downstream from a multiplexer. 



EXAMPLE

Checking for Events on a Stream
The following example opens a pair of STREAMS devices and then waits for either one to become writable. This example proceeds as follows:
  1. Sets the timeout parameter to 500 milliseconds.
  2. Opens the STREAMS devices /dev/dev0 and /dev/dev1, and then polls them, specifying POLLOUT and POLLWRBAND as the events of interest.
    The STREAMS device names /dev/dev0 and /dev/dev1 are only examples of how STREAMS devices can be named; 
  3. Uses the ret variable to determine whether an event has occurred on either of the two STREAMS. The poll() function is given 500 milliseconds to wait for an event to occur (if it has not occurred prior to the poll() call).
  4. Checks the returned value of ret. If a positive value is returned, one of the following can be done:
    1. Priority data can be written to the open STREAM on priority bands greater than 0, because the POLLWRBAND event occurred on the open STREAM ( fds[0] or fds[1]).
    2. Data can be written to the open STREAM on priority-band 0, because the POLLOUT event occurred on the open STREAM ( fds[0] or fds[1]).
  5. If the returned value is not a positive value, permission to write data to the open STREAM (on any priority band) is denied.
  6. If the POLLHUP event occurs on the open STREAM ( fds[0] or fds[1]), the device on the open STREAM has disconnected.
#include <stropts.h>
#include <poll.h>
...
struct pollfd fds[2];
int timeout_msecs = 500;
int ret;
    int i;


/* Open STREAMS device. */
fds[0].fd = open("/dev/dev0", ...);
fds[1].fd = open("/dev/dev1", ...);
fds[0].events = POLLOUT | POLLWRBAND;
fds[1].events = POLLOUT | POLLWRBAND;


ret = poll(fds, 2, timeout_msecs);


if (ret > 0) {
    /* An event on one of the fds has occurred. */
    for (i=0; i<2; i++) {
        if (fds[i].revents & POLLWRBAND) {
        /* Priority data may be written on device number i. */
...
        }
        if (fds[i].revents & POLLOUT) {
        /* Data may be written on device number i. */
...
        }
        if (fds[i].revents & POLLHUP) {
        /* A hangup has occurred on device number i. */
...
        }
    }
}




There is one important variant of poll function known as poll_wait


The system uses a poll_wait call to indicate that the poll system is interested in events. The poll_wait call includes a reference to a wait queue that must be triggered by a driver event. Another argument to poll_wait function is a poll_table structure.


 What exactly happens is that on calling poll_wait() the kernel calls all the fops->poll on all associated fds, passing the the global poll table.
 poll_wait() adds the process' wait_queue(events its is waiting for) to this global poll table. Or simply,a process adds itself to all the wait queues it is dependent on, and on
poll/poll_wait invocation the kernel checks the global poll table if the
event has occured. If the event is not ready (blocked on I/O, device not
ready etc), it puts the process to sleep. Once an event has occurred (say
read on FD), it is removed from all wait queues and all the wake handlers
associated with the queue are called waking up the process. So from the
outside it'll look like the poll_wait() block until an event has occured,
but actually the event triggers the wakeup of the process. 






No comments:

Post a Comment