This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
QNX needs <sys/select.h> to define fd_set.
[perl5.git] / ext / IO / poll.c
1 /*
2  * poll.c
3  *
4  * Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. All rights reserved.
5  * This program is free software; you can redistribute it and/or
6  * modify it under the same terms as Perl itself.
7  *
8  * For systems that do not have the poll() system call (for example Linux)
9  * try to emulate it as closely as possible using select()
10  *
11  */
12
13 #include "EXTERN.h"
14 #include "perl.h"
15 #include "poll.h"
16 #ifdef I_SYS_TIME
17 # include <sys/time.h>
18 #endif
19 #ifdef I_TIME
20 # include <time.h>
21 #endif
22 #include <sys/types.h>
23 #if defined(HAS_SOCKET) && !defined(VMS) /* VMS handles sockets via vmsish.h */
24 #  include <sys/socket.h>
25 #endif
26 #include <sys/stat.h>
27 #include <errno.h>
28
29 #ifdef HAS_SELECT
30 #ifdef I_SYS_SELECT
31 #include <sys/select.h>
32 #endif
33 #endif
34
35 #ifdef EMULATE_POLL_WITH_SELECT
36
37 # define POLL_CAN_READ  (POLLIN | POLLRDNORM )
38 # define POLL_CAN_WRITE (POLLOUT | POLLWRNORM | POLLWRBAND )
39 # define POLL_HAS_EXCP  (POLLRDBAND | POLLPRI )
40
41 # define POLL_EVENTS_MASK (POLL_CAN_READ | POLL_CAN_WRITE | POLL_HAS_EXCP)
42
43 int
44 poll(struct pollfd *fds, unsigned long nfds, int timeout)
45 {
46     int i,err;
47     fd_set rfd,wfd,efd,ifd;
48     struct timeval timebuf;
49     struct timeval *tbuf = (struct timeval *)0;
50     int n = 0;
51     int count;
52
53     FD_ZERO(&ifd);
54
55 again:
56
57     FD_ZERO(&rfd);
58     FD_ZERO(&wfd);
59     FD_ZERO(&efd);
60
61     for(i = 0 ; i < nfds ; i++) {
62         int events = fds[i].events;
63         int fd = fds[i].fd;
64
65         fds[i].revents = 0;
66
67         if(fd < 0 || FD_ISSET(fd, &ifd))
68             continue;
69
70         if(fd > n)
71             n = fd;
72
73         if(events & POLL_CAN_READ)
74             FD_SET(fd, &rfd);
75
76         if(events & POLL_CAN_WRITE)
77             FD_SET(fd, &wfd);
78
79         if(events & POLL_HAS_EXCP)
80             FD_SET(fd, &efd);
81     }
82
83     if(timeout >= 0) {
84         timebuf.tv_sec = timeout / 1000;
85         timebuf.tv_usec = (timeout % 1000) * 1000;
86         tbuf = &timebuf;
87     }
88
89     err = select(n+1,&rfd,&wfd,&efd,tbuf);
90
91     if(err < 0) {
92 #ifdef HAS_FSTAT
93         if(errno == EBADF) {
94             for(i = 0 ; i < nfds ; i++) {
95                 struct stat buf;
96                 if((fstat(fds[i].fd,&buf) < 0) && (errno == EBADF)) {
97                     FD_SET(fds[i].fd, &ifd);
98                     goto again;
99                 }
100             }
101         }
102 #endif /* HAS_FSTAT */
103         return err;
104     }
105
106     count = 0;
107
108     for(i = 0 ; i < nfds ; i++) {
109         int revents = (fds[i].events & POLL_EVENTS_MASK);
110         int fd = fds[i].fd;
111
112         if(fd < 0)
113             continue;
114
115         if(FD_ISSET(fd, &ifd))
116             revents = POLLNVAL;
117         else {
118             if(!FD_ISSET(fd, &rfd))
119                 revents &= ~POLL_CAN_READ;
120
121             if(!FD_ISSET(fd, &wfd))
122                 revents &= ~POLL_CAN_WRITE;
123
124             if(!FD_ISSET(fd, &efd))
125                 revents &= ~POLL_HAS_EXCP;
126         }
127
128         if((fds[i].revents = revents) != 0)
129             count++;
130     }
131
132     return count; 
133 }
134
135 #endif /* EMULATE_POLL_WITH_SELECT */