ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/iom.C
Revision: 1.10
Committed: Sat Jan 17 14:10:40 2004 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +19 -16 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 iom.C -- generic I/O multiplexor
3 Copyright (C) 2003, 2004 Marc Lehmann <pcg@goof.com>
4
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 #include <cstdlib>
22 #include <cerrno>
23
24 #include <sys/select.h>
25 #include <sys/time.h>
26
27 #include "iom.h"
28
29 // TSTAMP_MAX must still fit into a positive struct timeval
30 #define TSTAMP_MAX (double)(1UL<<31)
31
32 // this is a dummy time watcher to ensure that the first
33 // time watcher is _always_ valid, this gets rid of a lot
34 // of null-pointer-checks
35 // (must come _before_ iom is being defined)
36 static struct tw0 : time_watcher {
37 void cb (time_watcher &w)
38 {
39 // should never get called
40 // reached end-of-time, or tstamp has a bogus definition,
41 // or compiler initilization order broken, or somethine else :)
42 abort ();
43 }
44
45 tw0()
46 : time_watcher (this, &tw0::cb)
47 { }
48 } tw0;
49
50 tstamp NOW;
51 static bool iom_valid;
52 io_manager iom;
53
54 template<class watcher>
55 void io_manager::reg (watcher *w, io_manager_vec<watcher> &queue)
56 {
57 if (!iom_valid)
58 abort ();
59
60 if (!w->active)
61 {
62 queue.push_back (w);
63 w->active = queue.size ();
64 }
65 }
66
67 template<class watcher>
68 void io_manager::unreg (watcher *w, io_manager_vec<watcher> &queue)
69 {
70 if (!iom_valid)
71 return;
72
73 if (w->active)
74 {
75 queue [w->active - 1] = 0;
76 w->active = 0;
77 }
78 }
79
80 #if IOM_TIME
81 void time_watcher::trigger ()
82 {
83 call (*this);
84
85 iom.reg (this);
86 }
87
88 void io_manager::reg (time_watcher *w) { reg (w, tw); }
89 void io_manager::unreg (time_watcher *w) { unreg (w, tw); }
90 #endif
91
92 #if IOM_IO
93 void io_manager::reg (io_watcher *w) { reg (w, iow); }
94 void io_manager::unreg (io_watcher *w) { unreg (w, iow); }
95 #endif
96
97 #if IOM_CHECK
98 void io_manager::reg (check_watcher *w) { reg (w, cw); }
99 void io_manager::unreg (check_watcher *w) { unreg (w, cw); }
100 #endif
101
102 #if IOM_IDLE
103 void io_manager::reg (idle_watcher *w) { reg (w, iw); }
104 void io_manager::unreg (idle_watcher *w) { unreg (w, iw); }
105 #endif
106
107 #if IOM_TIME
108 inline void set_now (void)
109 {
110 struct timeval tv;
111
112 gettimeofday (&tv, 0);
113
114 NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
115 #endif
116 }
117
118 void io_manager::loop ()
119 {
120 #if IOM_TIME
121 set_now ();
122 #endif
123
124 for (;;)
125 {
126 struct timeval *to = 0;
127 struct timeval tval;
128
129 #if IOM_IDLE
130 if (iw.size ())
131 {
132 tval.tv_sec = 0;
133 tval.tv_usec = 0;
134 to = &tval;
135 }
136 else
137 #endif
138 {
139 #if IOM_TIME
140 time_watcher *next;
141
142 for (;;)
143 {
144 next = tw[0]; // the first time-watcher must exist at ALL times
145
146 for (int i = tw.size (); i--; )
147 if (!tw[i])
148 tw.erase_unordered (i);
149 else if (tw[i]->at < next->at)
150 next = tw[i];
151
152 if (next->at > NOW)
153 {
154 if (next != tw[0])
155 {
156 double diff = next->at - NOW;
157 tval.tv_sec = (int)diff;
158 tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000);
159 to = &tval;
160 }
161 break;
162 }
163 else
164 {
165 unreg (next);
166 next->call (*next);
167 }
168 }
169 #endif
170 }
171
172 #if IOM_CHECK
173 for (int i = cw.size (); i--; )
174 if (!cw[i])
175 cw.erase_unordered (i);
176 else
177 cw[i]->call (*cw[i]);
178 #endif
179
180 #if IOM_IO
181 fd_set rfd, wfd, efd;
182
183 FD_ZERO (&rfd);
184 FD_ZERO (&wfd);
185
186 int fds = 0;
187
188 for (io_manager_vec<io_watcher>::iterator i = iow.end (); i-- > iow.begin (); )
189 if (*i)
190 {
191 if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd);
192 if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd);
193
194 if ((*i)->fd >= fds) fds = (*i)->fd + 1;
195 }
196
197 if (!to && !fds) //TODO: also check idle_watchers and check_watchers
198 break; // no events
199
200 fds = select (fds, &rfd, &wfd, &efd, to);
201 # if IOM_TIME
202 set_now ();
203 # endif
204
205 if (fds > 0)
206 for (int i = iow.size (); i--; )
207 if (!iow[i])
208 iow.erase_unordered (i);
209 else
210 {
211 short revents = iow[i]->events;
212
213 if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ;
214 if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE;
215
216 if (revents)
217 iow[i]->call (*iow[i], revents);
218 }
219 else if (fds < 0 && errno != EINTR)
220 {
221 perror ("Error while waiting for I/O or time event");
222 abort ();
223 }
224 #if IOM_IDLE
225 else
226 for (int i = iw.size (); i--; )
227 if (!iw[i])
228 iw.erase_unordered (i);
229 else
230 iw[i]->call (*iw[i]);
231 #endif
232
233 #elif IOM_TIME
234 if (!to)
235 break;
236
237 select (0, 0, 0, 0, &to);
238 set_now ();
239 #else
240 break;
241 #endif
242 }
243 }
244
245 io_manager::io_manager ()
246 {
247 iom_valid = true;
248
249 #if IOM_TIME
250 set_now ();
251
252 tw0.start (TSTAMP_MAX);
253 printf ("abort, %f but inly on %f\n", NOW, tw0.at);
254 #endif
255 }
256
257 io_manager::~io_manager ()
258 {
259 iom_valid = false;
260 }
261