1 #if defined(HAS_DEVPOLL)
2 #include <sys/devpoll.h>
3     static int dpfd=0;
4     static struct pollfd *Pollfd=0;
5     static int pollMax=200;
6     static int Nfds;
7 
8 #define MAXFD 65000
9 
10     typedef struct _fdToEvent {
11         pe_io *ev;
12     } FdToEvent;
13 
14     static FdToEvent fdToEvent[MAXFD];
15 #endif /*HAS_DEVPOLL*/
16 
boot_devpoll()17 static void boot_devpoll() {
18 #if defined(HAS_DEVPOLL)
19     memset(fdToEvent, 0, MAXFD*sizeof(FdToEvent));
20 
21     EvNew(9, Pollfd, pollMax, struct pollfd);
22 
23     /* Open /dev/poll driver */
24     if (!dpfd) {
25         fprintf(stderr, "INIT Open /dev/poll!!!\n");
26         if ((dpfd = open("/dev/poll", O_RDWR)) < 0) {
27             croak("Event: Can't open /dev/poll!\n");
28         }
29     }
30 #endif /*HAS_DEVPOLL*/
31 }
32 
pe_sys_fileno(SV * sv,char * context)33 static int pe_sys_fileno(SV *sv, char *context) {
34     IO *io;
35     PerlIO *fp;
36 
37     if (!sv)
38 	croak("Event %s: no filehandle available", context);
39     if (SvGMAGICAL(sv))
40 	mg_get(sv);
41     if (SvIOK(sv)) /* maybe non-portable but nice for unixen */
42 	return SvIV(sv);
43     if (SvROK(sv))
44 	sv = SvRV(sv);
45     if (SvTYPE(sv) == SVt_PVGV) {
46 	if (!(io=GvIO((GV*)sv)) || !(fp = IoIFP(io))) {
47 	    croak("Event '%s': GLOB(0x%x) isn't a valid IO", context, sv);
48 	}
49 	return PerlIO_fileno(fp);
50     }
51     sv_dump(sv);
52     croak("Event '%s': can't find fileno", context);
53     return -1;
54 }
55 
_queue_io(pe_io * wa,int got)56 static void _queue_io(pe_io *wa, int got) {
57     pe_ioevent *ev;
58     got &= wa->poll;
59     if (!got) {
60 	if (WaDEBUGx(wa) >= 3) {
61 	    STRLEN n_a;
62 	    warn("Event: io '%s' queued nothing", SvPV(wa->base.desc, n_a));
63 	}
64 	return;
65     }
66     ev = (pe_ioevent*) (*wa->base.vtbl->new_event)((pe_watcher*) wa);
67     ++ev->base.hits;
68     ev->got |= got;
69     queueEvent((pe_event*) ev);
70 }
71 
72 /************************************************* DEVPOLL */
73 #if defined(HAS_DEVPOLL) && !PE_SYS_IO
74 #define PE_SYS_IO 1
75 
pe_sys_sleep(NV left)76 static void pe_sys_sleep(NV left) {
77     int ret;
78     NV t0 = NVtime();
79     NV t1 = t0 + left;
80     while (1) {
81         ret = poll(0, 0, (int) (left * 1000)); /* hope zeroes okay */
82         if (ret < 0 && errno != EAGAIN && errno != EINTR)
83             croak("poll(%.2f) got errno %d", left, errno);
84         left = t1 - NVtime();
85         if (left > IntervalEpsilon) {
86             if (ret==0) ++TimeoutTooEarly;
87             continue;
88         }
89         break;
90     }
91 }
92 
pe_sys_io_add(pe_io * ev)93 static void pe_sys_io_add (pe_io *ev) {
94     struct pollfd tmp_pfd;
95     int bits=0;
96 
97     if (ev->fd <= 0 || ev->fd > MAXFD) {
98         croak("pe_sys_io_add: non-valid fd (%d)", ev->fd);
99         return;
100     }
101 
102     if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI);
103     if (ev->poll & PE_W) bits |= POLLOUT;
104     if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI);
105 
106     tmp_pfd.fd = ev->fd;
107     tmp_pfd.events = bits;
108 
109     if (write(dpfd, &tmp_pfd, sizeof(struct pollfd)) !=
110         sizeof(struct pollfd)) {
111         fprintf(stderr, "pe_sys_io_add(fd %d): could not write fd to /dev/poll",
112             dpfd);
113         return;
114     }
115 
116     if (fdToEvent[ev->fd].ev != NULL) {
117         fprintf(stderr, "pe_sys_io_add(fd %d): mapping between fd and event already exists!", ev->fd);
118     } else {
119         fdToEvent[ev->fd].ev = ev;
120     }
121 }
122 
pe_sys_io_del(pe_io * ev)123 static void pe_sys_io_del (pe_io *ev) {
124     struct pollfd tmp_pfd;
125     int bits=0;
126 
127     if (ev-> fd <= 0) {
128         return;
129     }
130 
131     if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI);
132     if (ev->poll & PE_W) bits |= POLLOUT;
133     if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI);
134 
135     tmp_pfd.fd = ev->fd;
136     tmp_pfd.events = POLLREMOVE;
137 
138     if (write(dpfd, &tmp_pfd, sizeof(struct pollfd)) !=
139         sizeof(struct pollfd)) {
140         fprintf(stderr, "pe_sys_io_del(fd %d): could not write fd to /dev/poll", dpfd);
141     }
142 
143     fdToEvent[ev->fd].ev = NULL;
144 }
145 
pe_sys_multiplex(NV timeout)146 static void pe_sys_multiplex(NV timeout) {
147     pe_io *ev;
148     int xx, got, mask, fd;
149     int ret;
150     int err, m_rfds;
151     struct dvpoll dopoll;
152 
153     if (pollMax < IOWatchCount) {
154         if (Pollfd)
155             EvFree(9, Pollfd);
156         pollMax = IOWatchCount*2;
157         EvNew(9, Pollfd, pollMax, struct pollfd);
158         IOWatch_OK = 0;
159     }
160 
161 
162     if (!IOWatch_OK) {
163         Nfds = 0;
164 	if (Pollfd)
165             Zero(Pollfd, pollMax, struct pollfd);
166         ev = (pe_io*) IOWatch.next->self;
167         while (ev) {
168             int fd = ev->fd;
169             ev->xref = -1;
170             assert(fd >= 0); {
171                 int bits=0;
172                 if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI);
173                 if (ev->poll & PE_W) bits |= POLLOUT;
174                 if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI);
175                 assert(bits); {
176                     Pollfd[Nfds].fd = fd;
177                     Pollfd[Nfds].events |= bits;
178                     Nfds++;
179                 }
180             }
181             ev = (pe_io*) ev->ioring.next->self;
182         }
183         IOWatch_OK = 1;
184     }
185 
186     for (xx=0; xx < Nfds; xx++)
187         Pollfd[xx].revents = 0; /* needed? XXX */
188 
189     if (timeout < 0)
190         timeout = 0;
191 
192     dopoll.dp_timeout = (int) (timeout * 1000);
193     dopoll.dp_nfds = pollMax;
194     dopoll.dp_fds = Pollfd;
195 
196     /* Wait for I/O events the clients are interested in */
197     m_rfds = ioctl(dpfd, DP_POLL, &dopoll);
198     if (m_rfds == -1) {
199         err = errno;
200         fprintf(stderr, "pe_sys_multiplex: poll() returned -1, errno %d\n", err);
201         return;
202     }
203 
204     while (m_rfds >= 1) {
205         m_rfds--;
206         fd = Pollfd[m_rfds].fd;
207         ev = fdToEvent[fd].ev;
208         got = 0;
209         mask = Pollfd[m_rfds].revents;
210         if (mask & (POLLIN | POLLPRI | POLLHUP | POLLERR)) got |= PE_R;
211         if (mask & (POLLOUT | POLLERR)) got |= PE_W;
212         if (mask & (POLLRDBAND | POLLPRI | POLLHUP | POLLERR)) got |= PE_E;
213         if (mask & POLLNVAL) {
214             STRLEN n_a;
215             warn("Event: '%s' was unexpectedly closed",
216                  SvPV(ev->base.desc, n_a));
217             pe_io_reset_handle((pe_watcher*) ev);
218         } else {
219             if ((mask & POLLHUP) && (ev->poll & PE_W) && (!(got & PE_W))
220                 && (!(ev->poll & PE_R)) && (!(ev->poll & PE_E))) {
221               /* Must notify about POLLHUP _some_ way - Allen */
222               got |= PE_W;
223             }
224         }
225 
226         if (got) _queue_io(ev, got);
227 
228     }
229 }
230 #endif /*HAS_DEVPOLL*/
231 
232 /************************************************* POLL */
233 #if defined(HAS_POLL) && !PE_SYS_IO
234 #define PE_SYS_IO 1
235 
236 static struct pollfd *Pollfd=0;
237 static int pollMax=0;
238 static int Nfds;
239 
pe_sys_sleep(NV left)240 static void pe_sys_sleep(NV left) {
241     int ret;
242     NV t0 = NVtime();
243     NV t1 = t0 + left;
244     while (1) {
245 	ret = poll(0, 0, (int) (left * 1000)); /* hope zeroes okay */
246 	if (ret < 0 && errno != EAGAIN && errno != EINTR)
247 	    croak("poll(%.2f) got errno %d", left, errno);
248 	left = t1 - NVtime();
249 	if (left > IntervalEpsilon) {
250 	    if (ret==0) ++TimeoutTooEarly;
251 	    continue;
252 	}
253 	break;
254     }
255 }
256 
pe_sys_io_add(pe_io * ev)257 static void pe_sys_io_add (pe_io *ev) {}
pe_sys_io_del(pe_io * ev)258 static void pe_sys_io_del (pe_io *ev) {}
259 
pe_sys_multiplex(NV timeout)260 static void pe_sys_multiplex(NV timeout) {
261     pe_io *ev;
262     int xx;
263     int ret;
264     if (pollMax < IOWatchCount) {
265 	if (Pollfd)
266 	    EvFree(9, Pollfd);
267 	pollMax = IOWatchCount+5;
268 	EvNew(9, Pollfd, pollMax, struct pollfd);
269 	IOWatch_OK = 0;
270     }
271     if (!IOWatch_OK) {
272 	Nfds = 0;
273 	if (Pollfd)
274             Zero(Pollfd, pollMax, struct pollfd);
275 	ev = (pe_io*) IOWatch.next->self;
276 	while (ev) {
277 	    int fd = ev->fd;
278 	    ev->xref = -1;
279 	    assert(fd >= 0); {
280 		int bits=0;
281 		if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI);
282 		if (ev->poll & PE_W) bits |= POLLOUT;
283 		if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI);
284 		assert(bits); {
285 		    int ok=0;;
286 		    for (xx = 0; xx < Nfds; xx++) {
287 			if (Pollfd[xx].fd == fd) { ok=1; break; }
288 		    }
289 		    if (!ok) xx = Nfds++;
290 		    Pollfd[xx].fd = fd;
291 		    Pollfd[xx].events |= bits;
292 		    ev->xref = xx;
293 		}
294 	    }
295 	    ev = (pe_io*) ev->ioring.next->self;
296 	}
297 	IOWatch_OK = 1;
298     }
299     for (xx=0; xx < Nfds; xx++)
300 	Pollfd[xx].revents = 0; /* needed? XXX */
301     if (timeout < 0)
302 	timeout = 0;
303     ret = poll(Pollfd, Nfds, (int) (timeout * 1000));
304 
305     if (ret < 0) {
306 	if (errno == EINTR || errno == EAGAIN)
307 	    return;
308 	if (errno == EINVAL) {
309 	    warn("poll: bad args %d %.2f", Nfds, timeout);
310 	    return;
311 	}
312 	warn("poll got errno %d", errno);
313 	return;
314     }
315     ev = (pe_io*) IOWatch.next->self;
316     while (ev) {
317 	pe_io *next_ev = (pe_io*) ev->ioring.next->self;
318 	STRLEN n_a;
319 	int xref = ev->xref;
320 	if (xref >= 0) {
321 	    int got = 0;
322 	    int mask = Pollfd[xref].revents;
323 	    if (mask & (POLLIN | POLLPRI | POLLHUP | POLLERR)) got |= PE_R;
324 	    if (mask & (POLLOUT | POLLERR)) got |= PE_W;
325 	    if (mask & (POLLRDBAND | POLLPRI | POLLHUP | POLLERR)) got |= PE_E;
326 	    if (mask & POLLNVAL) {
327 		warn("Event: '%s' was unexpectedly closed",
328 		     SvPV(ev->base.desc, n_a));
329 		pe_io_reset_handle((pe_watcher*) ev);
330 	    } else {
331 	      if ((mask & POLLHUP) && (ev->poll & PE_W) && (!(got & PE_W))
332 		  && (!(ev->poll & PE_R)) && (!(ev->poll & PE_E))) {
333 		/* Must notify about POLLHUP _some_ way - Allen */
334 		got |= PE_W;
335 	    }
336 
337 	      if (got) _queue_io(ev, got);
338 	    /*
339 	      Can only do this if fd-to-watcher is 1-to-1
340 	      if (--ret == 0) { ev=0; continue; }
341 	    */
342 	    }
343 	}
344 	ev = next_ev;
345     }
346 }
347 #endif /*HAS_POLL*/
348 
349 
350 /************************************************* SELECT */
351 #if defined(HAS_SELECT) && !PE_SYS_IO
352 #define PE_SYS_IO 1
353 
354 static int Nfds;
355 static fd_set Rfds, Wfds, Efds;
356 
pe_sys_sleep(NV left)357 static void pe_sys_sleep(NV left) {
358     struct timeval tm;
359     NV t0 = NVtime();
360     NV t1 = t0 + left;
361     int ret;
362     while (1) {
363 	tm.tv_sec = left;
364 	tm.tv_usec = (left - tm.tv_sec) * 1000000;
365 	ret = select(0, 0, 0, 0, &tm);
366 	if (ret < 0 && errno != EINTR && errno != EAGAIN)
367 	    croak("select(%.2f) got errno %d", left, errno);
368 	left = t1 - NVtime();
369 	if (left > IntervalEpsilon) {
370 	    if (ret==0) ++TimeoutTooEarly;
371 	    continue;
372 	}
373 	break;
374     }
375 }
376 
pe_sys_io_add(pe_io * ev)377 static void pe_sys_io_add (pe_io *ev) {}
pe_sys_io_del(pe_io * ev)378 static void pe_sys_io_del (pe_io *ev) {}
379 
pe_sys_multiplex(NV timeout)380 static void pe_sys_multiplex(NV timeout) {
381     struct timeval tm;
382     int ret;
383     fd_set rfds, wfds, efds;
384     pe_io *ev;
385 
386     if (!IOWatch_OK) {
387 	Nfds = -1;
388 	FD_ZERO(&Rfds);
389 	FD_ZERO(&Wfds);
390 	FD_ZERO(&Efds);
391 	ev = IOWatch.next->self;
392 	while (ev) {
393 	    int fd = ev->fd;
394 	    if (fd >= 0) {
395 		int bits=0;
396 		if (ev->poll & PE_R) { FD_SET(fd, &Rfds); ++bits; }
397 		if (ev->poll & PE_W) { FD_SET(fd, &Wfds); ++bits; }
398 		if (ev->poll & PE_E) { FD_SET(fd, &Efds); ++bits; }
399 		if (bits && fd > Nfds) Nfds = fd;
400 	    }
401 	    ev = ev->ioring.next->self;
402 	}
403 	IOWatch_OK = 1;
404     }
405 
406     if (timeout < 0)
407 	timeout = 0;
408     tm.tv_sec = timeout;
409     tm.tv_usec = (timeout - tm.tv_sec) * 1000000;
410     if (Nfds > -1) {
411 	memcpy(&rfds, &Rfds, sizeof(fd_set));
412 	memcpy(&wfds, &Wfds, sizeof(fd_set));
413 	memcpy(&efds, &Efds, sizeof(fd_set));
414 	ret = select(Nfds+1, &rfds, &wfds, &efds, &tm);
415     }
416     else
417 	ret = select(0, 0, 0, 0, &tm);
418 
419     if (ret < 0) {
420 	if (errno == EINTR)
421 	    return;
422 	if (errno == EBADF) {
423 	    STRLEN n_a;
424 	    ev = IOWatch.next->self;
425 	    while (ev) {
426 		int fd = ev->fd;
427 		struct stat buf;
428 		if (fd >= 0 && PerlLIO_fstat(fd, &buf) < 0 && errno == EBADF) {
429 		    warn("Event: '%s' was unexpectedly closed",
430 			 SvPV(ev->base.desc, n_a));
431 		    pe_io_reset_handle((pe_watcher*) ev);
432 		    return;
433 		}
434 		ev = ev->ioring.next->self;
435 	    }
436 	    warn("select: couldn't find cause of EBADF");
437 	    return;
438 	}
439 	if (errno == EINVAL) {
440 	    warn("select: bad args %d %.2f", Nfds, timeout);
441 	    return;
442 	}
443 	warn("select got errno %d", errno);
444 	return;
445     }
446     ev = IOWatch.next->self;
447     while (ev) {
448 	pe_io *next_ev = (pe_io*) ev->ioring.next->self;
449 	int fd = ev->fd;
450 	if (fd >= 0) {
451 	    int got = 0;
452 	    if (FD_ISSET(fd, &rfds)) got |= PE_R;
453 	    if (FD_ISSET(fd, &wfds)) got |= PE_W;
454 	    if (FD_ISSET(fd, &efds)) got |= PE_E;
455 	    if (got) _queue_io(ev, got);
456 	    /*
457 	      Can only do this if fd-to-watcher is 1-to-1
458 
459 	      if (--ret == 0) { ev=0; continue; }
460 	    */
461 	}
462 	ev = next_ev;
463     }
464 }
465 #endif /*HAS_SELECT*/
466