ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/iom.C
Revision: 1.14
Committed: Sat Jan 17 14:08:57 2004 UTC (20 years, 4 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +19 -16 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.13 #include <sys/select.h>
25 pcg 1.1 #include <sys/time.h>
26    
27 pcg 1.13 #include "iom.h"
28 pcg 1.11
29 pcg 1.13 // TSTAMP_MAX must still fit into a positive struct timeval
30     #define TSTAMP_MAX (double)(1UL<<31)
31 pcg 1.1
32 pcg 1.14 // 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 pcg 1.10 tstamp NOW;
51 pcg 1.13 static bool iom_valid;
52 pcg 1.10 io_manager iom;
53    
54 pcg 1.13 template<class watcher>
55     void io_manager::reg (watcher *w, io_manager_vec<watcher> &queue)
56 pcg 1.4 {
57 pcg 1.13 if (!iom_valid)
58     abort ();
59 pcg 1.4
60 pcg 1.13 if (!w->active)
61 pcg 1.11 {
62 pcg 1.13 queue.push_back (w);
63     w->active = queue.size ();
64 pcg 1.11 }
65 pcg 1.10 }
66    
67 pcg 1.13 template<class watcher>
68     void io_manager::unreg (watcher *w, io_manager_vec<watcher> &queue)
69 pcg 1.10 {
70 pcg 1.13 if (!iom_valid)
71     return;
72 pcg 1.10
73 pcg 1.13 if (w->active)
74 pcg 1.11 {
75 pcg 1.13 queue [w->active - 1] = 0;
76     w->active = 0;
77 pcg 1.11 }
78 pcg 1.1 }
79    
80 pcg 1.13 #if IOM_TIME
81     void time_watcher::trigger ()
82 pcg 1.1 {
83 pcg 1.13 call (*this);
84 pcg 1.11
85 pcg 1.13 iom.reg (this);
86 pcg 1.1 }
87    
88 pcg 1.13 void io_manager::reg (time_watcher *w) { reg (w, tw); }
89     void io_manager::unreg (time_watcher *w) { unreg (w, tw); }
90     #endif
91 pcg 1.6
92 pcg 1.13 #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 pcg 1.7
97 pcg 1.13 #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 pcg 1.1
102 pcg 1.13 #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 pcg 1.1
107 pcg 1.13 #if IOM_TIME
108 pcg 1.1 inline void set_now (void)
109     {
110     struct timeval tv;
111    
112     gettimeofday (&tv, 0);
113    
114 pcg 1.2 NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
115 pcg 1.13 #endif
116 pcg 1.1 }
117    
118     void io_manager::loop ()
119     {
120 pcg 1.13 #if IOM_TIME
121 pcg 1.1 set_now ();
122 pcg 1.13 #endif
123 pcg 1.1
124 pcg 1.4 for (;;)
125 pcg 1.1 {
126 pcg 1.13 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 pcg 1.4 {
139 pcg 1.13 #if IOM_TIME
140     time_watcher *next;
141 pcg 1.7
142 pcg 1.13 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 pcg 1.1
172 pcg 1.13 #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 pcg 1.7
183 pcg 1.13 FD_ZERO (&rfd);
184     FD_ZERO (&wfd);
185 pcg 1.7
186 pcg 1.13 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 pcg 1.1
194 pcg 1.13 if ((*i)->fd >= fds) fds = (*i)->fd + 1;
195     }
196 pcg 1.1
197 pcg 1.13 if (!to && !fds) //TODO: also check idle_watchers and check_watchers
198     break; // no events
199 pcg 1.1
200 pcg 1.13 fds = select (fds, &rfd, &wfd, &efd, to);
201     # if IOM_TIME
202 pcg 1.4 set_now ();
203 pcg 1.13 # endif
204 pcg 1.1
205 pcg 1.13 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 pcg 1.9
237 pcg 1.13 select (0, 0, 0, 0, &to);
238     set_now ();
239     #else
240     break;
241     #endif
242 pcg 1.1 }
243     }
244    
245     io_manager::io_manager ()
246     {
247 pcg 1.10 iom_valid = true;
248    
249 pcg 1.13 #if IOM_TIME
250 pcg 1.1 set_now ();
251 pcg 1.13
252     tw0.start (TSTAMP_MAX);
253 pcg 1.14 printf ("abort, %f but inly on %f\n", NOW, tw0.at);
254 pcg 1.13 #endif
255 pcg 1.1 }
256    
257     io_manager::~io_manager ()
258     {
259 pcg 1.10 iom_valid = false;
260 pcg 1.1 }
261