OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_pump_libevent.h" | 5 #include "base/message_pump_libevent.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 | 9 |
10 #include "eintr_wrapper.h" | 10 #include "eintr_wrapper.h" |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 Watcher* watcher = static_cast<Watcher*>(context); | 208 Watcher* watcher = static_cast<Watcher*>(context); |
209 | 209 |
210 if (flags & EV_WRITE) { | 210 if (flags & EV_WRITE) { |
211 watcher->OnFileCanWriteWithoutBlocking(fd); | 211 watcher->OnFileCanWriteWithoutBlocking(fd); |
212 } | 212 } |
213 if (flags & EV_READ) { | 213 if (flags & EV_READ) { |
214 watcher->OnFileCanReadWithoutBlocking(fd); | 214 watcher->OnFileCanReadWithoutBlocking(fd); |
215 } | 215 } |
216 } | 216 } |
217 | 217 |
| 218 // Tell libevent to break out of inner loop. |
| 219 static void timer_callback(int fd, short events, void *context) |
| 220 { |
| 221 event_base_loopbreak((struct event_base *)context); |
| 222 } |
| 223 |
218 // Reentrant! | 224 // Reentrant! |
219 void MessagePumpLibevent::Run(Delegate* delegate) { | 225 void MessagePumpLibevent::Run(Delegate* delegate) { |
220 DCHECK(keep_running_) << "Quit must have been called outside of Run!"; | 226 DCHECK(keep_running_) << "Quit must have been called outside of Run!"; |
221 | 227 |
222 bool old_in_run = in_run_; | 228 bool old_in_run = in_run_; |
223 in_run_ = true; | 229 in_run_ = true; |
224 | 230 |
| 231 // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641. |
| 232 // Instead, make our own timer and reuse it on each call to event_base_loop(). |
| 233 scoped_ptr<event> timer_event(new event); |
| 234 |
225 for (;;) { | 235 for (;;) { |
226 ScopedNSAutoreleasePool autorelease_pool; | 236 ScopedNSAutoreleasePool autorelease_pool; |
227 | 237 |
228 bool did_work = delegate->DoWork(); | 238 bool did_work = delegate->DoWork(); |
229 if (!keep_running_) | 239 if (!keep_running_) |
230 break; | 240 break; |
231 | 241 |
232 did_work |= delegate->DoDelayedWork(&delayed_work_time_); | 242 did_work |= delegate->DoDelayedWork(&delayed_work_time_); |
233 if (!keep_running_) | 243 if (!keep_running_) |
234 break; | 244 break; |
(...skipping 11 matching lines...) Expand all Loading... |
246 // EVLOOP_ONCE tells libevent to only block once, | 256 // EVLOOP_ONCE tells libevent to only block once, |
247 // but to service all pending events when it wakes up. | 257 // but to service all pending events when it wakes up. |
248 if (delayed_work_time_.is_null()) { | 258 if (delayed_work_time_.is_null()) { |
249 event_base_loop(event_base_, EVLOOP_ONCE); | 259 event_base_loop(event_base_, EVLOOP_ONCE); |
250 } else { | 260 } else { |
251 TimeDelta delay = delayed_work_time_ - Time::Now(); | 261 TimeDelta delay = delayed_work_time_ - Time::Now(); |
252 if (delay > TimeDelta()) { | 262 if (delay > TimeDelta()) { |
253 struct timeval poll_tv; | 263 struct timeval poll_tv; |
254 poll_tv.tv_sec = delay.InSeconds(); | 264 poll_tv.tv_sec = delay.InSeconds(); |
255 poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond; | 265 poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond; |
256 event_base_loopexit(event_base_, &poll_tv); | 266 event_set(timer_event.get(), -1, 0, timer_callback, event_base_); |
| 267 event_base_set(event_base_, timer_event.get()); |
| 268 event_add(timer_event.get(), &poll_tv); |
257 event_base_loop(event_base_, EVLOOP_ONCE); | 269 event_base_loop(event_base_, EVLOOP_ONCE); |
| 270 event_del(timer_event.get()); |
258 } else { | 271 } else { |
259 // It looks like delayed_work_time_ indicates a time in the past, so we | 272 // It looks like delayed_work_time_ indicates a time in the past, so we |
260 // need to call DoDelayedWork now. | 273 // need to call DoDelayedWork now. |
261 delayed_work_time_ = Time(); | 274 delayed_work_time_ = Time(); |
262 } | 275 } |
263 } | 276 } |
264 } | 277 } |
265 | 278 |
266 keep_running_ = true; | 279 keep_running_ = true; |
267 in_run_ = old_in_run; | 280 in_run_ = old_in_run; |
(...skipping 15 matching lines...) Expand all Loading... |
283 } | 296 } |
284 | 297 |
285 void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) { | 298 void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) { |
286 // We know that we can't be blocked on Wait right now since this method can | 299 // We know that we can't be blocked on Wait right now since this method can |
287 // only be called on the same thread as Run, so we only need to update our | 300 // only be called on the same thread as Run, so we only need to update our |
288 // record of how long to sleep when we do sleep. | 301 // record of how long to sleep when we do sleep. |
289 delayed_work_time_ = delayed_work_time; | 302 delayed_work_time_ = delayed_work_time; |
290 } | 303 } |
291 | 304 |
292 } // namespace base | 305 } // namespace base |
OLD | NEW |