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