fd_set is a data structure used to store a set of file descriptors.
A few functions are defined to manipulate the fd_set:
ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/select.h
......
/* Access macros for `fd_set'. */
#define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp)
#define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp)
#define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp)
#define FD_ZERO(fdsetp) __FD_ZERO (fdsetp)
......
2. pselect
pselect is identical to select but provides a finer control.
1) The timeout value for "select" is specified by a timeval structure, but for pselect , a timespec structure is used, which provides nanosecond level time control.
2) The timeout value for "pselect" is declared const, and its value will not change as a result of calling pselect.
3) signal mask provide a way to install the signal mask atomically while calling the pselect, on return, the previous signal is restored.
3. Example:
select.c:
#include<stdio.h>
#include<stdlib.h>
#include<sys/select.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc, char* argv[])
{
int fd1;
int fd2;
// Open file descriptors
if((fd1 = open(argv[1], O_RDONLY)) < 0) {
printf("open error!\n");
exit(1);
}
if((fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC)) < 0) {
printf("open error!\n");
exit(1);
}
// Setup select
int maxfd = (fd1 > fd2)? fd1 : fd2;
struct timeval ts;
ts.tv_sec = 2;
ts.tv_usec = 500;
fd_set rset, wset, eset;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
FD_SET(fd1, &rset);
FD_SET(fd2, &rset);
FD_SET(fd1, &wset);
FD_SET(fd2, &wset);
int rc;
if((rc = select(maxfd+1, &rset, &wset, &eset, &ts)) == 0) {
printf("time out, no fd is ready.\n");
exit(2);
} else if(rc < 0) {
printf("sth wrong happens.\n");
exit(3);
}
// Output ready descriptors
printf("there are totally %d file descriptors are ready.\n", rc);
if(FD_ISSET(fd1, &rset)) {
printf("fd1 is ready for read.\n");
}
if(FD_ISSET(fd2, &rset)) {
printf("fd2 is ready for read.\n");
}
if(FD_ISSET(fd1, &wset)) {
printf("fd1 is ready for write.\n");
}
if(FD_ISSET(fd2, &wset)) {
printf("fd2 is ready for write.\n");
}
close(fd1);
close(fd2);
exit(0);
}
shell:
ubuntu@ip-172-31-23-227:~$ ./select.out test1 test2
there are totally 4 file descriptors are ready.
fd1 is ready for read.
fd2 is ready for read.
fd1 is ready for write.
fd2 is ready for write.
4. poll function
poll function is similar from select, just the interface is different.
System Definition:
ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/sys/poll.h
......
/* Data structure describing a polling request. */
struct pollfd
{
int fd; /* File descriptor to poll. */
short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */
};
__BEGIN_DECLS
/* Poll the file descriptors described by the NFDS structures starting at
FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
......
Every time we call poll, we need to create an array of struct pollfd, including the file descriptor, event type we care about. When poll function returns, fd, events don't change, but revents is repopulated to tell which event occured. Following is the list of all events:
ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/poll.h
......
/* Event types that can be polled for. These bits may be set in `events'
to indicate the interesting event types; they will appear in `revents'
to indicate the status of the file descriptor. */
#define POLLIN 0x001 /* There is data to read. */
#define POLLPRI 0x002 /* There is urgent data to read. */
#define POLLOUT 0x004 /* Writing now will not block. */
#if defined __USE_XOPEN || defined __USE_XOPEN2K8
/* These values are defined in XPG4.2. */
# define POLLRDNORM 0x040 /* Normal data may be read. */
# define POLLRDBAND 0x080 /* Priority data may be read. */
# define POLLWRNORM 0x100 /* Writing now will not block. */
# define POLLWRBAND 0x200 /* Priority data may be written. */
#endif
#ifdef __USE_GNU
/* These are extensions for Linux. */
# define POLLMSG 0x400
# define POLLREMOVE 0x1000
# define POLLRDHUP 0x2000
#endif
/* Event types always implicitly polled for. These bits need not be set in
`events', but they will appear in `revents' to indicate the status of
the file descriptor. */
#define POLLERR 0x008 /* Error condition. */
#define POLLHUP 0x010 /* Hung up. */
#define POLLNVAL 0x020 /* Invalid polling request. */
......
Note: It is important to realize the difference between an end of file and a hangup. If we're entering data from the terminal and type the end-of-file character, POLLIN is turned on. If we're reading from a modem and the telephone line is hungup, we'll receive the POLLHUP notification.
For select and poll, whether the file descriptor is blocking or not doesn't affect the select and poll's blocking.
No comments:
Post a Comment