--- rxvt-unicode/src/iom.C 2003/12/02 21:49:46 1.6 +++ rxvt-unicode/src/iom.C 2004/01/29 23:26:01 1.12 @@ -1,6 +1,6 @@ /* iom.C -- generic I/O multiplexor - Copyright (C) 2003 Marc Lehmann + Copyright (C) 2003, 2004 Marc Lehmann This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,51 +17,77 @@ Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "../config.h" - #include +#include +#include -#include #include +#if 1 // older unices need these includes for select(2) +# include +# include +#endif + +// if the BSDs would at least be marginally POSIX-compatible.. *sigh* +// until that happens, sys/select.h must come last +#include + #include "iom.h" +// TSTAMP_MAX must still fit into a positive struct timeval +#define TSTAMP_MAX (double)(1UL<<31) + +// this is a dummy time watcher to ensure that the first +// time watcher is _always_ valid, this gets rid of a lot +// of null-pointer-checks +// (must come _before_ iom is being defined) +static struct tw0 : time_watcher { + void cb (time_watcher &w) + { + // should never get called + // reached end-of-time, or tstamp has a bogus definition, + // or compiler initilization order broken, or somethine else :) + abort (); + } + + tw0() + : time_watcher (this, &tw0::cb) + { } +} tw0; + tstamp NOW; -bool iom_valid; +static bool iom_valid; io_manager iom; template -void io_manager::reg (watcher *w, simplevec &queue) +void io_manager::reg (watcher *w, io_manager_vec &queue) { - if (find (queue.begin (), queue.end (), w) == queue.end ()) - queue.push_back (w); -} + if (!iom_valid) + abort (); -template -void io_manager::unreg (watcher *w, simplevec &queue) -{ - queue.erase (find (queue.begin (), queue.end (), w)); + if (!w->active) + { +#if IOM_CHECK + queue.activity = true; +#endif + queue.push_back (w); + w->active = queue.size (); + } } -#if IOM_IO -io_watcher::~io_watcher () +template +void io_manager::unreg (watcher *w, io_manager_vec &queue) { - if (iom_valid) - iom.unreg (this); -} + if (!iom_valid) + return; -void io_manager::reg (io_watcher *w) -{ - reg (w, iow); -} - -void io_manager::unreg (io_watcher *w) -{ - unreg (w, iow); + if (w->active) + { + queue [w->active - 1] = 0; + w->active = 0; + } } -#endif - #if IOM_TIME void time_watcher::trigger () { @@ -70,41 +96,23 @@ iom.reg (this); } -time_watcher::~time_watcher () -{ - if (iom_valid) - iom.unreg (this); - - at = TSTAMP_CANCEL; -} - -void io_manager::reg (time_watcher *w) -{ - reg (w, tw); -} +void io_manager::reg (time_watcher *w) { reg (w, tw); } +void io_manager::unreg (time_watcher *w) { unreg (w, tw); } +#endif -void io_manager::unreg (time_watcher *w) -{ - unreg (w, tw); -} +#if IOM_IO +void io_manager::reg (io_watcher *w) { reg (w, iow); } +void io_manager::unreg (io_watcher *w) { unreg (w, iow); } #endif #if IOM_CHECK -check_watcher::~check_watcher () -{ - if (iom_valid) - iom.unreg (this); -} - -void io_manager::reg (check_watcher *w) -{ - reg (w, cw); -} +void io_manager::reg (check_watcher *w) { reg (w, cw); } +void io_manager::unreg (check_watcher *w) { unreg (w, cw); } +#endif -void io_manager::unreg (check_watcher *w) -{ - unreg (w, cw); -} +#if IOM_IDLE +void io_manager::reg (idle_watcher *w) { reg (w, iw); } +void io_manager::unreg (idle_watcher *w) { unreg (w, iw); } #endif #if IOM_TIME @@ -127,76 +135,121 @@ for (;;) { struct timeval *to = 0; - -#if IOM_TIME struct timeval tval; - time_watcher *w; - for (;tw.size ();) +#if IOM_IDLE + if (iw.size ()) { - w = tw[0]; - - for (time_watcher **i = tw.begin (); i < tw.end (); ++i) - if ((*i)->at < w->at) - w = *i; + tval.tv_sec = 0; + tval.tv_usec = 0; + to = &tval; + } + else +#endif + { +#if IOM_TIME + time_watcher *next; - if (w->at > NOW) + for (;;) { - double diff = w->at - NOW; - tval.tv_sec = (int)diff; - tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000); - to = &tval; - break; + next = tw[0]; // the first time-watcher must exist at ALL times + + for (int i = tw.size (); i--; ) + if (!tw[i]) + tw.erase_unordered (i); + else if (tw[i]->at < next->at) + next = tw[i]; + + if (next->at > NOW) + { + if (next != tw[0]) + { + double diff = next->at - NOW; + tval.tv_sec = (int)diff; + tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000); + to = &tval; + } + break; + } + else + { + unreg (next); + next->call (*next); + } } - else if (w->at >= 0) - w->call (*w); - else - unreg (w); - } #endif + } #if IOM_CHECK - for (int i = 0; i < cw.size (); ++i) - cw[i]->call (*cw[i]); + tw.activity = false; + + for (int i = cw.size (); i--; ) + if (!cw[i]) + cw.erase_unordered (i); + else + cw[i]->call (*cw[i]); + + if (tw.activity) + { + tval.tv_sec = 0; + tval.tv_usec = 0; + to = &tval; + } #endif #if IOM_IO - fd_set rfd, wfd; + fd_set rfd, wfd, efd; FD_ZERO (&rfd); FD_ZERO (&wfd); int fds = 0; - for (io_watcher **w = iow.begin (); w < iow.end (); ++w) - { - if ((*w)->events & EVENT_READ ) FD_SET ((*w)->fd, &rfd); - if ((*w)->events & EVENT_WRITE) FD_SET ((*w)->fd, &wfd); + for (io_manager_vec::iterator i = iow.end (); i-- > iow.begin (); ) + if (*i) + { + if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd); + if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd); - if ((*w)->fd >= fds) fds = (*w)->fd + 1; - } + if ((*i)->fd >= fds) fds = (*i)->fd + 1; + } - if (!to && !fds) + if (!to && !fds) //TODO: also check idle_watchers and check_watchers break; // no events - fds = select (fds, &rfd, &wfd, 0, to); + fds = select (fds, &rfd, &wfd, &efd, to); # if IOM_TIME set_now (); # endif if (fds > 0) - for (int i = 0; i < iow.size (); ++i) - { - io_watcher *w = iow[i]; + for (int i = iow.size (); i--; ) + if (!iow[i]) + iow.erase_unordered (i); + else + { + short revents = iow[i]->events; - short revents = w->events; + if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ; + if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE; - if (!FD_ISSET (w->fd, &rfd)) revents &= ~EVENT_READ; - if (!FD_ISSET (w->fd, &wfd)) revents &= ~EVENT_WRITE; + if (revents) + iow[i]->call (*iow[i], revents); + } + else if (fds < 0 && errno != EINTR) + { + perror ("Error while waiting for I/O or time event"); + abort (); + } +#if IOM_IDLE + else + for (int i = iw.size (); i--; ) + if (!iw[i]) + iw.erase_unordered (i); + else + iw[i]->call (*iw[i]); +#endif - if (revents) - w->call (*w, revents); - } #elif IOM_TIME if (!to) break; @@ -211,11 +264,13 @@ io_manager::io_manager () { + iom_valid = true; + #if IOM_TIME set_now (); -#endif - iom_valid = true; + tw0.start (TSTAMP_MAX); +#endif } io_manager::~io_manager ()