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