]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
10a89ef0 | 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
064af421 | 7 | * |
a14bc59f BP |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include "poll-loop.h" | |
064af421 | 19 | #include <errno.h> |
2886875a | 20 | #include <inttypes.h> |
064af421 BP |
21 | #include <poll.h> |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
064af421 BP |
24 | #include "coverage.h" |
25 | #include "dynamic-string.h" | |
d8b30702 | 26 | #include "fatal-signal.h" |
064af421 | 27 | #include "list.h" |
2c06a966 | 28 | #include "ovs-thread.h" |
f89ffb0e | 29 | #include "socket-util.h" |
064af421 | 30 | #include "timeval.h" |
064af421 BP |
31 | #include "vlog.h" |
32 | ||
f89ffb0e BP |
33 | #undef poll_fd_wait |
34 | #undef poll_timer_wait | |
35 | #undef poll_timer_wait_until | |
36 | #undef poll_immediate_wake | |
37 | ||
d98e6007 | 38 | VLOG_DEFINE_THIS_MODULE(poll_loop); |
5136ce49 | 39 | |
d76f09ea BP |
40 | COVERAGE_DEFINE(poll_fd_wait); |
41 | COVERAGE_DEFINE(poll_zero_timeout); | |
42 | ||
2c06a966 BP |
43 | struct poll_loop { |
44 | /* All active poll waiters. */ | |
45 | struct pollfd *pollfds; /* Events to pass to poll(). */ | |
46 | const char **where; /* Where each pollfd was created. */ | |
47 | size_t n_waiters; /* Number of elems in 'where' and 'pollfds'. */ | |
48 | size_t allocated_waiters; /* Allocated elems in 'where' and 'pollfds'. */ | |
064af421 | 49 | |
2c06a966 BP |
50 | /* Time at which to wake up the next call to poll_block(), LLONG_MIN to |
51 | * wake up immediately, or LLONG_MAX to wait forever. */ | |
52 | long long int timeout_when; /* In msecs as returned by time_msec(). */ | |
53 | const char *timeout_where; /* Where 'timeout_when' was set. */ | |
54 | }; | |
064af421 | 55 | |
2c06a966 | 56 | static struct poll_loop *poll_loop(void); |
064af421 BP |
57 | |
58 | /* Registers 'fd' as waiting for the specified 'events' (which should be POLLIN | |
59 | * or POLLOUT or POLLIN | POLLOUT). The following call to poll_block() will | |
60 | * wake up when 'fd' becomes ready for one or more of the requested events. | |
61 | * | |
62 | * The event registration is one-shot: only the following call to poll_block() | |
63 | * is affected. The event will need to be re-registered after poll_block() is | |
f89ffb0e BP |
64 | * called if it is to persist. |
65 | * | |
66 | * Ordinarily the 'where' argument is supplied automatically; see poll-loop.h | |
67 | * for more information. */ | |
8f6c3ad7 | 68 | void |
f89ffb0e | 69 | poll_fd_wait(int fd, short int events, const char *where) |
064af421 | 70 | { |
2c06a966 BP |
71 | struct poll_loop *loop = poll_loop(); |
72 | ||
064af421 | 73 | COVERAGE_INC(poll_fd_wait); |
2c06a966 BP |
74 | if (loop->n_waiters >= loop->allocated_waiters) { |
75 | loop->where = x2nrealloc(loop->where, &loop->allocated_waiters, | |
76 | sizeof *loop->where); | |
77 | loop->pollfds = xrealloc(loop->pollfds, | |
78 | (loop->allocated_waiters | |
79 | * sizeof *loop->pollfds)); | |
80 | } | |
81 | ||
82 | loop->where[loop->n_waiters] = where; | |
83 | loop->pollfds[loop->n_waiters].fd = fd; | |
84 | loop->pollfds[loop->n_waiters].events = events; | |
85 | loop->n_waiters++; | |
064af421 BP |
86 | } |
87 | ||
88 | /* Causes the following call to poll_block() to block for no more than 'msec' | |
89 | * milliseconds. If 'msec' is nonpositive, the following call to poll_block() | |
90 | * will not block at all. | |
91 | * | |
92 | * The timer registration is one-shot: only the following call to poll_block() | |
93 | * is affected. The timer will need to be re-registered after poll_block() is | |
f89ffb0e BP |
94 | * called if it is to persist. |
95 | * | |
96 | * Ordinarily the 'where' argument is supplied automatically; see poll-loop.h | |
97 | * for more information. */ | |
064af421 | 98 | void |
f89ffb0e | 99 | poll_timer_wait(long long int msec, const char *where) |
064af421 | 100 | { |
cee03df4 BP |
101 | long long int now = time_msec(); |
102 | long long int when; | |
103 | ||
104 | if (msec <= 0) { | |
105 | /* Wake up immediately. */ | |
106 | when = LLONG_MIN; | |
107 | } else if ((unsigned long long int) now + msec <= LLONG_MAX) { | |
108 | /* Normal case. */ | |
109 | when = now + msec; | |
110 | } else { | |
111 | /* now + msec would overflow. */ | |
112 | when = LLONG_MAX; | |
113 | } | |
114 | ||
115 | poll_timer_wait_until(when, where); | |
064af421 BP |
116 | } |
117 | ||
7cf8b266 | 118 | /* Causes the following call to poll_block() to wake up when the current time, |
cee03df4 | 119 | * as returned by time_msec(), reaches 'when' or later. If 'when' is earlier |
7cf8b266 BP |
120 | * than the current time, the following call to poll_block() will not block at |
121 | * all. | |
122 | * | |
123 | * The timer registration is one-shot: only the following call to poll_block() | |
124 | * is affected. The timer will need to be re-registered after poll_block() is | |
f89ffb0e BP |
125 | * called if it is to persist. |
126 | * | |
127 | * Ordinarily the 'where' argument is supplied automatically; see poll-loop.h | |
128 | * for more information. */ | |
7cf8b266 | 129 | void |
cee03df4 | 130 | poll_timer_wait_until(long long int when, const char *where) |
7cf8b266 | 131 | { |
2c06a966 BP |
132 | struct poll_loop *loop = poll_loop(); |
133 | if (when < loop->timeout_when) { | |
134 | loop->timeout_when = when; | |
135 | loop->timeout_where = where; | |
cee03df4 | 136 | } |
7cf8b266 BP |
137 | } |
138 | ||
064af421 | 139 | /* Causes the following call to poll_block() to wake up immediately, without |
f89ffb0e BP |
140 | * blocking. |
141 | * | |
142 | * Ordinarily the 'where' argument is supplied automatically; see poll-loop.h | |
143 | * for more information. */ | |
064af421 | 144 | void |
f89ffb0e | 145 | poll_immediate_wake(const char *where) |
064af421 | 146 | { |
f89ffb0e | 147 | poll_timer_wait(0, where); |
064af421 BP |
148 | } |
149 | ||
959ec62e BP |
150 | /* Logs, if appropriate, that the poll loop was awakened by an event |
151 | * registered at 'where' (typically a source file and line number). The other | |
152 | * arguments have two possible interpretations: | |
153 | * | |
154 | * - If 'pollfd' is nonnull then it should be the "struct pollfd" that caused | |
d19cedb2 | 155 | * the wakeup. 'timeout' is ignored. |
959ec62e | 156 | * |
d19cedb2 BP |
157 | * - If 'pollfd' is NULL then 'timeout' is the number of milliseconds after |
158 | * which the poll loop woke up. | |
959ec62e BP |
159 | */ |
160 | static void | |
161 | log_wakeup(const char *where, const struct pollfd *pollfd, int timeout) | |
064af421 | 162 | { |
cf1b8a92 | 163 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10); |
959ec62e BP |
164 | enum vlog_level level; |
165 | int cpu_usage; | |
166 | struct ds s; | |
064af421 | 167 | |
959ec62e BP |
168 | cpu_usage = get_cpu_usage(); |
169 | if (VLOG_IS_DBG_ENABLED()) { | |
170 | level = VLL_DBG; | |
692bf61a BP |
171 | } else if (cpu_usage > 50 && !VLOG_DROP_INFO(&rl)) { |
172 | level = VLL_INFO; | |
959ec62e BP |
173 | } else { |
174 | return; | |
175 | } | |
064af421 | 176 | |
959ec62e BP |
177 | ds_init(&s); |
178 | ds_put_cstr(&s, "wakeup due to "); | |
179 | if (pollfd) { | |
180 | char *description = describe_fd(pollfd->fd); | |
181 | if (pollfd->revents & POLLIN) { | |
182 | ds_put_cstr(&s, "[POLLIN]"); | |
183 | } | |
184 | if (pollfd->revents & POLLOUT) { | |
185 | ds_put_cstr(&s, "[POLLOUT]"); | |
186 | } | |
187 | if (pollfd->revents & POLLERR) { | |
188 | ds_put_cstr(&s, "[POLLERR]"); | |
189 | } | |
190 | if (pollfd->revents & POLLHUP) { | |
191 | ds_put_cstr(&s, "[POLLHUP]"); | |
192 | } | |
193 | if (pollfd->revents & POLLNVAL) { | |
194 | ds_put_cstr(&s, "[POLLNVAL]"); | |
195 | } | |
196 | ds_put_format(&s, " on fd %d (%s)", pollfd->fd, description); | |
197 | free(description); | |
198 | } else { | |
199 | ds_put_format(&s, "%d-ms timeout", timeout); | |
200 | } | |
f89ffb0e | 201 | if (where) { |
959ec62e | 202 | ds_put_format(&s, " at %s", where); |
064af421 | 203 | } |
959ec62e BP |
204 | if (cpu_usage >= 0) { |
205 | ds_put_format(&s, " (%d%% CPU usage)", cpu_usage); | |
206 | } | |
207 | VLOG(level, "%s", ds_cstr(&s)); | |
208 | ds_destroy(&s); | |
064af421 BP |
209 | } |
210 | ||
211 | /* Blocks until one or more of the events registered with poll_fd_wait() | |
212 | * occurs, or until the minimum duration registered with poll_timer_wait() | |
d474bd01 | 213 | * elapses, or not at all if poll_immediate_wake() has been called. */ |
064af421 BP |
214 | void |
215 | poll_block(void) | |
216 | { | |
2c06a966 | 217 | struct poll_loop *loop = poll_loop(); |
cee03df4 | 218 | int elapsed; |
064af421 BP |
219 | int retval; |
220 | ||
d8b30702 JG |
221 | /* Register fatal signal events before actually doing any real work for |
222 | * poll_block. */ | |
223 | fatal_signal_wait(); | |
224 | ||
2c06a966 | 225 | if (loop->timeout_when == LLONG_MIN) { |
064af421 BP |
226 | COVERAGE_INC(poll_zero_timeout); |
227 | } | |
2c06a966 BP |
228 | |
229 | retval = time_poll(loop->pollfds, loop->n_waiters, | |
230 | loop->timeout_when, &elapsed); | |
064af421 BP |
231 | if (retval < 0) { |
232 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
10a89ef0 | 233 | VLOG_ERR_RL(&rl, "poll: %s", ovs_strerror(-retval)); |
959ec62e | 234 | } else if (!retval) { |
2c06a966 | 235 | log_wakeup(loop->timeout_where, NULL, elapsed); |
8f6c3ad7 BP |
236 | } else if (get_cpu_usage() > 50 || VLOG_IS_DBG_ENABLED()) { |
237 | size_t i; | |
064af421 | 238 | |
2c06a966 BP |
239 | for (i = 0; i < loop->n_waiters; i++) { |
240 | if (loop->pollfds[i].revents) { | |
241 | log_wakeup(loop->where[i], &loop->pollfds[i], 0); | |
8f6c3ad7 | 242 | } |
064af421 | 243 | } |
064af421 BP |
244 | } |
245 | ||
2c06a966 BP |
246 | loop->timeout_when = LLONG_MAX; |
247 | loop->timeout_where = NULL; | |
248 | loop->n_waiters = 0; | |
d8b30702 JG |
249 | |
250 | /* Handle any pending signals before doing anything else. */ | |
251 | fatal_signal_run(); | |
064af421 | 252 | } |
064af421 | 253 | \f |
8f6c3ad7 | 254 | static void |
2c06a966 | 255 | free_poll_loop(void *loop_) |
064af421 | 256 | { |
2c06a966 BP |
257 | struct poll_loop *loop = loop_; |
258 | ||
259 | free(loop->pollfds); | |
260 | free(loop->where); | |
261 | free(loop); | |
262 | } | |
263 | ||
264 | static struct poll_loop * | |
265 | poll_loop(void) | |
266 | { | |
267 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; | |
268 | static pthread_key_t key; | |
269 | struct poll_loop *loop; | |
270 | ||
271 | if (ovsthread_once_start(&once)) { | |
272 | xpthread_key_create(&key, free_poll_loop); | |
273 | ovsthread_once_done(&once); | |
8f6c3ad7 BP |
274 | } |
275 | ||
2c06a966 BP |
276 | loop = pthread_getspecific(key); |
277 | if (!loop) { | |
278 | loop = xzalloc(sizeof *loop); | |
279 | pthread_setspecific(key, loop); | |
280 | } | |
281 | return loop; | |
064af421 | 282 | } |
2c06a966 | 283 |