1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/message_loop.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,593 @@ 1.4 +// Copyright (c) 2009 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/message_loop.h" 1.9 + 1.10 +#include <algorithm> 1.11 + 1.12 +#include "mozilla/Atomics.h" 1.13 +#include "base/compiler_specific.h" 1.14 +#include "base/lazy_instance.h" 1.15 +#include "base/logging.h" 1.16 +#include "base/message_pump_default.h" 1.17 +#include "base/string_util.h" 1.18 +#include "base/thread_local.h" 1.19 + 1.20 +#if defined(OS_MACOSX) 1.21 +#include "base/message_pump_mac.h" 1.22 +#endif 1.23 +#if defined(OS_POSIX) 1.24 +#include "base/message_pump_libevent.h" 1.25 +#endif 1.26 +#if defined(OS_LINUX) || defined(OS_BSD) 1.27 +#if defined(MOZ_WIDGET_GTK) 1.28 +#include "base/message_pump_glib.h" 1.29 +#endif 1.30 +#ifdef MOZ_WIDGET_QT 1.31 +#include "base/message_pump_qt.h" 1.32 +#endif 1.33 +#endif 1.34 +#ifdef ANDROID 1.35 +#include "base/message_pump_android.h" 1.36 +#endif 1.37 +#ifdef MOZ_TASK_TRACER 1.38 +#include "GeckoTaskTracer.h" 1.39 +#endif 1.40 + 1.41 +#include "MessagePump.h" 1.42 + 1.43 +using base::Time; 1.44 +using base::TimeDelta; 1.45 +using base::TimeTicks; 1.46 + 1.47 +// A lazily created thread local storage for quick access to a thread's message 1.48 +// loop, if one exists. This should be safe and free of static constructors. 1.49 +static base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr( 1.50 + base::LINKER_INITIALIZED); 1.51 + 1.52 +//------------------------------------------------------------------------------ 1.53 + 1.54 +// Logical events for Histogram profiling. Run with -message-loop-histogrammer 1.55 +// to get an accounting of messages and actions taken on each thread. 1.56 +static const int kTaskRunEvent = 0x1; 1.57 +static const int kTimerEvent = 0x2; 1.58 + 1.59 +// Provide range of message IDs for use in histogramming and debug display. 1.60 +static const int kLeastNonZeroMessageId = 1; 1.61 +static const int kMaxMessageId = 1099; 1.62 +static const int kNumberOfDistinctMessagesDisplayed = 1100; 1.63 + 1.64 +//------------------------------------------------------------------------------ 1.65 + 1.66 +#if defined(OS_WIN) 1.67 + 1.68 +// Upon a SEH exception in this thread, it restores the original unhandled 1.69 +// exception filter. 1.70 +static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 1.71 + ::SetUnhandledExceptionFilter(old_filter); 1.72 + return EXCEPTION_CONTINUE_SEARCH; 1.73 +} 1.74 + 1.75 +// Retrieves a pointer to the current unhandled exception filter. There 1.76 +// is no standalone getter method. 1.77 +static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { 1.78 + LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; 1.79 + top_filter = ::SetUnhandledExceptionFilter(0); 1.80 + ::SetUnhandledExceptionFilter(top_filter); 1.81 + return top_filter; 1.82 +} 1.83 + 1.84 +#endif // defined(OS_WIN) 1.85 + 1.86 +//------------------------------------------------------------------------------ 1.87 + 1.88 +// static 1.89 +MessageLoop* MessageLoop::current() { 1.90 + // TODO(darin): sadly, we cannot enable this yet since people call us even 1.91 + // when they have no intention of using us. 1.92 + //DCHECK(loop) << "Ouch, did you forget to initialize me?"; 1.93 + return lazy_tls_ptr.Pointer()->Get(); 1.94 +} 1.95 + 1.96 +static mozilla::Atomic<int32_t> message_loop_id_seq(0); 1.97 + 1.98 +MessageLoop::MessageLoop(Type type) 1.99 + : type_(type), 1.100 + id_(++message_loop_id_seq), 1.101 + nestable_tasks_allowed_(true), 1.102 + exception_restoration_(false), 1.103 + state_(NULL), 1.104 + run_depth_base_(1), 1.105 +#ifdef OS_WIN 1.106 + os_modal_loop_(false), 1.107 +#endif // OS_WIN 1.108 + transient_hang_timeout_(0), 1.109 + permanent_hang_timeout_(0), 1.110 + next_sequence_num_(0) { 1.111 + DCHECK(!current()) << "should only have one message loop per thread"; 1.112 + lazy_tls_ptr.Pointer()->Set(this); 1.113 + if (type_ == TYPE_MOZILLA_UI) { 1.114 + pump_ = new mozilla::ipc::MessagePump(); 1.115 + return; 1.116 + } 1.117 + if (type_ == TYPE_MOZILLA_CHILD) { 1.118 + pump_ = new mozilla::ipc::MessagePumpForChildProcess(); 1.119 + // There is a MessageLoop Run call from XRE_InitChildProcess 1.120 + // and another one from MessagePumpForChildProcess. The one 1.121 + // from MessagePumpForChildProcess becomes the base, so we need 1.122 + // to set run_depth_base_ to 2 or we'll never be able to process 1.123 + // Idle tasks. 1.124 + run_depth_base_ = 2; 1.125 + return; 1.126 + } 1.127 + if (type_ == TYPE_MOZILLA_NONMAINTHREAD) { 1.128 + pump_ = new mozilla::ipc::MessagePumpForNonMainThreads(); 1.129 + return; 1.130 + } 1.131 + 1.132 +#if defined(OS_WIN) 1.133 + // TODO(rvargas): Get rid of the OS guards. 1.134 + if (type_ == TYPE_DEFAULT) { 1.135 + pump_ = new base::MessagePumpDefault(); 1.136 + } else if (type_ == TYPE_IO) { 1.137 + pump_ = new base::MessagePumpForIO(); 1.138 + } else { 1.139 + DCHECK(type_ == TYPE_UI); 1.140 + pump_ = new base::MessagePumpForUI(); 1.141 + } 1.142 +#elif defined(OS_POSIX) 1.143 + if (type_ == TYPE_UI) { 1.144 +#if defined(OS_MACOSX) 1.145 + pump_ = base::MessagePumpMac::Create(); 1.146 +#elif defined(OS_LINUX) || defined(OS_BSD) 1.147 + pump_ = new base::MessagePumpForUI(); 1.148 +#endif // OS_LINUX 1.149 + } else if (type_ == TYPE_IO) { 1.150 + pump_ = new base::MessagePumpLibevent(); 1.151 + } else { 1.152 + pump_ = new base::MessagePumpDefault(); 1.153 + } 1.154 +#endif // OS_POSIX 1.155 +} 1.156 + 1.157 +MessageLoop::~MessageLoop() { 1.158 + DCHECK(this == current()); 1.159 + 1.160 + // Let interested parties have one last shot at accessing this. 1.161 + FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 1.162 + WillDestroyCurrentMessageLoop()); 1.163 + 1.164 + DCHECK(!state_); 1.165 + 1.166 + // Clean up any unprocessed tasks, but take care: deleting a task could 1.167 + // result in the addition of more tasks (e.g., via DeleteSoon). We set a 1.168 + // limit on the number of times we will allow a deleted task to generate more 1.169 + // tasks. Normally, we should only pass through this loop once or twice. If 1.170 + // we end up hitting the loop limit, then it is probably due to one task that 1.171 + // is being stubborn. Inspect the queues to see who is left. 1.172 + bool did_work; 1.173 + for (int i = 0; i < 100; ++i) { 1.174 + DeletePendingTasks(); 1.175 + ReloadWorkQueue(); 1.176 + // If we end up with empty queues, then break out of the loop. 1.177 + did_work = DeletePendingTasks(); 1.178 + if (!did_work) 1.179 + break; 1.180 + } 1.181 + DCHECK(!did_work); 1.182 + 1.183 + // OK, now make it so that no one can find us. 1.184 + lazy_tls_ptr.Pointer()->Set(NULL); 1.185 +} 1.186 + 1.187 +void MessageLoop::AddDestructionObserver(DestructionObserver *obs) { 1.188 + DCHECK(this == current()); 1.189 + destruction_observers_.AddObserver(obs); 1.190 +} 1.191 + 1.192 +void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) { 1.193 + DCHECK(this == current()); 1.194 + destruction_observers_.RemoveObserver(obs); 1.195 +} 1.196 + 1.197 +void MessageLoop::Run() { 1.198 + AutoRunState save_state(this); 1.199 + RunHandler(); 1.200 +} 1.201 + 1.202 +void MessageLoop::RunAllPending() { 1.203 + AutoRunState save_state(this); 1.204 + state_->quit_received = true; // Means run until we would otherwise block. 1.205 + RunHandler(); 1.206 +} 1.207 + 1.208 +// Runs the loop in two different SEH modes: 1.209 +// enable_SEH_restoration_ = false : any unhandled exception goes to the last 1.210 +// one that calls SetUnhandledExceptionFilter(). 1.211 +// enable_SEH_restoration_ = true : any unhandled exception goes to the filter 1.212 +// that was existed before the loop was run. 1.213 +void MessageLoop::RunHandler() { 1.214 +#if defined(OS_WIN) 1.215 + if (exception_restoration_) { 1.216 + LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); 1.217 + MOZ_SEH_TRY { 1.218 + RunInternal(); 1.219 + } MOZ_SEH_EXCEPT(SEHFilter(current_filter)) { 1.220 + } 1.221 + return; 1.222 + } 1.223 +#endif 1.224 + 1.225 + RunInternal(); 1.226 +} 1.227 + 1.228 +//------------------------------------------------------------------------------ 1.229 + 1.230 +void MessageLoop::RunInternal() { 1.231 + DCHECK(this == current()); 1.232 + pump_->Run(this); 1.233 +} 1.234 + 1.235 +//------------------------------------------------------------------------------ 1.236 +// Wrapper functions for use in above message loop framework. 1.237 + 1.238 +bool MessageLoop::ProcessNextDelayedNonNestableTask() { 1.239 + if (state_->run_depth > run_depth_base_) 1.240 + return false; 1.241 + 1.242 + if (deferred_non_nestable_work_queue_.empty()) 1.243 + return false; 1.244 + 1.245 + Task* task = deferred_non_nestable_work_queue_.front().task; 1.246 + deferred_non_nestable_work_queue_.pop(); 1.247 + 1.248 + RunTask(task); 1.249 + return true; 1.250 +} 1.251 + 1.252 +//------------------------------------------------------------------------------ 1.253 + 1.254 +void MessageLoop::Quit() { 1.255 + DCHECK(current() == this); 1.256 + if (state_) { 1.257 + state_->quit_received = true; 1.258 + } else { 1.259 + NOTREACHED() << "Must be inside Run to call Quit"; 1.260 + } 1.261 +} 1.262 + 1.263 +void MessageLoop::PostTask( 1.264 + const tracked_objects::Location& from_here, Task* task) { 1.265 + PostTask_Helper(from_here, task, 0, true); 1.266 +} 1.267 + 1.268 +void MessageLoop::PostDelayedTask( 1.269 + const tracked_objects::Location& from_here, Task* task, int delay_ms) { 1.270 + PostTask_Helper(from_here, task, delay_ms, true); 1.271 +} 1.272 + 1.273 +void MessageLoop::PostNonNestableTask( 1.274 + const tracked_objects::Location& from_here, Task* task) { 1.275 + PostTask_Helper(from_here, task, 0, false); 1.276 +} 1.277 + 1.278 +void MessageLoop::PostNonNestableDelayedTask( 1.279 + const tracked_objects::Location& from_here, Task* task, int delay_ms) { 1.280 + PostTask_Helper(from_here, task, delay_ms, false); 1.281 +} 1.282 + 1.283 +void MessageLoop::PostIdleTask( 1.284 + const tracked_objects::Location& from_here, Task* task) { 1.285 + DCHECK(current() == this); 1.286 + 1.287 +#ifdef MOZ_TASK_TRACER 1.288 + task = mozilla::tasktracer::CreateTracedTask(task); 1.289 +#endif 1.290 + 1.291 + task->SetBirthPlace(from_here); 1.292 + PendingTask pending_task(task, false); 1.293 + deferred_non_nestable_work_queue_.push(pending_task); 1.294 +} 1.295 + 1.296 +// Possibly called on a background thread! 1.297 +void MessageLoop::PostTask_Helper( 1.298 + const tracked_objects::Location& from_here, Task* task, int delay_ms, 1.299 + bool nestable) { 1.300 + 1.301 +#ifdef MOZ_TASK_TRACER 1.302 + task = mozilla::tasktracer::CreateTracedTask(task); 1.303 +#endif 1.304 + 1.305 + task->SetBirthPlace(from_here); 1.306 + 1.307 + PendingTask pending_task(task, nestable); 1.308 + 1.309 + if (delay_ms > 0) { 1.310 + pending_task.delayed_run_time = 1.311 + TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms); 1.312 + } else { 1.313 + DCHECK(delay_ms == 0) << "delay should not be negative"; 1.314 + } 1.315 + 1.316 + // Warning: Don't try to short-circuit, and handle this thread's tasks more 1.317 + // directly, as it could starve handling of foreign threads. Put every task 1.318 + // into this queue. 1.319 + 1.320 + scoped_refptr<base::MessagePump> pump; 1.321 + { 1.322 + AutoLock locked(incoming_queue_lock_); 1.323 + incoming_queue_.push(pending_task); 1.324 + pump = pump_; 1.325 + } 1.326 + // Since the incoming_queue_ may contain a task that destroys this message 1.327 + // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 1.328 + // We use a stack-based reference to the message pump so that we can call 1.329 + // ScheduleWork outside of incoming_queue_lock_. 1.330 + 1.331 + pump->ScheduleWork(); 1.332 +} 1.333 + 1.334 +void MessageLoop::SetNestableTasksAllowed(bool allowed) { 1.335 + if (nestable_tasks_allowed_ != allowed) { 1.336 + nestable_tasks_allowed_ = allowed; 1.337 + if (!nestable_tasks_allowed_) 1.338 + return; 1.339 + // Start the native pump if we are not already pumping. 1.340 + pump_->ScheduleWorkForNestedLoop(); 1.341 + } 1.342 +} 1.343 + 1.344 +void MessageLoop::ScheduleWork() { 1.345 + // Start the native pump if we are not already pumping. 1.346 + pump_->ScheduleWork(); 1.347 +} 1.348 + 1.349 +bool MessageLoop::NestableTasksAllowed() const { 1.350 + return nestable_tasks_allowed_; 1.351 +} 1.352 + 1.353 +//------------------------------------------------------------------------------ 1.354 + 1.355 +void MessageLoop::RunTask(Task* task) { 1.356 + DCHECK(nestable_tasks_allowed_); 1.357 + // Execute the task and assume the worst: It is probably not reentrant. 1.358 + nestable_tasks_allowed_ = false; 1.359 + 1.360 + task->Run(); 1.361 + delete task; 1.362 + 1.363 + nestable_tasks_allowed_ = true; 1.364 +} 1.365 + 1.366 +bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 1.367 + if (pending_task.nestable || state_->run_depth <= run_depth_base_) { 1.368 + RunTask(pending_task.task); 1.369 + // Show that we ran a task (Note: a new one might arrive as a 1.370 + // consequence!). 1.371 + return true; 1.372 + } 1.373 + 1.374 + // We couldn't run the task now because we're in a nested message loop 1.375 + // and the task isn't nestable. 1.376 + deferred_non_nestable_work_queue_.push(pending_task); 1.377 + return false; 1.378 +} 1.379 + 1.380 +void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 1.381 + // Move to the delayed work queue. Initialize the sequence number 1.382 + // before inserting into the delayed_work_queue_. The sequence number 1.383 + // is used to faciliate FIFO sorting when two tasks have the same 1.384 + // delayed_run_time value. 1.385 + PendingTask new_pending_task(pending_task); 1.386 + new_pending_task.sequence_num = next_sequence_num_++; 1.387 + delayed_work_queue_.push(new_pending_task); 1.388 +} 1.389 + 1.390 +void MessageLoop::ReloadWorkQueue() { 1.391 + // We can improve performance of our loading tasks from incoming_queue_ to 1.392 + // work_queue_ by waiting until the last minute (work_queue_ is empty) to 1.393 + // load. That reduces the number of locks-per-task significantly when our 1.394 + // queues get large. 1.395 + if (!work_queue_.empty()) 1.396 + return; // Wait till we *really* need to lock and load. 1.397 + 1.398 + // Acquire all we can from the inter-thread queue with one lock acquisition. 1.399 + { 1.400 + AutoLock lock(incoming_queue_lock_); 1.401 + if (incoming_queue_.empty()) 1.402 + return; 1.403 + std::swap(incoming_queue_, work_queue_); 1.404 + DCHECK(incoming_queue_.empty()); 1.405 + } 1.406 +} 1.407 + 1.408 +bool MessageLoop::DeletePendingTasks() { 1.409 + MOZ_ASSERT(work_queue_.empty()); 1.410 + bool did_work = !deferred_non_nestable_work_queue_.empty(); 1.411 + while (!deferred_non_nestable_work_queue_.empty()) { 1.412 + Task* task = deferred_non_nestable_work_queue_.front().task; 1.413 + deferred_non_nestable_work_queue_.pop(); 1.414 + delete task; 1.415 + } 1.416 + did_work |= !delayed_work_queue_.empty(); 1.417 + while (!delayed_work_queue_.empty()) { 1.418 + Task* task = delayed_work_queue_.top().task; 1.419 + delayed_work_queue_.pop(); 1.420 + delete task; 1.421 + } 1.422 + return did_work; 1.423 +} 1.424 + 1.425 +bool MessageLoop::DoWork() { 1.426 + if (!nestable_tasks_allowed_) { 1.427 + // Task can't be executed right now. 1.428 + return false; 1.429 + } 1.430 + 1.431 + for (;;) { 1.432 + ReloadWorkQueue(); 1.433 + if (work_queue_.empty()) 1.434 + break; 1.435 + 1.436 + // Execute oldest task. 1.437 + do { 1.438 + PendingTask pending_task = work_queue_.front(); 1.439 + work_queue_.pop(); 1.440 + if (!pending_task.delayed_run_time.is_null()) { 1.441 + AddToDelayedWorkQueue(pending_task); 1.442 + // If we changed the topmost task, then it is time to re-schedule. 1.443 + if (delayed_work_queue_.top().task == pending_task.task) 1.444 + pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 1.445 + } else { 1.446 + if (DeferOrRunPendingTask(pending_task)) 1.447 + return true; 1.448 + } 1.449 + } while (!work_queue_.empty()); 1.450 + } 1.451 + 1.452 + // Nothing happened. 1.453 + return false; 1.454 +} 1.455 + 1.456 +bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { 1.457 + if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 1.458 + *next_delayed_work_time = TimeTicks(); 1.459 + return false; 1.460 + } 1.461 + 1.462 + if (delayed_work_queue_.top().delayed_run_time > TimeTicks::Now()) { 1.463 + *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 1.464 + return false; 1.465 + } 1.466 + 1.467 + PendingTask pending_task = delayed_work_queue_.top(); 1.468 + delayed_work_queue_.pop(); 1.469 + 1.470 + if (!delayed_work_queue_.empty()) 1.471 + *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 1.472 + 1.473 + return DeferOrRunPendingTask(pending_task); 1.474 +} 1.475 + 1.476 +bool MessageLoop::DoIdleWork() { 1.477 + if (ProcessNextDelayedNonNestableTask()) 1.478 + return true; 1.479 + 1.480 + if (state_->quit_received) 1.481 + pump_->Quit(); 1.482 + 1.483 + return false; 1.484 +} 1.485 + 1.486 +//------------------------------------------------------------------------------ 1.487 +// MessageLoop::AutoRunState 1.488 + 1.489 +MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) { 1.490 + // Make the loop reference us. 1.491 + previous_state_ = loop_->state_; 1.492 + if (previous_state_) { 1.493 + run_depth = previous_state_->run_depth + 1; 1.494 + } else { 1.495 + run_depth = 1; 1.496 + } 1.497 + loop_->state_ = this; 1.498 + 1.499 + // Initialize the other fields: 1.500 + quit_received = false; 1.501 +#if defined(OS_WIN) 1.502 + dispatcher = NULL; 1.503 +#endif 1.504 +} 1.505 + 1.506 +MessageLoop::AutoRunState::~AutoRunState() { 1.507 + loop_->state_ = previous_state_; 1.508 +} 1.509 + 1.510 +//------------------------------------------------------------------------------ 1.511 +// MessageLoop::PendingTask 1.512 + 1.513 +bool MessageLoop::PendingTask::operator<(const PendingTask& other) const { 1.514 + // Since the top of a priority queue is defined as the "greatest" element, we 1.515 + // need to invert the comparison here. We want the smaller time to be at the 1.516 + // top of the heap. 1.517 + 1.518 + if (delayed_run_time < other.delayed_run_time) 1.519 + return false; 1.520 + 1.521 + if (delayed_run_time > other.delayed_run_time) 1.522 + return true; 1.523 + 1.524 + // If the times happen to match, then we use the sequence number to decide. 1.525 + // Compare the difference to support integer roll-over. 1.526 + return (sequence_num - other.sequence_num) > 0; 1.527 +} 1.528 + 1.529 +//------------------------------------------------------------------------------ 1.530 +// MessageLoopForUI 1.531 + 1.532 +#if defined(OS_WIN) 1.533 + 1.534 +void MessageLoopForUI::Run(Dispatcher* dispatcher) { 1.535 + AutoRunState save_state(this); 1.536 + state_->dispatcher = dispatcher; 1.537 + RunHandler(); 1.538 +} 1.539 + 1.540 +void MessageLoopForUI::AddObserver(Observer* observer) { 1.541 + pump_win()->AddObserver(observer); 1.542 +} 1.543 + 1.544 +void MessageLoopForUI::RemoveObserver(Observer* observer) { 1.545 + pump_win()->RemoveObserver(observer); 1.546 +} 1.547 + 1.548 +void MessageLoopForUI::WillProcessMessage(const MSG& message) { 1.549 + pump_win()->WillProcessMessage(message); 1.550 +} 1.551 +void MessageLoopForUI::DidProcessMessage(const MSG& message) { 1.552 + pump_win()->DidProcessMessage(message); 1.553 +} 1.554 +void MessageLoopForUI::PumpOutPendingPaintMessages() { 1.555 + pump_ui()->PumpOutPendingPaintMessages(); 1.556 +} 1.557 + 1.558 +#endif // defined(OS_WIN) 1.559 + 1.560 +//------------------------------------------------------------------------------ 1.561 +// MessageLoopForIO 1.562 + 1.563 +#if defined(OS_WIN) 1.564 + 1.565 +void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 1.566 + pump_io()->RegisterIOHandler(file, handler); 1.567 +} 1.568 + 1.569 +bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 1.570 + return pump_io()->WaitForIOCompletion(timeout, filter); 1.571 +} 1.572 + 1.573 +#elif defined(OS_POSIX) 1.574 + 1.575 +bool MessageLoopForIO::WatchFileDescriptor(int fd, 1.576 + bool persistent, 1.577 + Mode mode, 1.578 + FileDescriptorWatcher *controller, 1.579 + Watcher *delegate) { 1.580 + return pump_libevent()->WatchFileDescriptor( 1.581 + fd, 1.582 + persistent, 1.583 + static_cast<base::MessagePumpLibevent::Mode>(mode), 1.584 + controller, 1.585 + delegate); 1.586 +} 1.587 + 1.588 +bool 1.589 +MessageLoopForIO::CatchSignal(int sig, 1.590 + SignalEvent* sigevent, 1.591 + SignalWatcher* delegate) 1.592 +{ 1.593 + return pump_libevent()->CatchSignal(sig, sigevent, delegate); 1.594 +} 1.595 + 1.596 +#endif