ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/iom.C
Revision: 1.12
Committed: Thu Oct 16 02:41:21 2003 UTC (20 years, 8 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: poll-based-iom, VPE_1_2, POLL_BASED_IOM
Changes since 1.11: +2 -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     Copyright (C) 2003 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 "config.h"
21    
22     #include <sys/time.h>
23    
24     #include <algorithm>
25     #include <functional>
26    
27 pcg 1.11 #include "gettext.h"
28    
29 pcg 1.1 #include "slog.h"
30     #include "iom.h"
31    
32 pcg 1.10 tstamp NOW;
33     bool iom_valid;
34     io_manager iom;
35    
36 pcg 1.9 inline bool earliest_first (const time_watcher *a, const time_watcher *b)
37 pcg 1.1 {
38     return a->at > b->at;
39     }
40    
41 pcg 1.2 void time_watcher::set (tstamp when)
42 pcg 1.1 {
43     at = when;
44 pcg 1.6
45     if (registered)
46     iom.reschedule_time_watchers ();
47 pcg 1.1 }
48    
49 pcg 1.4 void time_watcher::trigger ()
50     {
51 pcg 1.9 call (*this);
52 pcg 1.6
53     if (registered)
54     iom.reschedule_time_watchers ();
55     else
56     iom.reg (this);
57 pcg 1.4 }
58    
59 pcg 1.11 time_watcher::~time_watcher ()
60 pcg 1.4 {
61 pcg 1.11 if (iom_valid)
62     iom.unreg (this);
63 pcg 1.4 }
64    
65 pcg 1.11 void io_watcher::set(int fd_, short events_)
66 pcg 1.10 {
67 pcg 1.11 fd = fd_;
68     events = events_;
69    
70     if (registered)
71     {
72     iom.unreg (this);
73     iom.reg (this);
74     }
75 pcg 1.10 }
76    
77     io_watcher::~io_watcher ()
78     {
79     if (iom_valid)
80     iom.unreg (this);
81     }
82    
83 pcg 1.9 void io_manager::reg (io_watcher *w)
84 pcg 1.1 {
85 pcg 1.11 if (!w->registered)
86     {
87     w->registered = true;
88    
89     pollfd pfd;
90 pcg 1.1
91 pcg 1.11 pfd.fd = w->fd;
92     pfd.events = w->events;
93 pcg 1.10
94 pcg 1.11 pfs.push_back (pfd);
95     iow.push_back (w);
96     }
97 pcg 1.1 }
98    
99 pcg 1.7 void io_manager::unreg (io_watcher *w)
100 pcg 1.1 {
101 pcg 1.11 if (w->registered)
102 pcg 1.10 {
103 pcg 1.11 w->registered = false;
104    
105 pcg 1.10 unsigned int sz = iow.size ();
106     unsigned int i = find (iow.begin (), iow.end (), w) - iow.begin ();
107    
108     assert (i != sz);
109 pcg 1.1
110     if (sz == 1)
111     {
112     pfs.clear ();
113     iow.clear ();
114     }
115     else if (i == sz - 1)
116     {
117     iow.pop_back ();
118     pfs.pop_back ();
119     }
120     else
121     {
122     iow[i] = iow[sz - 1]; iow.pop_back ();
123     pfs[i] = pfs[sz - 1]; pfs.pop_back ();
124     }
125     }
126     }
127    
128 pcg 1.6 void io_manager::reschedule_time_watchers ()
129     {
130 pcg 1.9 make_heap (tw.begin (), tw.end (), earliest_first);
131 pcg 1.6 }
132    
133 pcg 1.1 void io_manager::reg (time_watcher *w)
134     {
135 pcg 1.11 if (!w->registered)
136     {
137     w->registered = true;
138 pcg 1.7
139 pcg 1.11 tw.push_back (w);
140     push_heap (tw.begin (), tw.end (), earliest_first);
141     }
142 pcg 1.1 }
143    
144 pcg 1.7 void io_manager::unreg (time_watcher *w)
145 pcg 1.1 {
146 pcg 1.7 if (w->registered)
147     {
148 pcg 1.11 w->registered = false;
149    
150 pcg 1.7 unsigned int sz = tw.size ();
151     unsigned int i = find (tw.begin (), tw.end (), w) - tw.begin ();
152 pcg 1.1
153 pcg 1.10 assert (i != sz);
154    
155     if (i != sz - 1)
156     tw[i] = tw[sz - 1];
157 pcg 1.7
158 pcg 1.10 tw.pop_back ();
159     reschedule_time_watchers ();
160 pcg 1.1 }
161     }
162    
163     inline void set_now (void)
164     {
165     struct timeval tv;
166    
167     gettimeofday (&tv, 0);
168    
169 pcg 1.2 NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
170 pcg 1.1 }
171    
172     void io_manager::loop ()
173     {
174     set_now ();
175    
176 pcg 1.4 for (;;)
177 pcg 1.1 {
178 pcg 1.4 while (tw[0]->at <= NOW)
179     {
180 pcg 1.7 // remove the first watcher
181     time_watcher *w = tw[0];
182    
183 pcg 1.9 pop_heap (tw.begin (), tw.end (), earliest_first);
184 pcg 1.6 tw.pop_back ();
185 pcg 1.1
186 pcg 1.7 w->registered = false;
187    
188     // call it
189 pcg 1.9 w->call (*w);
190 pcg 1.7
191     // re-add it if necessary
192     if (w->at >= 0 && !w->registered)
193     reg (w);
194 pcg 1.4 }
195 pcg 1.1
196 pcg 1.4 int timeout = (int) ((tw[0]->at - NOW) * 1000);
197 pcg 1.1
198 pcg 1.4 int fds = poll (&pfs[0], pfs.size (), timeout);
199 pcg 1.1
200 pcg 1.4 set_now ();
201 pcg 1.1
202 pcg 1.9 vector<io_watcher *>::iterator w;
203     vector<pollfd>::iterator p;
204    
205     for (w = iow.begin (), p = pfs.begin ();
206     fds > 0 && w < iow.end ();
207     ++w, ++p)
208     if (p->revents)
209 pcg 1.4 {
210     --fds;
211 pcg 1.11
212     if (p->revents & POLLNVAL)
213     {
214     slog (L_ERR, _("io_watcher started on illegal file descriptor, disabling."));
215     (*w)->stop ();
216     }
217     else
218     (*w)->call (**w, p->revents);
219 pcg 1.4 }
220 pcg 1.1 }
221     }
222    
223 pcg 1.9 void io_manager::idle_cb (time_watcher &w)
224 pcg 1.4 {
225 pcg 1.9 w.at = NOW + 86400; // wake up every day, for no good reason
226 pcg 1.4 }
227    
228 pcg 1.1 io_manager::io_manager ()
229     {
230 pcg 1.10 iom_valid = true;
231    
232 pcg 1.1 set_now ();
233 pcg 1.4 idle = new time_watcher (this, &io_manager::idle_cb);
234     idle->start (0);
235 pcg 1.1 }
236    
237     io_manager::~io_manager ()
238     {
239 pcg 1.10 iom_valid = false;
240 pcg 1.1 }
241