ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/iom.C
Revision: 1.16
Committed: Sat Jan 17 16:49:01 2004 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: VPE_1_4
Changes since 1.15: +0 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2 pcg 1.12 iom.C -- generic I/O multiplexor
3 pcg 1.13 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 pcg 1.13 #include <cstdio>
21     #include <cstdlib>
22     #include <cerrno>
23 pcg 1.1
24 pcg 1.15 #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.13 #include <sys/select.h>
34 pcg 1.1
35 pcg 1.13 #include "iom.h"
36 pcg 1.11
37 pcg 1.13 // TSTAMP_MAX must still fit into a positive struct timeval
38     #define TSTAMP_MAX (double)(1UL<<31)
39 pcg 1.1
40 pcg 1.14 // 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.10 tstamp NOW;
59 pcg 1.13 static bool iom_valid;
60 pcg 1.10 io_manager iom;
61    
62 pcg 1.13 template<class watcher>
63     void io_manager::reg (watcher *w, io_manager_vec<watcher> &queue)
64 pcg 1.4 {
65 pcg 1.13 if (!iom_valid)
66     abort ();
67 pcg 1.4
68 pcg 1.13 if (!w->active)
69 pcg 1.11 {
70 pcg 1.13 queue.push_back (w);
71     w->active = queue.size ();
72 pcg 1.11 }
73 pcg 1.10 }
74    
75 pcg 1.13 template<class watcher>
76     void io_manager::unreg (watcher *w, io_manager_vec<watcher> &queue)
77 pcg 1.10 {
78 pcg 1.13 if (!iom_valid)
79     return;
80 pcg 1.10
81 pcg 1.13 if (w->active)
82 pcg 1.11 {
83 pcg 1.13 queue [w->active - 1] = 0;
84     w->active = 0;
85 pcg 1.11 }
86 pcg 1.1 }
87    
88 pcg 1.13 #if IOM_TIME
89     void time_watcher::trigger ()
90 pcg 1.1 {
91 pcg 1.13 call (*this);
92 pcg 1.11
93 pcg 1.13 iom.reg (this);
94 pcg 1.1 }
95    
96 pcg 1.13 void io_manager::reg (time_watcher *w) { reg (w, tw); }
97     void io_manager::unreg (time_watcher *w) { unreg (w, tw); }
98     #endif
99 pcg 1.6
100 pcg 1.13 #if IOM_IO
101     void io_manager::reg (io_watcher *w) { reg (w, iow); }
102     void io_manager::unreg (io_watcher *w) { unreg (w, iow); }
103     #endif
104 pcg 1.7
105 pcg 1.13 #if IOM_CHECK
106     void io_manager::reg (check_watcher *w) { reg (w, cw); }
107     void io_manager::unreg (check_watcher *w) { unreg (w, cw); }
108     #endif
109 pcg 1.1
110 pcg 1.13 #if IOM_IDLE
111     void io_manager::reg (idle_watcher *w) { reg (w, iw); }
112     void io_manager::unreg (idle_watcher *w) { unreg (w, iw); }
113     #endif
114 pcg 1.1
115 pcg 1.13 #if IOM_TIME
116 pcg 1.1 inline void set_now (void)
117     {
118     struct timeval tv;
119    
120     gettimeofday (&tv, 0);
121    
122 pcg 1.2 NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
123 pcg 1.13 #endif
124 pcg 1.1 }
125    
126     void io_manager::loop ()
127     {
128 pcg 1.13 #if IOM_TIME
129 pcg 1.1 set_now ();
130 pcg 1.13 #endif
131 pcg 1.1
132 pcg 1.4 for (;;)
133 pcg 1.1 {
134 pcg 1.13 struct timeval *to = 0;
135     struct timeval tval;
136    
137     #if IOM_IDLE
138     if (iw.size ())
139     {
140     tval.tv_sec = 0;
141     tval.tv_usec = 0;
142     to = &tval;
143     }
144     else
145     #endif
146 pcg 1.4 {
147 pcg 1.13 #if IOM_TIME
148     time_watcher *next;
149 pcg 1.7
150 pcg 1.13 for (;;)
151     {
152     next = tw[0]; // the first time-watcher must exist at ALL times
153    
154     for (int i = tw.size (); i--; )
155     if (!tw[i])
156     tw.erase_unordered (i);
157     else if (tw[i]->at < next->at)
158     next = tw[i];
159    
160     if (next->at > NOW)
161     {
162     if (next != tw[0])
163     {
164     double diff = next->at - NOW;
165     tval.tv_sec = (int)diff;
166     tval.tv_usec = (int)((diff - tval.tv_sec) * 1000000);
167     to = &tval;
168     }
169     break;
170     }
171     else
172     {
173     unreg (next);
174     next->call (*next);
175     }
176     }
177     #endif
178     }
179 pcg 1.1
180 pcg 1.13 #if IOM_CHECK
181     for (int i = cw.size (); i--; )
182     if (!cw[i])
183     cw.erase_unordered (i);
184     else
185     cw[i]->call (*cw[i]);
186     #endif
187    
188     #if IOM_IO
189     fd_set rfd, wfd, efd;
190 pcg 1.7
191 pcg 1.13 FD_ZERO (&rfd);
192     FD_ZERO (&wfd);
193 pcg 1.7
194 pcg 1.13 int fds = 0;
195    
196     for (io_manager_vec<io_watcher>::iterator i = iow.end (); i-- > iow.begin (); )
197     if (*i)
198     {
199     if ((*i)->events & EVENT_READ ) FD_SET ((*i)->fd, &rfd);
200     if ((*i)->events & EVENT_WRITE) FD_SET ((*i)->fd, &wfd);
201 pcg 1.1
202 pcg 1.13 if ((*i)->fd >= fds) fds = (*i)->fd + 1;
203     }
204 pcg 1.1
205 pcg 1.13 if (!to && !fds) //TODO: also check idle_watchers and check_watchers
206     break; // no events
207 pcg 1.1
208 pcg 1.13 fds = select (fds, &rfd, &wfd, &efd, to);
209     # if IOM_TIME
210 pcg 1.4 set_now ();
211 pcg 1.13 # endif
212 pcg 1.1
213 pcg 1.13 if (fds > 0)
214     for (int i = iow.size (); i--; )
215     if (!iow[i])
216     iow.erase_unordered (i);
217     else
218     {
219     short revents = iow[i]->events;
220    
221     if (!FD_ISSET (iow[i]->fd, &rfd)) revents &= ~EVENT_READ;
222     if (!FD_ISSET (iow[i]->fd, &wfd)) revents &= ~EVENT_WRITE;
223    
224     if (revents)
225     iow[i]->call (*iow[i], revents);
226     }
227     else if (fds < 0 && errno != EINTR)
228     {
229     perror ("Error while waiting for I/O or time event");
230     abort ();
231     }
232     #if IOM_IDLE
233     else
234     for (int i = iw.size (); i--; )
235     if (!iw[i])
236     iw.erase_unordered (i);
237     else
238     iw[i]->call (*iw[i]);
239     #endif
240    
241     #elif IOM_TIME
242     if (!to)
243     break;
244 pcg 1.9
245 pcg 1.13 select (0, 0, 0, 0, &to);
246     set_now ();
247     #else
248     break;
249     #endif
250 pcg 1.1 }
251     }
252    
253     io_manager::io_manager ()
254     {
255 pcg 1.10 iom_valid = true;
256    
257 pcg 1.13 #if IOM_TIME
258 pcg 1.1 set_now ();
259 pcg 1.13
260     tw0.start (TSTAMP_MAX);
261     #endif
262 pcg 1.1 }
263    
264     io_manager::~io_manager ()
265     {
266 pcg 1.10 iom_valid = false;
267 pcg 1.1 }
268