I was reading about poll in C programming and built an application given on the poll(2) man page.
Here is the example:
#include<stdio.h>
#include <stropts.h>
#include <poll.h>
#include <fcntl.h>
int main() {
struct pollfd fds[2];
int timeout_msecs = -1;
int ret;
int i;
/* Open STREAMS device. */
fds[0].fd = open("/home/jeshwanth/mywork/poll/dev0", O_RDONLY);
fds[1].fd = open("/home/jeshwanth/mywork/poll/dev1", O_RDONLY);
fds[0].events = POLLOUT | POLLWRBAND;
fds[1].events = POLLOUT | POLLWRBAND;
while (1) {
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 != 0) {
/* Priority data may be written on device number i. */
printf(
"Priority Data may be written on device number %d POLLWRBAND\n",
i);
}
if (fds[i].revents = !0) {
/* Data may be written on device number i. */
printf("Data may be written on device number %d POLLOUT\n",
i);
}
if (fds[i].revents = !0) {
/* A hangup has occurred on device number i. */
printf("A hangup has occurred on device number %d\n", i);
}
}
}
}
return 0;
}
Note: dev0 and dev1 are normal files. When I run the program, if no event occurred in dev0 and dev1, the message is displayed. But I was expecting when some write into the file happens, only then should it display the message. Am I wrong?
Polling it for output readiness doesn't mean you will get notified when some output occurs: it means that you'll get notified when there is output buffer space available so you can output (but you should still check the return value of your output function. The buffer state may have changed between polling and outputting; always check return values).
Minimal FIFO named pipe example
You won't be able to see anything interesting with regular files, since those always give POLLIN
immediately: How can select() wait on regular file descriptors (non-sockets)?
The simplest way to play around with poll
is to use named pipes as shown below. This should prepare you for their major application: sockets and device files.
Source below. Usage:
sudo mknod poll0.tmp p
sudo mknod poll1.tmp p
sudo chmod 666 poll*.tmp
./poll.out
On another shell:
printf a > poll0.tmp
printf b > poll1.tmp
Output:
loop
POLLIN i=0 n=1 buf=a
loop
POLLHUP i=0
loop
POLLIN i=1 n=1 buf=b
POLLHUP i=1
loop
So notice how poll
waits for the reads without looping.
Cooler example:
(while true; do date; sleep 1; done) > poll0.tmp &
(while true; do date; sleep 2; done) > poll1.tmp &
0
gets written every one second, and 1
every two seconds, which shows how poll()
is dealing with both inputs concurrently, without stalling each other.
Source:
#define _XOPEN_SOURCE 700
#include <fcntl.h> /* creat, O_CREAT */
#include <poll.h> /* poll */
#include <stdio.h> /* printf, puts, snprintf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <unistd.h> /* read */
int main(void) {
enum { N = 2 };
char buf[1024], path[1024];
int fd, i, n;
short revents;
struct pollfd pfds[N];
for (i = 0; i < N; ++i) {
snprintf(path, sizeof(path), "poll%d.tmp", i);
/* O_NONBLOCK is required or else the open blocks
* until the other side of the pipe opens. */
fd = open(path, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
pfds[i].fd = fd;
/* Only events in this mask will be listened to.
* However, there are also some events that are unmaskable,
* notably POLLHUP when pipe closes! */
pfds[i].events = POLLIN;
}
while (1) {
puts("loop");
i = poll(pfds, N, -1);
if (i == -1) {
perror("poll");
exit(EXIT_FAILURE);
}
for (i = 0; i < N; ++i) {
revents = pfds[i].revents;
if (revents & POLLIN) {
n = read(pfds[i].fd, buf, sizeof(buf));
printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
}
if (revents & POLLHUP) {
printf("POLLHUP i=%d\n", i);
/* This happens when the other side closed.
* This event is only cleared when we close the reader. */
/* poll won't set POLLHUP anymore once all fds are closed.
* Any futher polls on this will give the POLLNVAL event instead. */
close(pfds[i].fd);
/* negative fds are ignored. So if we negate an FD,
* we can both turn if off for a while, and turn it on
* later on by re-nagating it. */
pfds[i].fd *= -1;
}
}
}
}
Compile with:
gcc -o poll.out -std=c99 poll.c
Tested in Ubuntu 14.04.
GitHub upstream.
The lines:
close(pfds[i].fd);
pfds[i].fd *= -1;
are required or else you get POLLHUP
forever, see also: How to use the poll C function to watch named pipes in Linux?
For even more fun, create a Linux kernel module what implements the poll
fops: How to add poll function to the kernel module code?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With