ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/iom.C
(Generate patch)

Comparing rxvt-unicode/src/iom.C (file contents):
Revision 1.24 by root, Sat Dec 11 17:18:29 2004 UTC vs.
Revision 1.39 by root, Thu Oct 25 12:42:00 2007 UTC

1/* 1/*
2 iom.C -- generic I/O multiplexer 2 iom.C -- generic I/O multiplexer
3 Copyright (C) 2003, 2004 Marc Lehmann <pcg@goof.com> 3 Copyright (C) 2003-2006 Marc Lehmann <gvpe@schmorp.de>
4 4
5 This file is part of GVPE.
6
5 This program is free software; you can redistribute it and/or modify 7 GVPE is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 8 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or 9 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version. 10 (at your option) any later version.
9 11
10 This program is distributed in the hope that it will be useful, 12 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details. 15 GNU General Public License for more details.
14 16
15 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software 18 along with gvpe; if not, write to the Free Software
17 Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/ 20*/
19 21
20#include "iom.h" 22#include "iom.h"
21 23
22#include <cstdio> 24#include <cstdio>
23#include <cstdlib> 25#include <cstdlib>
24#include <cerrno> 26#include <cerrno>
27#include <cassert>
25 28
29#include <sys/types.h>
26#include <sys/time.h> 30#include <sys/time.h>
27
28#include <assert.h>
29 31
30#if 1 // older unices need these includes for select (2) 32#if 1 // older unices need these includes for select (2)
31# include <unistd.h> 33# include <unistd.h>
32# include <sys/types.h>
33# include <time.h> 34# include <time.h>
34#endif 35#endif
35 36
36// for IOM_SIG 37#if IOM_CHILD
38# include <sys/wait.h>
39#endif
40
37#if IOM_SIG 41#if IOM_SIG
38# include <signal.h> 42# include <csignal>
39# include <fcntl.h> 43# include <fcntl.h>
40#endif 44#endif
41 45
42// if the BSDs would at least be marginally POSIX-compatible.. *sigh* 46// if the BSDs would at least be marginally POSIX-compatible.. *sigh*
43// until that happens, sys/select.h must come last 47// until that happens, sys/select.h must come last
44#include <sys/select.h> 48#include <sys/select.h>
45 49
46// TSTAMP_MAX must still fit into a positive struct timeval
47#define TSTAMP_MAX (double)(1UL<<31)
48
49#define TIMEVAL timeval 50#define TIMEVAL timeval
50#define TV_FRAC tv_usec 51#define TV_FRAC tv_usec
51#define TV_MULT 1000000L 52#define TV_MULT 1000000L
52 53
53#if IOM_IO
54static io_manager_vec<io_watcher> iow;
55#endif
56#if IOM_CHECK 54#if IOM_CHECK
57static io_manager_vec<check_watcher> cw; 55static io_manager_vec<check_watcher> cw;
58#endif 56#endif
59#if IOM_TIME
60static io_manager_vec<time_watcher> tw;
61#endif
62#if IOM_IDLE 57#if IOM_IDLE
63static io_manager_vec<idle_watcher> iw; 58static io_manager_vec<idle_watcher> iw;
64#endif 59#endif
60
65#if IOM_SIG 61#if IOM_SIG
66static int sigpipe[2]; // signal signalling pipe 62static int sigpipe[2]; // signal signalling pipe
67static sigset_t sigs; 63static sigset_t sigs;
68struct sig_vec : io_manager_vec<sig_watcher> { 64struct sig_vec : io_manager_vec<sig_watcher> {
69 int pending; 65 int pending;
72 { } 68 { }
73}; 69};
74static vector<sig_vec *> sw; 70static vector<sig_vec *> sw;
75#endif 71#endif
76 72
73#if IOM_CHILD
74static io_manager_vec<child_watcher> pw;
75#endif
76
77#ifdef IOM_LIBEVENT
78static bool need_set_now; // need to set_now in callback
79#else
80 #if IOM_IO
81 static io_manager_vec<io_watcher> iow;
82 #endif
83 #if IOM_TIME
84 static io_manager_vec<time_watcher> tw;
85 #endif
86#endif
87
88#if IOM_TIME
89tstamp io_manager::now ()
90{
91 struct timeval tv;
92
93 gettimeofday (&tv, 0);
94 return (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000.;
95}
96
97void io_manager::set_now ()
98{
99 NOW = now ();
100 #ifdef IOM_LIBEVENT
101 need_set_now = false;
102 #endif
103}
104#endif
105
106#ifndef IOM_LIBEVENT
77// this is a dummy time watcher to ensure that the first 107// this is a dummy time watcher to ensure that the first
78// time watcher is _always_ valid, this gets rid of a lot 108// time watcher is _always_ valid, this gets rid of a lot
79// of null-pointer-checks 109// of null-pointer-checks
80// (must come _before_ iom is being defined) 110// (must come _before_ iom is being defined)
81static struct tw0 : time_watcher 111static struct tw0 : time_watcher
112{
113 void cb (time_watcher &w)
82 { 114 {
83 void cb (time_watcher &w)
84 {
85 // should never get called 115 // should never get called
86 // reached end-of-time, or tstamp has a bogus definition, 116 // reached end-of-time, or tstamp has a bogus definition,
87 // or compiler initialisation order broken, or something else :) 117 // or compiler initialisation order broken, or something else :)
88 abort (); 118 abort ();
89 } 119 }
90 120
91 tw0 () 121 tw0 ()
92 : time_watcher (this, &tw0::cb) 122 : time_watcher (this, &tw0::cb)
93 { } 123 { }
94 } tw0; 124} tw0;
125#endif
95 126
96tstamp NOW; 127tstamp NOW;
97 128
98#if IOM_TIME 129#if IOM_CHILD
99tstamp io_manager::now () 130// sig_watcher for child signal(s)
131static struct sw0 : sig_watcher
100{ 132{
101 struct timeval tv; 133 void cb (sig_watcher &w)
134 {
135 // SIGCHLD, call corresponding watchera
136 pid_t pid;
137 int status;
102 138
103 gettimeofday (&tv, 0); 139 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
104 return (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000.; 140 for (int i = pw.size (); i--; )
105} 141 {
142 child_watcher *w = pw[i];
106 143
107void io_manager::set_now () 144 if (!w)
108{ 145 pw.erase_unordered (i);
109 NOW = now (); 146 else if (w->pid == pid)
110} 147 {
148 io_manager::unreg (*w);
149 w->call (*w, status);
150 }
151 }
152 }
153
154 sw0 ()
155 : sig_watcher (this, &sw0::cb)
156 { }
157} sw0;
111#endif 158#endif
112 159
113static bool iom_valid; 160static bool iom_valid;
114 161
115// used for initialisation only 162// used for initialisation only
116static struct init { 163static struct init {
117 init () 164 init ()
118 { 165 {
119#if IOM_SIG 166 #ifdef IOM_PREINIT
120 sigemptyset (&sigs); 167 { IOM_PREINIT }
121
122 if (pipe (sigpipe))
123 {
124 perror ("io_manager: unable to create signal pipe, aborting.");
125 abort ();
126 }
127
128 fcntl (sigpipe[0], F_SETFL, O_NONBLOCK);
129 fcntl (sigpipe[1], F_SETFL, O_NONBLOCK);
130#endif 168 #endif
131 169
170 #ifdef IOM_LIBEVENT
171 event_init ();
172 #endif
132 iom_valid = true; 173 iom_valid = true;
133 174
175 #if IOM_SIG
176 sigemptyset (&sigs);
177
178 if (pipe (sigpipe))
179 {
180 perror ("io_manager: unable to create signal pipe, aborting.");
181 abort ();
182 }
183
184 fcntl (sigpipe[0], F_SETFL, O_NONBLOCK); fcntl (sigpipe[0], F_SETFD, FD_CLOEXEC);
185 fcntl (sigpipe[1], F_SETFL, O_NONBLOCK); fcntl (sigpipe[1], F_SETFD, FD_CLOEXEC);
186 #endif
187
188 #if IOM_CHILD
189 sw0.start (SIGCHLD);
190 #endif
191
134#if IOM_TIME 192 #if IOM_TIME
135 io_manager::set_now (); 193 io_manager::set_now ();
136 194
195 #ifndef IOM_LIBEVENT
137 tw0.start (TSTAMP_MAX); 196 tw0.start (TSTAMP_MAX);
197 #endif
138#endif 198 #endif
199
200 #ifdef IOM_POSTINIT
201 { IOM_POSTINIT }
202 #endif
203 }
204
205 ~init ()
206 {
207 iom_valid = false;
139 } 208 }
140 209
141 static void required (); 210 static void required ();
142} init; 211} init;
143 212
176 w.active = 0; 245 w.active = 0;
177 } 246 }
178} 247}
179 248
180#if IOM_TIME 249#if IOM_TIME
250 #ifdef IOM_LIBEVENT
251 void iom_time_c_callback (int fd, short events, void *data)
252 {
253 if (need_set_now) io_manager::set_now ();
254 time_watcher *w = static_cast<time_watcher *>(data);
255 w->call (*w);
256 }
257
181void time_watcher::trigger () 258 void time_watcher::start ()
182{ 259 {
183 call (*this); 260 stop ();
184 io_manager::reg (*this); 261 evtimer_set (&ev, iom_time_c_callback, (void *)this);
185} 262 struct timeval tv;
186 263 tv.tv_sec = (long)at;
264 tv.tv_usec = (long)((at - (tstamp)tv.tv_sec) * 1000000.);
265 evtimer_add (&ev, &tv);
266 active = 1;
267 }
268 #else
187void io_manager::reg (time_watcher &w) { io_manager::reg (w, tw); } 269 void io_manager::reg (time_watcher &w) { io_manager::reg (w, tw); }
188void io_manager::unreg (time_watcher &w) { io_manager::unreg (w, tw); } 270 void io_manager::unreg (time_watcher &w) { io_manager::unreg (w, tw); }
271 #endif
272
273 void time_watcher::trigger ()
274 {
275 call (*this);
276 start ();
277 }
189#endif 278#endif
190 279
191#if IOM_IO 280#if IOM_IO
281 #ifdef IOM_LIBEVENT
282 void iom_io_c_callback (int fd, short events, void *data)
283 {
284 if (need_set_now) io_manager::set_now ();
285 io_watcher *w = static_cast<io_watcher *>(data);
286 w->call (*w, events);
287 }
288
289 void io_watcher::set (int fd_, short events_)
290 {
291 if (active) event_del (&ev);
292 fd = fd_;
293 events = events_;
294 event_set (&ev, fd_, events_ | EV_PERSIST, iom_io_c_callback, (void *)this);
295 if (active) event_add (&ev, 0);
296 }
297 #else
192void io_manager::reg (io_watcher &w) { io_manager::reg (w, iow); } 298 void io_manager::reg (io_watcher &w) { io_manager::reg (w, iow); }
193void io_manager::unreg (io_watcher &w) { io_manager::unreg (w, iow); } 299 void io_manager::unreg (io_watcher &w) { io_manager::unreg (w, iow); }
300 #endif
194#endif 301#endif
195 302
196#if IOM_CHECK 303#if IOM_CHECK
197void io_manager::reg (check_watcher &w) { io_manager::reg (w, cw); } 304void io_manager::reg (check_watcher &w) { io_manager::reg (w, cw); }
198void io_manager::unreg (check_watcher &w) { io_manager::unreg (w, cw); } 305void io_manager::unreg (check_watcher &w) { io_manager::unreg (w, cw); }
215 write (sigpipe[1], &ch, 1); 322 write (sigpipe[1], &ch, 1);
216} 323}
217 324
218void io_manager::reg (sig_watcher &w) 325void io_manager::reg (sig_watcher &w)
219{ 326{
327 init::required ();
328
220 assert (0 < w.signum); 329 assert (0 < w.signum);
221 330
222 sw.reserve (w.signum); 331 sw.reserve (w.signum);
223 332
224 while (sw.size () < w.signum) // pathetic 333 while (sw.size () < w.signum) // pathetic
249 io_manager::reg (w, *sv); 358 io_manager::reg (w, *sv);
250} 359}
251 360
252void io_manager::unreg (sig_watcher &w) 361void io_manager::unreg (sig_watcher &w)
253{ 362{
254 if (!w.active) 363 if (!w.active || !iom_valid)
255 return; 364 return;
256 365
257 assert (0 < w.signum && w.signum <= sw.size ()); 366 assert (0 < w.signum && w.signum <= sw.size ());
258 367
259 io_manager::unreg (w, *sw[w.signum - 1]); 368 io_manager::unreg (w, *sw[w.signum - 1]);
265 this->signum = signum; 374 this->signum = signum;
266 io_manager::reg (*this); 375 io_manager::reg (*this);
267} 376}
268#endif 377#endif
269 378
379#if IOM_CHILD
380void io_manager::reg (child_watcher &w) { io_manager::reg (w, pw); }
381void io_manager::unreg (child_watcher &w) { io_manager::unreg (w, pw); }
382#endif
383
270void io_manager::loop () 384void io_manager::loop ()
271{ 385{
272 init::required (); 386 init::required ();
273 387
274#if IOM_TIME 388 #if IOM_TIME
275 set_now (); 389 set_now ();
276#endif 390 #endif
277 391
278 for (;;) 392 for (;;)
279 { 393 {
280 394 #ifndef IOM_LIBEVENT
281#if IOM_TIME 395 #if IOM_TIME
282 // call pending time watchers 396 // call pending time watchers
283 { 397 {
284 bool activity; 398 bool activity;
285 399
286 do 400 do
287 { 401 {
288 activity = false; 402 activity = false;
289 403
290 for (int i = tw.size (); i--; ) 404 for (int i = tw.size (); i--; )
291 if (!tw[i]) 405 if (!tw[i])
292 tw.erase_unordered (i); 406 tw.erase_unordered (i);
293 else if (tw[i]->at <= NOW) 407 else if (tw[i]->at <= NOW)
294 { 408 {
295 time_watcher &w = *tw[i]; 409 time_watcher &w = *tw[i];
410
411 unreg (w);
412 w.call (w);
413
414 activity = true;
296 415 }
297 unreg (w);
298 w.call (w);
299
300 activity = true;
301 }
302 } 416 }
303 while (activity); 417 while (activity);
304 } 418 }
305#endif 419 #endif
420 #endif
306 421
307#if IOM_CHECK 422 #if IOM_CHECK
308 // call all check watchers 423 // call all check watchers
309 for (int i = cw.size (); i--; ) 424 for (int i = cw.size (); i--; )
310 if (!cw[i]) 425 if (!cw[i])
311 cw.erase_unordered (i); 426 cw.erase_unordered (i);
312 else 427 else
313 cw[i]->call (*cw[i]); 428 cw[i]->call (*cw[i]);
314#endif 429 #endif
315 430
316 struct TIMEVAL *to = 0; 431 struct TIMEVAL *to = 0;
317 struct TIMEVAL tval; 432 struct TIMEVAL tval;
318 433
319#if IOM_IDLE 434#if IOM_IDLE
324 to = &tval; 439 to = &tval;
325 } 440 }
326 else 441 else
327#endif 442#endif
328 { 443 {
329#if IOM_TIME 444 #ifndef IOM_LIBEVENT
445 #if IOM_TIME
330 // find earliest active watcher 446 // find earliest active watcher
331 time_watcher *next = tw[0]; // the first time-watcher must exist at ALL times 447 time_watcher *next = tw[0]; // the first time-watcher must exist at ALL times
332 448
333 for (io_manager_vec<time_watcher>::const_iterator i = tw.end (); i-- > tw.begin (); ) 449 for (io_manager_vec<time_watcher>::const_iterator i = tw.end (); i-- > tw.begin (); )
334 if (*i && (*i)->at < next->at) 450 if (*i && (*i)->at < next->at)
335 next = *i; 451 next = *i;
336 452
337 if (next->at > NOW && next != tw[0]) 453 if (next->at > NOW && next != tw[0])
338 { 454 {
339 double diff = next->at - NOW; 455 double diff = next->at - NOW;
340 tval.tv_sec = (int)diff; 456 tval.tv_sec = (int)diff;
341 tval.TV_FRAC = (int) ((diff - tval.tv_sec) * TV_MULT); 457 tval.TV_FRAC = (int) ((diff - tval.tv_sec) * TV_MULT);
342 to = &tval; 458 to = &tval;
343 } 459 }
460 #endif
461 #endif
344 } 462 }
345#endif
346 463
464 #ifndef IOM_LIBEVENT
347#if IOM_IO || IOM_SIG 465 #if IOM_IO || IOM_SIG
348 fd_set rfd, wfd; 466 fd_set rfd, wfd;
349 467
350 FD_ZERO (&rfd); 468 FD_ZERO (&rfd);
351 FD_ZERO (&wfd); 469 FD_ZERO (&wfd);
352 470
353 int fds = 0; 471 int fds = 0;
354 472
355# if IOM_IO 473 #if IOM_IO
356 for (io_manager_vec<io_watcher>::const_iterator i = iow.end (); i-- > iow.begin (); ) 474 for (io_manager_vec<io_watcher>::const_iterator i = iow.end (); i-- > iow.begin (); )
357 if (*i) 475 if (*i)
476 {
477 if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd);
478 if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd);
479
480 if ((*i)->fd >= fds) fds = (*i)->fd + 1;
481 }
482 #endif
483
484 if (!to && !fds) //TODO: also check idle_watchers and check_watchers?
485 break; // no events
486
487 #if IOM_SIG
488 FD_SET (sigpipe[0], &rfd);
489 if (sigpipe[0] >= fds) fds = sigpipe[0] + 1;
490 #endif
491
492 #if IOM_SIG
493 // there is no race, as we use a pipe for signals, so select
494 // will return if a signal is caught.
495 sigprocmask (SIG_UNBLOCK, &sigs, NULL);
496 #endif
497 fds = select (fds, &rfd, &wfd, NULL, to);
498 #if IOM_SIG
499 sigprocmask (SIG_BLOCK, &sigs, NULL);
500 #endif
501 #elif IOM_TIME
502 if (!to)
503 break;
504
505 select (0, 0, 0, 0, to);
506 #endif
507
508 #if IOM_TIME
358 { 509 {
359 if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd); 510 // update time, try to compensate for gross non-monotonic time changes
360 if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd); 511 tstamp diff = NOW;
512 set_now ();
513 diff = NOW - diff;
361 514
362 if ((*i)->fd >= fds) fds = (*i)->fd + 1; 515 if (diff < 0)
516 for (io_manager_vec<time_watcher>::const_iterator i = tw.end (); i-- > tw.begin (); )
517 if (*i)
518 (*i)->at += diff;
363 } 519 }
364# endif 520 #endif
365 521
366 if (!to && !fds) //TODO: also check idle_watchers and check_watchers?
367 break; // no events
368
369# if IOM_SIG
370 FD_SET (sigpipe[0], &rfd);
371 if (sigpipe[0] >= fds) fds = sigpipe[0] + 1;
372# endif
373
374# if IOM_SIG
375 // there is no race, as we use a pipe for signals, so select
376 // will return if a signal is caught.
377 sigprocmask (SIG_UNBLOCK, &sigs, NULL);
378# endif
379 fds = select (fds, &rfd, &wfd, NULL, to);
380# if IOM_SIG
381 sigprocmask (SIG_BLOCK, &sigs, NULL);
382# endif
383
384# if IOM_TIME
385 set_now ();
386# endif
387
388 if (fds > 0) 522 if (fds > 0)
389 { 523 {
390# if IOM_SIG 524 #if IOM_SIG
391 if (FD_ISSET (sigpipe[0], &rfd)) 525 if (FD_ISSET (sigpipe[0], &rfd))
392 { 526 {
393 char ch; 527 char ch;
394 528
395 while (read (sigpipe[0], &ch, 1) > 0) 529 while (read (sigpipe[0], &ch, 1) > 0)
396 ; 530 ;
397 531
398 for (vector<sig_vec *>::iterator svp = sw.end (); svp-- > sw.begin (); ) 532 for (vector<sig_vec *>::iterator svp = sw.end (); svp-- > sw.begin (); )
399 if (*svp && (*svp)->pending) 533 if (*svp && (*svp)->pending)
534 {
535 sig_vec &sv = **svp;
536 for (int i = sv.size (); i--; )
537 if (!sv[i])
538 sv.erase_unordered (i);
539 else
540 sv[i]->call (*sv[i]);
541
542 sv.pending = false;
543 }
544 }
545 #endif
546
547 #if IOM_IO
548 for (int i = iow.size (); i--; )
549 if (!iow[i])
550 iow.erase_unordered (i);
551 else
400 { 552 {
401 sig_vec &sv = **svp; 553 io_watcher &w = *iow[i];
402 for (int i = sv.size (); i--; ) 554 short revents = w.events;
555
556 if (!FD_ISSET (w.fd, &rfd)) revents &= ~EVENT_READ;
557 if (!FD_ISSET (w.fd, &wfd)) revents &= ~EVENT_WRITE;
558
403 if (!sv[i]) 559 if (revents)
404 sv.erase_unordered (i); 560 w.call (w, revents);
405 else
406 sv[i]->call (*sv[i]);
407
408 sv.pending = false;
409 } 561 }
562 #endif
410 } 563 }
411# endif 564 else if (fds < 0 && errno != EINTR)
412 565 {
566 perror ("io_manager: fatal error while waiting for I/O or time event, aborting.");
567 abort ();
568 }
413# if IOM_IO 569#if IOM_IDLE
570 else
414 for (int i = iow.size (); i--; ) 571 for (int i = iw.size (); i--; )
415 if (!iow[i]) 572 if (!iw[i])
416 iow.erase_unordered (i); 573 iw.erase_unordered (i);
417 else 574 else
418 {
419 short revents = iow[i]->events;
420
421 if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ;
422 if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE;
423
424 if (revents)
425 iow[i]->call (*iow[i], revents);
426 }
427#endif
428 }
429 else if (fds < 0 && errno != EINTR)
430 {
431 perror ("io_manager: fatal error while waiting for I/O or time event, aborting.");
432 abort ();
433 }
434#if IOM_IDLE
435 else
436 for (int i = iw.size (); i--; )
437 if (!iw[i])
438 iw.erase_unordered (i);
439 else
440 iw[i]->call (*iw[i]); 575 iw[i]->call (*iw[i]);
441#endif 576#endif
442 577
443#elif IOM_TIME 578 #else
579 need_set_now = true;
580
444 if (!to) 581 if (to)
445 break; 582 event_loop (EVLOOP_NONBLOCK);
583 else
584 event_loop (EVLOOP_ONCE);
446 585
447 select (0, 0, 0, 0, &to); 586 if (need_set_now) set_now ();
448 set_now (); 587 #endif
449#else 588 //TODO: IOM_IDLE
450 break;
451#endif
452 } 589 }
453} 590}
454 591

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines