ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/iom.C
Revision: 1.12
Committed: Thu Jan 29 23:26:01 2004 UTC (20 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: before_astyle
Changes since 1.11: +12 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     iom.C -- generic I/O multiplexor
3 pcg 1.9 Copyright (C) 2003, 2004 Marc Lehmann <pcg@goof.com>
4 pcg 1.1
5     This program is free software; you can redistribute it and/or modify
6     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
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18     */
19    
20     #include <cstdio>
21 pcg 1.8 #include <cstdlib>
22     #include <cerrno>
23 pcg 1.1
24 pcg 1.11 #include <sys/time.h>
25    
26     #if 1 // older unices need these includes for select(2)
27     # include <unistd.h>
28     # include <sys/types.h>
29     #endif
30    
31     // if the BSDs would at least be marginally POSIX-compatible.. *sigh*
32     // until that happens, sys/select.h must come last
33 pcg 1.1 #include <sys/select.h>
34    
35     #include "iom.h"
36    
37 pcg 1.8 // TSTAMP_MAX must still fit into a positive struct timeval
38     #define TSTAMP_MAX (double)(1UL<<31)
39    
40 pcg 1.10 // this is a dummy time watcher to ensure that the first
41     // time watcher is _always_ valid, this gets rid of a lot
42     // of null-pointer-checks
43     // (must come _before_ iom is being defined)
44     static struct tw0 : time_watcher {
45     void cb (time_watcher &w)
46     {
47     // should never get called
48     // reached end-of-time, or tstamp has a bogus definition,
49     // or compiler initilization order broken, or somethine else :)
50     abort ();
51     }
52    
53     tw0()
54     : time_watcher (this, &tw0::cb)
55     { }
56     } tw0;
57    
58 pcg 1.1 tstamp NOW;
59 pcg 1.8 static bool iom_valid;
60 pcg 1.1 io_manager iom;
61    
62 pcg 1.4 template<class watcher>
63 pcg 1.9 void io_manager::reg (watcher *w, io_manager_vec<watcher> &queue)
64 pcg 1.4 {
65 pcg 1.8 if (!iom_valid)
66     abort ();
67    
68     if (!w->active)
69     {
70 pcg 1.12 #if IOM_CHECK
71     queue.activity = true;
72     #endif
73 pcg 1.8 queue.push_back (w);
74     w->active = queue.size ();
75     }
76 pcg 1.4 }
77    
78     template<class watcher>
79 pcg 1.9 void io_manager::unreg (watcher *w, io_manager_vec<watcher> &queue)
80 pcg 1.4 {
81 pcg 1.8 if (!iom_valid)
82     return;
83 pcg 1.4
84 pcg 1.8 if (w->active)
85     {
86     queue [w->active - 1] = 0;
87     w->active = 0;
88     }
89 pcg 1.4 }
90    
91     #if IOM_TIME
92 pcg 1.1 void time_watcher::trigger ()
93     {
94     call (*this);
95    
96     iom.reg (this);
97     }
98    
99 pcg 1.8 void io_manager::reg (time_watcher *w) { reg (w, tw); }
100     void io_manager::unreg (time_watcher *w) { unreg (w, tw); }
101     #endif
102 pcg 1.3
103 pcg 1.8 #if IOM_IO
104     void io_manager::reg (io_watcher *w) { reg (w, iow); }
105     void io_manager::unreg (io_watcher *w) { unreg (w, iow); }
106 pcg 1.4 #endif
107 pcg 1.1
108 pcg 1.4 #if IOM_CHECK
109 pcg 1.8 void io_manager::reg (check_watcher *w) { reg (w, cw); }
110     void io_manager::unreg (check_watcher *w) { unreg (w, cw); }
111 pcg 1.4 #endif
112 pcg 1.1
113 pcg 1.7 #if IOM_IDLE
114 pcg 1.8 void io_manager::reg (idle_watcher *w) { reg (w, iw); }
115     void io_manager::unreg (idle_watcher *w) { unreg (w, iw); }
116 pcg 1.7 #endif
117    
118 pcg 1.4 #if IOM_TIME
119 pcg 1.1 inline void set_now (void)
120     {
121     struct timeval tv;
122    
123     gettimeofday (&tv, 0);
124    
125     NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
126 pcg 1.4 #endif
127 pcg 1.1 }
128    
129     void io_manager::loop ()
130     {
131 pcg 1.4 #if IOM_TIME
132 pcg 1.1 set_now ();
133 pcg 1.4 #endif
134 pcg 1.1
135     for (;;)
136     {
137 pcg 1.5 struct timeval *to = 0;
138     struct timeval tval;
139 pcg 1.1
140 pcg 1.7 #if IOM_IDLE
141     if (iw.size ())
142     {
143     tval.tv_sec = 0;
144     tval.tv_usec = 0;
145     to = &tval;
146     }
147     else
148     #endif
149 pcg 1.1 {
150 pcg 1.7 #if IOM_TIME
151 pcg 1.8 time_watcher *next;
152 pcg 1.1
153 pcg 1.8 for (;;)
154 pcg 1.7 {
155 pcg 1.8 next = tw[0]; // the first time-watcher must exist at ALL times
156 pcg 1.1
157 pcg 1.8 for (int i = tw.size (); i--; )
158     if (!tw[i])
159     tw.erase_unordered (i);
160     else if (tw[i]->at < next->at)
161     next = tw[i];
162 pcg 1.7
163 pcg 1.8 if (next->at > NOW)
164 pcg 1.7 {
165 pcg 1.8 if (next != tw[0])
166     {
167     double diff = next->at - NOW;
168     tval.tv_sec = (int)diff;
169     tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000);
170     to = &tval;
171     }
172 pcg 1.7 break;
173     }
174 pcg 1.9 else
175 pcg 1.8 {
176     unreg (next);
177     next->call (*next);
178     }
179 pcg 1.5 }
180 pcg 1.7 #endif
181 pcg 1.1 }
182 pcg 1.6
183     #if IOM_CHECK
184 pcg 1.12 tw.activity = false;
185    
186 pcg 1.8 for (int i = cw.size (); i--; )
187     if (!cw[i])
188     cw.erase_unordered (i);
189     else
190     cw[i]->call (*cw[i]);
191 pcg 1.12
192     if (tw.activity)
193     {
194     tval.tv_sec = 0;
195     tval.tv_usec = 0;
196     to = &tval;
197     }
198 pcg 1.4 #endif
199 pcg 1.1
200 pcg 1.4 #if IOM_IO
201 pcg 1.8 fd_set rfd, wfd, efd;
202 pcg 1.1
203     FD_ZERO (&rfd);
204     FD_ZERO (&wfd);
205    
206     int fds = 0;
207    
208 pcg 1.9 for (io_manager_vec<io_watcher>::iterator i = iow.end (); i-- > iow.begin (); )
209 pcg 1.8 if (*i)
210     {
211     if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd);
212     if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd);
213 pcg 1.1
214 pcg 1.8 if ((*i)->fd >= fds) fds = (*i)->fd + 1;
215     }
216 pcg 1.1
217 pcg 1.8 if (!to && !fds) //TODO: also check idle_watchers and check_watchers
218 pcg 1.5 break; // no events
219    
220 pcg 1.8 fds = select (fds, &rfd, &wfd, &efd, to);
221 pcg 1.4 # if IOM_TIME
222 pcg 1.1 set_now ();
223 pcg 1.4 # endif
224 pcg 1.1
225     if (fds > 0)
226 pcg 1.8 for (int i = iow.size (); i--; )
227     if (!iow[i])
228     iow.erase_unordered (i);
229     else
230     {
231     short revents = iow[i]->events;
232 pcg 1.1
233 pcg 1.8 if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ;
234     if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE;
235 pcg 1.4
236 pcg 1.8 if (revents)
237     iow[i]->call (*iow[i], revents);
238     }
239     else if (fds < 0 && errno != EINTR)
240     {
241     perror ("Error while waiting for I/O or time event");
242     abort ();
243     }
244 pcg 1.7 #if IOM_IDLE
245 pcg 1.8 else
246     for (int i = iw.size (); i--; )
247     if (!iw[i])
248     iw.erase_unordered (i);
249     else
250     iw[i]->call (*iw[i]);
251 pcg 1.7 #endif
252    
253 pcg 1.4 #elif IOM_TIME
254 pcg 1.5 if (!to)
255     break;
256    
257 pcg 1.4 select (0, 0, 0, 0, &to);
258     set_now ();
259 pcg 1.5 #else
260     break;
261 pcg 1.4 #endif
262 pcg 1.5 }
263 pcg 1.1 }
264    
265     io_manager::io_manager ()
266     {
267 pcg 1.8 iom_valid = true;
268    
269 pcg 1.5 #if IOM_TIME
270 pcg 1.1 set_now ();
271 pcg 1.8
272     tw0.start (TSTAMP_MAX);
273 pcg 1.5 #endif
274 pcg 1.1 }
275    
276     io_manager::~io_manager ()
277     {
278     iom_valid = false;
279     }
280