50a5151475d415b8db001737b77a886a074ccc75
[p5sagit/p5-mst-13.2.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 EMULATE_POLL_WITH_SELECT
30
31 # define POLL_CAN_READ  (POLLIN | POLLRDNORM )
32 # define POLL_CAN_WRITE (POLLOUT | POLLWRNORM | POLLWRBAND )
33 # define POLL_HAS_EXCP  (POLLRDBAND | POLLPRI )
34
35 # define POLL_EVENTS_MASK (POLL_CAN_READ | POLL_CAN_WRITE | POLL_HAS_EXCP)
36
37 int
38 poll(fds, nfds, timeout)
39 struct pollfd *fds;
40 unsigned long nfds;
41 int timeout;
42 {
43     int i,err;
44     fd_set rfd,wfd,efd,ifd;
45     struct timeval timebuf;
46     struct timeval *tbuf = (struct timeval *)0;
47     int n = 0;
48     int count;
49
50     FD_ZERO(&ifd);
51
52 again:
53
54     FD_ZERO(&rfd);
55     FD_ZERO(&wfd);
56     FD_ZERO(&efd);
57
58     for(i = 0 ; i < nfds ; i++) {
59         int events = fds[i].events;
60         int fd = fds[i].fd;
61
62         fds[i].revents = 0;
63
64         if(fd < 0 || FD_ISSET(fd, &ifd))
65             continue;
66
67         if(fd > n)
68             n = fd;
69
70         if(events & POLL_CAN_READ)
71             FD_SET(fd, &rfd);
72
73         if(events & POLL_CAN_WRITE)
74             FD_SET(fd, &wfd);
75
76         if(events & POLL_HAS_EXCP)
77             FD_SET(fd, &efd);
78     }
79
80     if(timeout >= 0) {
81         timebuf.tv_sec = timeout / 1000;
82         timebuf.tv_usec = (timeout % 1000) * 1000;
83         tbuf = &timebuf;
84     }
85
86     err = select(n+1,&rfd,&wfd,&efd,tbuf);
87
88     if(err < 0) {
89 #ifdef HAS_FSTAT
90         if(errno == EBADF) {
91             for(i = 0 ; i < nfds ; i++) {
92                 struct stat buf;
93                 if((fstat(fds[i].fd,&buf) < 0) && (errno == EBADF)) {
94                     FD_SET(fds[i].fd, &ifd);
95                     goto again;
96                 }
97             }
98         }
99 #endif /* HAS_FSTAT */
100         return err;
101     }
102
103     count = 0;
104
105     for(i = 0 ; i < nfds ; i++) {
106         int revents = (fds[i].events & POLL_EVENTS_MASK);
107         int fd = fds[i].fd;
108
109         if(fd < 0)
110             continue;
111
112         if(FD_ISSET(fd, &ifd))
113             revents = POLLNVAL;
114         else {
115             if(!FD_ISSET(fd, &rfd))
116                 revents &= ~POLL_CAN_READ;
117
118             if(!FD_ISSET(fd, &wfd))
119                 revents &= ~POLL_CAN_WRITE;
120
121             if(!FD_ISSET(fd, &efd))
122                 revents &= ~POLL_HAS_EXCP;
123         }
124
125         if((fds[i].revents = revents) != 0)
126             count++;
127     }
128
129     return count; 
130 }
131
132 #endif /* EMULATE_POLL_WITH_SELECT */