1 | /* |
1 | /* |
2 | iom.C -- generic I/O multiplexer |
2 | iom.C -- generic I/O multiplexer |
3 | Copyright (C) 2003, 2004 Marc Lehmann <gvpe@schmorp.de> |
3 | Copyright (C) 2003-2006 Marc Lehmann <gvpe@schmorp.de> |
4 | |
4 | |
5 | This file is part of GVPE. |
5 | This file is part of GVPE. |
6 | |
6 | |
7 | GVPE is free software; you can redistribute it and/or modify |
7 | GVPE is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
8 | it under the terms of the GNU General Public License as published by |
… | |
… | |
22 | #include "iom.h" |
22 | #include "iom.h" |
23 | |
23 | |
24 | #include <cstdio> |
24 | #include <cstdio> |
25 | #include <cstdlib> |
25 | #include <cstdlib> |
26 | #include <cerrno> |
26 | #include <cerrno> |
|
|
27 | #include <cassert> |
27 | |
28 | |
|
|
29 | #include <sys/types.h> |
28 | #include <sys/time.h> |
30 | #include <sys/time.h> |
29 | |
|
|
30 | #include <assert.h> |
|
|
31 | |
31 | |
32 | #if 1 // older unices need these includes for select (2) |
32 | #if 1 // older unices need these includes for select (2) |
33 | # include <unistd.h> |
33 | # include <unistd.h> |
34 | # include <sys/types.h> |
|
|
35 | # include <time.h> |
34 | # include <time.h> |
36 | #endif |
35 | #endif |
37 | |
36 | |
38 | // for IOM_SIG |
37 | #if IOM_CHILD |
|
|
38 | # include <sys/wait.h> |
|
|
39 | #endif |
|
|
40 | |
39 | #if IOM_SIG |
41 | #if IOM_SIG |
40 | # include <csignal> |
42 | # include <csignal> |
41 | # include <fcntl.h> |
43 | # include <fcntl.h> |
42 | #endif |
44 | #endif |
43 | |
45 | |
… | |
… | |
70 | : pending (false) |
72 | : pending (false) |
71 | { } |
73 | { } |
72 | }; |
74 | }; |
73 | static vector<sig_vec *> sw; |
75 | static vector<sig_vec *> sw; |
74 | #endif |
76 | #endif |
|
|
77 | #if IOM_CHILD |
|
|
78 | static io_manager_vec<child_watcher> pw; |
|
|
79 | #endif |
75 | |
80 | |
76 | // this is a dummy time watcher to ensure that the first |
81 | // this is a dummy time watcher to ensure that the first |
77 | // time watcher is _always_ valid, this gets rid of a lot |
82 | // time watcher is _always_ valid, this gets rid of a lot |
78 | // of null-pointer-checks |
83 | // of null-pointer-checks |
79 | // (must come _before_ iom is being defined) |
84 | // (must come _before_ iom is being defined) |
80 | static struct tw0 : time_watcher |
85 | static struct tw0 : time_watcher |
|
|
86 | { |
|
|
87 | void cb (time_watcher &w) |
81 | { |
88 | { |
82 | void cb (time_watcher &w) |
|
|
83 | { |
|
|
84 | // should never get called |
89 | // should never get called |
85 | // reached end-of-time, or tstamp has a bogus definition, |
90 | // reached end-of-time, or tstamp has a bogus definition, |
86 | // or compiler initialisation order broken, or something else :) |
91 | // or compiler initialisation order broken, or something else :) |
87 | abort (); |
92 | abort (); |
88 | } |
93 | } |
89 | |
94 | |
90 | tw0 () |
95 | tw0 () |
91 | : time_watcher (this, &tw0::cb) |
96 | : time_watcher (this, &tw0::cb) |
92 | { } |
97 | { } |
93 | } tw0; |
98 | } tw0; |
94 | |
99 | |
95 | tstamp NOW; |
100 | tstamp NOW; |
|
|
101 | |
|
|
102 | #if IOM_CHILD |
|
|
103 | // sig_watcher for child signal(s) |
|
|
104 | static struct sw0 : sig_watcher |
|
|
105 | { |
|
|
106 | void cb (sig_watcher &w) |
|
|
107 | { |
|
|
108 | // SIGCHLD, call corresponding watchera |
|
|
109 | pid_t pid; |
|
|
110 | int status; |
|
|
111 | |
|
|
112 | while ((pid = waitpid (-1, &status, WNOHANG)) > 0) |
|
|
113 | for (int i = pw.size (); i--; ) |
|
|
114 | { |
|
|
115 | child_watcher *w = pw[i]; |
|
|
116 | |
|
|
117 | if (!w) |
|
|
118 | pw.erase_unordered (i); |
|
|
119 | else if (w->pid == pid) |
|
|
120 | { |
|
|
121 | io_manager::unreg (*w); |
|
|
122 | w->call (*w, status); |
|
|
123 | } |
|
|
124 | } |
|
|
125 | |
|
|
126 | } |
|
|
127 | |
|
|
128 | sw0 () |
|
|
129 | : sig_watcher (this, &sw0::cb) |
|
|
130 | { } |
|
|
131 | } sw0; |
|
|
132 | #endif |
96 | |
133 | |
97 | #if IOM_TIME |
134 | #if IOM_TIME |
98 | tstamp io_manager::now () |
135 | tstamp io_manager::now () |
99 | { |
136 | { |
100 | struct timeval tv; |
137 | struct timeval tv; |
… | |
… | |
113 | |
150 | |
114 | // used for initialisation only |
151 | // used for initialisation only |
115 | static struct init { |
152 | static struct init { |
116 | init () |
153 | init () |
117 | { |
154 | { |
|
|
155 | iom_valid = true; |
|
|
156 | |
118 | #if IOM_SIG |
157 | #if IOM_SIG |
119 | sigemptyset (&sigs); |
158 | sigemptyset (&sigs); |
120 | |
159 | |
121 | if (pipe (sigpipe)) |
160 | if (pipe (sigpipe)) |
122 | { |
161 | { |
… | |
… | |
126 | |
165 | |
127 | fcntl (sigpipe[0], F_SETFL, O_NONBLOCK); fcntl (sigpipe[0], F_SETFD, FD_CLOEXEC); |
166 | fcntl (sigpipe[0], F_SETFL, O_NONBLOCK); fcntl (sigpipe[0], F_SETFD, FD_CLOEXEC); |
128 | fcntl (sigpipe[1], F_SETFL, O_NONBLOCK); fcntl (sigpipe[1], F_SETFD, FD_CLOEXEC); |
167 | fcntl (sigpipe[1], F_SETFL, O_NONBLOCK); fcntl (sigpipe[1], F_SETFD, FD_CLOEXEC); |
129 | #endif |
168 | #endif |
130 | |
169 | |
131 | iom_valid = true; |
170 | #if IOM_CHILD |
|
|
171 | sw0.start (SIGCHLD); |
|
|
172 | #endif |
132 | |
173 | |
133 | #if IOM_TIME |
174 | #if IOM_TIME |
134 | io_manager::set_now (); |
175 | io_manager::set_now (); |
135 | |
176 | |
136 | tw0.start (TSTAMP_MAX); |
177 | tw0.start (TSTAMP_MAX); |
… | |
… | |
219 | write (sigpipe[1], &ch, 1); |
260 | write (sigpipe[1], &ch, 1); |
220 | } |
261 | } |
221 | |
262 | |
222 | void io_manager::reg (sig_watcher &w) |
263 | void io_manager::reg (sig_watcher &w) |
223 | { |
264 | { |
|
|
265 | init::required (); |
|
|
266 | |
224 | assert (0 < w.signum); |
267 | assert (0 < w.signum); |
225 | |
268 | |
226 | sw.reserve (w.signum); |
269 | sw.reserve (w.signum); |
227 | |
270 | |
228 | while (sw.size () < w.signum) // pathetic |
271 | while (sw.size () < w.signum) // pathetic |
… | |
… | |
253 | io_manager::reg (w, *sv); |
296 | io_manager::reg (w, *sv); |
254 | } |
297 | } |
255 | |
298 | |
256 | void io_manager::unreg (sig_watcher &w) |
299 | void io_manager::unreg (sig_watcher &w) |
257 | { |
300 | { |
258 | if (!w.active) |
301 | if (!w.active || !iom_valid) |
259 | return; |
302 | return; |
260 | |
303 | |
261 | assert (0 < w.signum && w.signum <= sw.size ()); |
304 | assert (0 < w.signum && w.signum <= sw.size ()); |
262 | |
305 | |
263 | io_manager::unreg (w, *sw[w.signum - 1]); |
306 | io_manager::unreg (w, *sw[w.signum - 1]); |
… | |
… | |
267 | { |
310 | { |
268 | stop (); |
311 | stop (); |
269 | this->signum = signum; |
312 | this->signum = signum; |
270 | io_manager::reg (*this); |
313 | io_manager::reg (*this); |
271 | } |
314 | } |
|
|
315 | #endif |
|
|
316 | |
|
|
317 | #if IOM_CHILD |
|
|
318 | void io_manager::reg (child_watcher &w) { io_manager::reg (w, pw); } |
|
|
319 | void io_manager::unreg (child_watcher &w) { io_manager::unreg (w, pw); } |
272 | #endif |
320 | #endif |
273 | |
321 | |
274 | void io_manager::loop () |
322 | void io_manager::loop () |
275 | { |
323 | { |
276 | init::required (); |
324 | init::required (); |