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, 7 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

# Content
1 /*
2 iom.C -- generic I/O multiplexor
3 Copyright (C) 2003 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 "config.h"
21
22 #include <sys/time.h>
23
24 #include <algorithm>
25 #include <functional>
26
27 #include "gettext.h"
28
29 #include "slog.h"
30 #include "iom.h"
31
32 tstamp NOW;
33 bool iom_valid;
34 io_manager iom;
35
36 inline bool earliest_first (const time_watcher *a, const time_watcher *b)
37 {
38 return a->at > b->at;
39 }
40
41 void time_watcher::set (tstamp when)
42 {
43 at = when;
44
45 if (registered)
46 iom.reschedule_time_watchers ();
47 }
48
49 void time_watcher::trigger ()
50 {
51 call (*this);
52
53 if (registered)
54 iom.reschedule_time_watchers ();
55 else
56 iom.reg (this);
57 }
58
59 time_watcher::~time_watcher ()
60 {
61 if (iom_valid)
62 iom.unreg (this);
63 }
64
65 void io_watcher::set(int fd_, short events_)
66 {
67 fd = fd_;
68 events = events_;
69
70 if (registered)
71 {
72 iom.unreg (this);
73 iom.reg (this);
74 }
75 }
76
77 io_watcher::~io_watcher ()
78 {
79 if (iom_valid)
80 iom.unreg (this);
81 }
82
83 void io_manager::reg (io_watcher *w)
84 {
85 if (!w->registered)
86 {
87 w->registered = true;
88
89 pollfd pfd;
90
91 pfd.fd = w->fd;
92 pfd.events = w->events;
93
94 pfs.push_back (pfd);
95 iow.push_back (w);
96 }
97 }
98
99 void io_manager::unreg (io_watcher *w)
100 {
101 if (w->registered)
102 {
103 w->registered = false;
104
105 unsigned int sz = iow.size ();
106 unsigned int i = find (iow.begin (), iow.end (), w) - iow.begin ();
107
108 assert (i != sz);
109
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 void io_manager::reschedule_time_watchers ()
129 {
130 make_heap (tw.begin (), tw.end (), earliest_first);
131 }
132
133 void io_manager::reg (time_watcher *w)
134 {
135 if (!w->registered)
136 {
137 w->registered = true;
138
139 tw.push_back (w);
140 push_heap (tw.begin (), tw.end (), earliest_first);
141 }
142 }
143
144 void io_manager::unreg (time_watcher *w)
145 {
146 if (w->registered)
147 {
148 w->registered = false;
149
150 unsigned int sz = tw.size ();
151 unsigned int i = find (tw.begin (), tw.end (), w) - tw.begin ();
152
153 assert (i != sz);
154
155 if (i != sz - 1)
156 tw[i] = tw[sz - 1];
157
158 tw.pop_back ();
159 reschedule_time_watchers ();
160 }
161 }
162
163 inline void set_now (void)
164 {
165 struct timeval tv;
166
167 gettimeofday (&tv, 0);
168
169 NOW = (tstamp)tv.tv_sec + (tstamp)tv.tv_usec / 1000000;
170 }
171
172 void io_manager::loop ()
173 {
174 set_now ();
175
176 for (;;)
177 {
178 while (tw[0]->at <= NOW)
179 {
180 // remove the first watcher
181 time_watcher *w = tw[0];
182
183 pop_heap (tw.begin (), tw.end (), earliest_first);
184 tw.pop_back ();
185
186 w->registered = false;
187
188 // call it
189 w->call (*w);
190
191 // re-add it if necessary
192 if (w->at >= 0 && !w->registered)
193 reg (w);
194 }
195
196 int timeout = (int) ((tw[0]->at - NOW) * 1000);
197
198 int fds = poll (&pfs[0], pfs.size (), timeout);
199
200 set_now ();
201
202 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 {
210 --fds;
211
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 }
220 }
221 }
222
223 void io_manager::idle_cb (time_watcher &w)
224 {
225 w.at = NOW + 86400; // wake up every day, for no good reason
226 }
227
228 io_manager::io_manager ()
229 {
230 iom_valid = true;
231
232 set_now ();
233 idle = new time_watcher (this, &io_manager::idle_cb);
234 idle->start (0);
235 }
236
237 io_manager::~io_manager ()
238 {
239 iom_valid = false;
240 }
241