blob: 9cef7bff23181c01a03eda4c3cf06f9795f53a4c [file] [log] [blame]
jar@chromium.org34571142011-04-05 13:48:53 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
darin@google.com6ddeb842008-08-15 16:31:20 +09005#include "base/message_loop.h"
6
darin@google.com981f3552008-08-16 12:09:05 +09007#include <algorithm>
8
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09009#include "base/bind.h"
mmentovai@google.comfa5f9932008-08-22 07:26:06 +090010#include "base/compiler_specific.h"
apatrick@chromium.org87164042011-05-20 07:28:25 +090011#include "base/debug/alias.h"
deanm@chromium.orgcd1ce302008-09-10 19:54:06 +090012#include "base/lazy_instance.h"
initial.commit3f4a7322008-07-27 06:49:38 +090013#include "base/logging.h"
thestig@chromium.orgefd4aaf2011-06-15 13:14:23 +090014#include "base/memory/scoped_ptr.h"
darin@google.com12d40bb2008-08-20 03:36:23 +090015#include "base/message_pump_default.h"
brettw@chromium.org275c2ec2010-10-14 13:38:38 +090016#include "base/metrics/histogram.h"
timurrrr@chromium.org490200b2011-01-05 04:06:51 +090017#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
brettw@chromium.org63965582010-12-31 07:18:56 +090018#include "base/threading/thread_local.h"
mbelshe@chromium.orgbee85b32011-05-16 04:20:49 +090019#include "base/time.h"
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090020#include "base/tracked_objects.h"
initial.commit3f4a7322008-07-27 06:49:38 +090021
mark@chromium.org059d0492008-09-24 06:08:28 +090022#if defined(OS_MACOSX)
23#include "base/message_pump_mac.h"
24#endif
dkegel@google.com9e044ae2008-09-19 03:46:26 +090025#if defined(OS_POSIX)
26#include "base/message_pump_libevent.h"
27#endif
michaelbai@google.com686190b2011-08-03 01:11:16 +090028#if defined(OS_ANDROID)
29#include "base/message_pump_android.h"
30#endif
31#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090032#include <gdk/gdk.h>
33#include <gdk/gdkx.h>
rjkroege@google.com3080f442010-10-23 01:17:47 +090034#if defined(TOUCH_UI)
sadrul@chromium.orgf7f3b262011-06-25 05:10:25 +090035#include "base/message_pump_x.h"
36#else
37#include "base/message_pump_gtk.h"
38#endif // defined(TOUCH_UI)
39#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
dkegel@google.com9e044ae2008-09-19 03:46:26 +090040
dsh@google.com0f8dd262008-10-28 05:43:33 +090041using base::TimeDelta;
jar@chromium.org9b0fb062010-11-07 07:23:29 +090042using base::TimeTicks;
dsh@google.com0f8dd262008-10-28 05:43:33 +090043
erg@chromium.orga7528522010-07-16 02:23:23 +090044namespace {
45
deanm@chromium.orgcd1ce302008-09-10 19:54:06 +090046// A lazily created thread local storage for quick access to a thread's message
47// loop, if one exists. This should be safe and free of static constructors.
erg@chromium.orga7528522010-07-16 02:23:23 +090048base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr(
deanm@chromium.orgcd1ce302008-09-10 19:54:06 +090049 base::LINKER_INITIALIZED);
initial.commit3f4a7322008-07-27 06:49:38 +090050
initial.commit3f4a7322008-07-27 06:49:38 +090051// Logical events for Histogram profiling. Run with -message-loop-histogrammer
52// to get an accounting of messages and actions taken on each thread.
erg@chromium.orga7528522010-07-16 02:23:23 +090053const int kTaskRunEvent = 0x1;
54const int kTimerEvent = 0x2;
initial.commit3f4a7322008-07-27 06:49:38 +090055
56// Provide range of message IDs for use in histogramming and debug display.
erg@chromium.orga7528522010-07-16 02:23:23 +090057const int kLeastNonZeroMessageId = 1;
58const int kMaxMessageId = 1099;
59const int kNumberOfDistinctMessagesDisplayed = 1100;
60
61// Provide a macro that takes an expression (such as a constant, or macro
62// constant) and creates a pair to initalize an array of pairs. In this case,
63// our pair consists of the expressions value, and the "stringized" version
64// of the expression (i.e., the exrpression put in quotes). For example, if
65// we have:
66// #define FOO 2
67// #define BAR 5
68// then the following:
69// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
70// will expand to:
71// {7, "FOO + BAR"}
72// We use the resulting array as an argument to our histogram, which reads the
73// number as a bucket identifier, and proceeds to use the corresponding name
74// in the pair (i.e., the quoted string) when printing out a histogram.
75#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
76
brettw@chromium.org275c2ec2010-10-14 13:38:38 +090077const base::LinearHistogram::DescriptionPair event_descriptions_[] = {
erg@chromium.orga7528522010-07-16 02:23:23 +090078 // Provide some pretty print capability in our histogram for our internal
79 // messages.
80
81 // A few events we handle (kindred to messages), and used to profile actions.
82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
84
85 {-1, NULL} // The list must be null terminated, per API to histogram.
86};
87
88bool enable_histogrammer_ = false;
89
michaelbai@google.com686190b2011-08-03 01:11:16 +090090MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
91
erg@chromium.orga7528522010-07-16 02:23:23 +090092} // namespace
initial.commit3f4a7322008-07-27 06:49:38 +090093
94//------------------------------------------------------------------------------
95
darin@google.com981f3552008-08-16 12:09:05 +090096#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +090097
initial.commit3f4a7322008-07-27 06:49:38 +090098// Upon a SEH exception in this thread, it restores the original unhandled
99// exception filter.
100static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
101 ::SetUnhandledExceptionFilter(old_filter);
102 return EXCEPTION_CONTINUE_SEARCH;
103}
104
105// Retrieves a pointer to the current unhandled exception filter. There
106// is no standalone getter method.
107static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
108 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
109 top_filter = ::SetUnhandledExceptionFilter(0);
110 ::SetUnhandledExceptionFilter(top_filter);
111 return top_filter;
112}
113
darin@google.com981f3552008-08-16 12:09:05 +0900114#endif // defined(OS_WIN)
115
initial.commit3f4a7322008-07-27 06:49:38 +0900116//------------------------------------------------------------------------------
117
erg@chromium.org493f5f62010-07-16 06:03:54 +0900118MessageLoop::TaskObserver::TaskObserver() {
119}
120
121MessageLoop::TaskObserver::~TaskObserver() {
122}
123
124MessageLoop::DestructionObserver::~DestructionObserver() {
125}
126
127//------------------------------------------------------------------------------
128
darin@google.comd936b5b2008-08-26 14:53:57 +0900129MessageLoop::MessageLoop(Type type)
130 : type_(type),
darin@google.comee6fa722008-08-13 08:25:43 +0900131 nestable_tasks_allowed_(true),
darin@google.com12d40bb2008-08-20 03:36:23 +0900132 exception_restoration_(false),
jar@chromium.org34571142011-04-05 13:48:53 +0900133 message_histogram_(NULL),
darin@google.combe165ae2008-09-07 17:08:29 +0900134 state_(NULL),
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900135 should_leak_tasks_(true),
ananta@chromium.orgc542fec2011-03-24 12:40:28 +0900136#ifdef OS_WIN
137 os_modal_loop_(false),
138#endif // OS_WIN
darin@google.combe165ae2008-09-07 17:08:29 +0900139 next_sequence_num_(0) {
deanm@chromium.orgcd1ce302008-09-10 19:54:06 +0900140 DCHECK(!current()) << "should only have one message loop per thread";
141 lazy_tls_ptr.Pointer()->Set(this);
darin@google.comd936b5b2008-08-26 14:53:57 +0900142
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900143// TODO(rvargas): Get rid of the OS guards.
darin@google.com981f3552008-08-16 12:09:05 +0900144#if defined(OS_WIN)
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900145#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
146#define MESSAGE_PUMP_IO new base::MessagePumpForIO()
147#elif defined(OS_MACOSX)
148#define MESSAGE_PUMP_UI base::MessagePumpMac::Create()
149#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
michaelbai@google.com686190b2011-08-03 01:11:16 +0900150#elif defined(OS_ANDROID)
151#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
152#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
rjkroege@google.com3080f442010-10-23 01:17:47 +0900153#elif defined(TOUCH_UI)
sadrul@chromium.orgf7f3b262011-06-25 05:10:25 +0900154#define MESSAGE_PUMP_UI new base::MessagePumpX()
rjkroege@google.com3080f442010-10-23 01:17:47 +0900155#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
abarth@chromium.org1f1c2172010-12-01 17:45:51 +0900156#elif defined(OS_NACL)
157// Currently NaCl doesn't have a UI or an IO MessageLoop.
158// TODO(abarth): Figure out if we need these.
159#define MESSAGE_PUMP_UI NULL
160#define MESSAGE_PUMP_IO NULL
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900161#elif defined(OS_POSIX) // POSIX but not MACOSX.
sadrul@chromium.orgf7f3b262011-06-25 05:10:25 +0900162#define MESSAGE_PUMP_UI new base::MessagePumpGtk()
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900163#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
evan@chromium.org875bb6e2009-12-29 09:32:52 +0900164#else
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900165#error Not implemented
evan@chromium.org875bb6e2009-12-29 09:32:52 +0900166#endif
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900167
168 if (type_ == TYPE_UI) {
michaelbai@google.com686190b2011-08-03 01:11:16 +0900169 if (message_pump_for_ui_factory_)
170 pump_ = message_pump_for_ui_factory_();
171 else
172 pump_ = MESSAGE_PUMP_UI;
dsh@google.com119a2522008-10-04 01:52:59 +0900173 } else if (type_ == TYPE_IO) {
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900174 pump_ = MESSAGE_PUMP_IO;
dkegel@google.com9e044ae2008-09-19 03:46:26 +0900175 } else {
thestig@chromium.org7016bac2010-04-15 10:04:29 +0900176 DCHECK_EQ(TYPE_DEFAULT, type_);
dkegel@google.com9e044ae2008-09-19 03:46:26 +0900177 pump_ = new base::MessagePumpDefault();
178 }
initial.commit3f4a7322008-07-27 06:49:38 +0900179}
180
181MessageLoop::~MessageLoop() {
thestig@chromium.org226880a2010-11-11 05:28:06 +0900182 DCHECK_EQ(this, current());
darin@google.com965e5342008-08-06 08:16:41 +0900183
darin@google.com0e500502008-09-09 14:55:35 +0900184 DCHECK(!state_);
185
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900186 // Clean up any unprocessed tasks, but take care: deleting a task could
187 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
188 // limit on the number of times we will allow a deleted task to generate more
189 // tasks. Normally, we should only pass through this loop once or twice. If
190 // we end up hitting the loop limit, then it is probably due to one task that
191 // is being stubborn. Inspect the queues to see who is left.
192 bool did_work;
193 for (int i = 0; i < 100; ++i) {
194 DeletePendingTasks();
195 ReloadWorkQueue();
196 // If we end up with empty queues, then break out of the loop.
197 did_work = DeletePendingTasks();
198 if (!did_work)
199 break;
darin@google.com0e500502008-09-09 14:55:35 +0900200 }
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900201 DCHECK(!did_work);
202
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +0900203 // Let interested parties have one last shot at accessing this.
204 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
205 WillDestroyCurrentMessageLoop());
206
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900207 // OK, now make it so that no one can find us.
deanm@chromium.orge4cc5922008-09-10 20:14:56 +0900208 lazy_tls_ptr.Pointer()->Set(NULL);
mbelshe@chromium.orgbee85b32011-05-16 04:20:49 +0900209
210#if defined(OS_WIN)
211 // If we left the high-resolution timer activated, deactivate it now.
212 // Doing this is not-critical, it is mainly to make sure we track
213 // the high resolution timer activations properly in our unit tests.
214 if (!high_resolution_timer_expiration_.is_null()) {
215 base::Time::ActivateHighResolutionTimer(false);
216 high_resolution_timer_expiration_ = base::TimeTicks();
217 }
218#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900219}
220
erg@google.com67a25432011-01-08 05:23:43 +0900221// static
222MessageLoop* MessageLoop::current() {
223 // TODO(darin): sadly, we cannot enable this yet since people call us even
224 // when they have no intention of using us.
225 // DCHECK(loop) << "Ouch, did you forget to initialize me?";
226 return lazy_tls_ptr.Pointer()->Get();
227}
228
229// static
230void MessageLoop::EnableHistogrammer(bool enable) {
231 enable_histogrammer_ = enable;
232}
233
michaelbai@google.com686190b2011-08-03 01:11:16 +0900234// static
235void MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
236 DCHECK(!message_pump_for_ui_factory_);
237 message_pump_for_ui_factory_ = factory;
238}
239
sky@chromium.org18c66dc2010-09-16 07:14:36 +0900240void MessageLoop::AddDestructionObserver(
241 DestructionObserver* destruction_observer) {
thestig@chromium.org226880a2010-11-11 05:28:06 +0900242 DCHECK_EQ(this, current());
sky@chromium.org18c66dc2010-09-16 07:14:36 +0900243 destruction_observers_.AddObserver(destruction_observer);
darin@google.com965e5342008-08-06 08:16:41 +0900244}
245
sky@chromium.org18c66dc2010-09-16 07:14:36 +0900246void MessageLoop::RemoveDestructionObserver(
247 DestructionObserver* destruction_observer) {
thestig@chromium.org226880a2010-11-11 05:28:06 +0900248 DCHECK_EQ(this, current());
sky@chromium.org18c66dc2010-09-16 07:14:36 +0900249 destruction_observers_.RemoveObserver(destruction_observer);
darin@google.com965e5342008-08-06 08:16:41 +0900250}
251
darin@google.combe165ae2008-09-07 17:08:29 +0900252void MessageLoop::PostTask(
253 const tracked_objects::Location& from_here, Task* task) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900254 CHECK(task);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900255 PendingTask pending_task(
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900256 base::Bind(
257 &base::subtle::TaskClosureAdapter::Run,
258 new base::subtle::TaskClosureAdapter(task, &should_leak_tasks_)),
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900259 from_here,
260 CalculateDelayedRuntime(0), true);
261 AddToIncomingQueue(&pending_task);
darin@google.combe165ae2008-09-07 17:08:29 +0900262}
263
264void MessageLoop::PostDelayedTask(
phajdan.jr@chromium.orgc3c92252009-06-18 02:23:51 +0900265 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900266 CHECK(task);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900267 PendingTask pending_task(
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900268 base::Bind(
269 &base::subtle::TaskClosureAdapter::Run,
270 new base::subtle::TaskClosureAdapter(task, &should_leak_tasks_)),
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900271 from_here,
272 CalculateDelayedRuntime(delay_ms), true);
273 AddToIncomingQueue(&pending_task);
darin@google.combe165ae2008-09-07 17:08:29 +0900274}
275
276void MessageLoop::PostNonNestableTask(
277 const tracked_objects::Location& from_here, Task* task) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900278 CHECK(task);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900279 PendingTask pending_task(
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900280 base::Bind(
281 &base::subtle::TaskClosureAdapter::Run,
282 new base::subtle::TaskClosureAdapter(task, &should_leak_tasks_)),
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900283 from_here,
284 CalculateDelayedRuntime(0), false);
285 AddToIncomingQueue(&pending_task);
darin@google.combe165ae2008-09-07 17:08:29 +0900286}
287
288void MessageLoop::PostNonNestableDelayedTask(
phajdan.jr@chromium.orgc3c92252009-06-18 02:23:51 +0900289 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900290 CHECK(task);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900291 PendingTask pending_task(
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900292 base::Bind(
293 &base::subtle::TaskClosureAdapter::Run,
294 new base::subtle::TaskClosureAdapter(task, &should_leak_tasks_)),
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900295 from_here,
296 CalculateDelayedRuntime(delay_ms), false);
297 AddToIncomingQueue(&pending_task);
298}
299
300void MessageLoop::PostTask(
301 const tracked_objects::Location& from_here, const base::Closure& task) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900302 CHECK(!task.is_null());
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900303 PendingTask pending_task(task, from_here, CalculateDelayedRuntime(0), true);
304 AddToIncomingQueue(&pending_task);
305}
306
307void MessageLoop::PostDelayedTask(
308 const tracked_objects::Location& from_here, const base::Closure& task,
309 int64 delay_ms) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900310 CHECK(!task.is_null());
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900311 PendingTask pending_task(task, from_here,
312 CalculateDelayedRuntime(delay_ms), true);
313 AddToIncomingQueue(&pending_task);
314}
315
316void MessageLoop::PostNonNestableTask(
317 const tracked_objects::Location& from_here, const base::Closure& task) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900318 CHECK(!task.is_null());
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900319 PendingTask pending_task(task, from_here, CalculateDelayedRuntime(0), false);
320 AddToIncomingQueue(&pending_task);
321}
322
323void MessageLoop::PostNonNestableDelayedTask(
324 const tracked_objects::Location& from_here, const base::Closure& task,
325 int64 delay_ms) {
apatrick@chromium.org47db3702011-05-11 06:52:21 +0900326 CHECK(!task.is_null());
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900327 PendingTask pending_task(task, from_here,
328 CalculateDelayedRuntime(delay_ms), false);
329 AddToIncomingQueue(&pending_task);
darin@google.combe165ae2008-09-07 17:08:29 +0900330}
331
erg@google.com67a25432011-01-08 05:23:43 +0900332void MessageLoop::Run() {
333 AutoRunState save_state(this);
334 RunHandler();
335}
darin@google.com0795f572008-08-30 09:22:48 +0900336
erg@google.com67a25432011-01-08 05:23:43 +0900337void MessageLoop::RunAllPending() {
338 AutoRunState save_state(this);
339 state_->quit_received = true; // Means run until we would otherwise block.
340 RunHandler();
341}
darin@google.com0795f572008-08-30 09:22:48 +0900342
erg@google.com67a25432011-01-08 05:23:43 +0900343void MessageLoop::Quit() {
344 DCHECK_EQ(this, current());
345 if (state_) {
346 state_->quit_received = true;
darin@google.com0795f572008-08-30 09:22:48 +0900347 } else {
erg@google.com67a25432011-01-08 05:23:43 +0900348 NOTREACHED() << "Must be inside Run to call Quit";
darin@google.com0795f572008-08-30 09:22:48 +0900349 }
erg@google.com67a25432011-01-08 05:23:43 +0900350}
darin@google.com0795f572008-08-30 09:22:48 +0900351
erg@google.com67a25432011-01-08 05:23:43 +0900352void MessageLoop::QuitNow() {
353 DCHECK_EQ(this, current());
354 if (state_) {
355 pump_->Quit();
356 } else {
357 NOTREACHED() << "Must be inside Run to call Quit";
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +0900358 }
initial.commit3f4a7322008-07-27 06:49:38 +0900359}
360
361void MessageLoop::SetNestableTasksAllowed(bool allowed) {
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900362 if (nestable_tasks_allowed_ != allowed) {
363 nestable_tasks_allowed_ = allowed;
364 if (!nestable_tasks_allowed_)
365 return;
366 // Start the native pump if we are not already pumping.
darin@google.com981f3552008-08-16 12:09:05 +0900367 pump_->ScheduleWork();
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900368 }
initial.commit3f4a7322008-07-27 06:49:38 +0900369}
370
371bool MessageLoop::NestableTasksAllowed() const {
372 return nestable_tasks_allowed_;
373}
374
jcampan@chromium.orgeac57172009-07-02 04:53:59 +0900375bool MessageLoop::IsNested() {
376 return state_->run_depth > 1;
377}
378
erg@google.com67a25432011-01-08 05:23:43 +0900379void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
380 DCHECK_EQ(this, current());
381 task_observers_.AddObserver(task_observer);
382}
383
384void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
385 DCHECK_EQ(this, current());
386 task_observers_.RemoveObserver(task_observer);
387}
388
willchan@chromium.org3a397672011-01-26 09:53:48 +0900389void MessageLoop::AssertIdle() const {
390 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
391 base::AutoLock lock(incoming_queue_lock_);
392 DCHECK(incoming_queue_.empty());
393}
394
initial.commit3f4a7322008-07-27 06:49:38 +0900395//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900396
erg@google.com67a25432011-01-08 05:23:43 +0900397// Runs the loop in two different SEH modes:
398// enable_SEH_restoration_ = false : any unhandled exception goes to the last
399// one that calls SetUnhandledExceptionFilter().
400// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
401// that was existed before the loop was run.
402void MessageLoop::RunHandler() {
403#if defined(OS_WIN)
404 if (exception_restoration_) {
405 RunInternalInSEHFrame();
406 return;
407 }
408#endif
409
410 RunInternal();
411}
412
413#if defined(OS_WIN)
414__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() {
415 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
416 __try {
417 RunInternal();
418 } __except(SEHFilter(current_filter)) {
419 }
420 return;
421}
422#endif
423
424void MessageLoop::RunInternal() {
425 DCHECK_EQ(this, current());
426
427 StartHistogrammer();
428
michaelbai@google.com686190b2011-08-03 01:11:16 +0900429#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
erg@google.com67a25432011-01-08 05:23:43 +0900430 if (state_->dispatcher && type() == TYPE_UI) {
431 static_cast<base::MessagePumpForUI*>(pump_.get())->
432 RunWithDispatcher(this, state_->dispatcher);
433 return;
434 }
435#endif
436
437 pump_->Run(this);
438}
439
440bool MessageLoop::ProcessNextDelayedNonNestableTask() {
441 if (state_->run_depth != 1)
442 return false;
443
444 if (deferred_non_nestable_work_queue_.empty())
445 return false;
446
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900447 PendingTask pending_task = deferred_non_nestable_work_queue_.front();
erg@google.com67a25432011-01-08 05:23:43 +0900448 deferred_non_nestable_work_queue_.pop();
449
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900450 RunTask(pending_task);
erg@google.com67a25432011-01-08 05:23:43 +0900451 return true;
452}
453
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900454void MessageLoop::RunTask(const PendingTask& pending_task) {
initial.commit3f4a7322008-07-27 06:49:38 +0900455 DCHECK(nestable_tasks_allowed_);
456 // Execute the task and assume the worst: It is probably not reentrant.
457 nestable_tasks_allowed_ = false;
darin@google.combe165ae2008-09-07 17:08:29 +0900458
apatrick@chromium.org87164042011-05-20 07:28:25 +0900459 // Before running the task, store the program counter where it was posted
460 // and deliberately alias it to ensure it is on the stack if the task
461 // crashes. Be careful not to assume that the variable itself will have the
462 // expected value when displayed by the optimizer in an optimized build.
463 // Look at a memory dump of the stack.
464 const void* program_counter = pending_task.birth_program_counter;
465 base::debug::Alias(&program_counter);
466
darin@google.combe165ae2008-09-07 17:08:29 +0900467 HistogramEvent(kTaskRunEvent);
willchan@chromium.orga9047632010-06-10 06:20:41 +0900468 FOR_EACH_OBSERVER(TaskObserver, task_observers_,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900469 WillProcessTask(pending_task.time_posted));
470 pending_task.task.Run();
471 FOR_EACH_OBSERVER(TaskObserver, task_observers_,
472 DidProcessTask(pending_task.time_posted));
473
474#if defined(TRACK_ALL_TASK_OBJECTS)
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900475 tracked_objects::ThreadData::TallyADeathIfActive(
476 pending_task.post_births,
477 TimeTicks::Now() - pending_task.time_posted);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900478#endif // defined(TRACK_ALL_TASK_OBJECTS)
darin@google.combe165ae2008-09-07 17:08:29 +0900479
480 nestable_tasks_allowed_ = true;
initial.commit3f4a7322008-07-27 06:49:38 +0900481}
482
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900483bool MessageLoop::DeferOrRunPendingTask(
484 const PendingTask& pending_task) {
darin@google.combe165ae2008-09-07 17:08:29 +0900485 if (pending_task.nestable || state_->run_depth == 1) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900486 RunTask(pending_task);
darin@google.combe165ae2008-09-07 17:08:29 +0900487 // Show that we ran a task (Note: a new one might arrive as a
488 // consequence!).
489 return true;
490 }
491
492 // We couldn't run the task now because we're in a nested message loop
493 // and the task isn't nestable.
494 deferred_non_nestable_work_queue_.push(pending_task);
495 return false;
initial.commit3f4a7322008-07-27 06:49:38 +0900496}
497
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900498void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
499 // Move to the delayed work queue. Initialize the sequence number
500 // before inserting into the delayed_work_queue_. The sequence number
501 // is used to faciliate FIFO sorting when two tasks have the same
502 // delayed_run_time value.
503 PendingTask new_pending_task(pending_task);
504 new_pending_task.sequence_num = next_sequence_num_++;
505 delayed_work_queue_.push(new_pending_task);
506}
507
initial.commit3f4a7322008-07-27 06:49:38 +0900508void MessageLoop::ReloadWorkQueue() {
509 // We can improve performance of our loading tasks from incoming_queue_ to
darin@google.com981f3552008-08-16 12:09:05 +0900510 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
511 // load. That reduces the number of locks-per-task significantly when our
darin@google.combe165ae2008-09-07 17:08:29 +0900512 // queues get large.
513 if (!work_queue_.empty())
initial.commit3f4a7322008-07-27 06:49:38 +0900514 return; // Wait till we *really* need to lock and load.
515
516 // Acquire all we can from the inter-thread queue with one lock acquisition.
initial.commit3f4a7322008-07-27 06:49:38 +0900517 {
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900518 base::AutoLock lock(incoming_queue_lock_);
darin@google.combe165ae2008-09-07 17:08:29 +0900519 if (incoming_queue_.empty())
initial.commit3f4a7322008-07-27 06:49:38 +0900520 return;
darin@chromium.orgb80ef1a2009-09-03 05:05:21 +0900521 incoming_queue_.Swap(&work_queue_); // Constant time
darin@google.combe165ae2008-09-07 17:08:29 +0900522 DCHECK(incoming_queue_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900523 }
524}
525
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900526bool MessageLoop::DeletePendingTasks() {
527 bool did_work = !work_queue_.empty();
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900528 // TODO(darin): Delete all tasks once it is safe to do so.
529 // Until it is totally safe, just do it when running Purify or
530 // Valgrind.
531 //
532 // See http://crbug.com/61131
533 //
534#if defined(PURIFY) || defined(USE_HEAPCHECKER)
535 should_leak_tasks_ = false;
536#else
537 if (RunningOnValgrind())
538 should_leak_tasks_ = false;
539#endif // defined(OS_POSIX)
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900540 while (!work_queue_.empty()) {
541 PendingTask pending_task = work_queue_.front();
542 work_queue_.pop();
543 if (!pending_task.delayed_run_time.is_null()) {
544 // We want to delete delayed tasks in the same order in which they would
545 // normally be deleted in case of any funny dependencies between delayed
546 // tasks.
547 AddToDelayedWorkQueue(pending_task);
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900548 }
initial.commit3f4a7322008-07-27 06:49:38 +0900549 }
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900550 did_work |= !deferred_non_nestable_work_queue_.empty();
551 while (!deferred_non_nestable_work_queue_.empty()) {
jar@chromium.org2fa6b4b2009-03-12 04:53:50 +0900552 deferred_non_nestable_work_queue_.pop();
initial.commit3f4a7322008-07-27 06:49:38 +0900553 }
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900554 did_work |= !delayed_work_queue_.empty();
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900555
556 // Historically, we always delete the task regardless of valgrind status. It's
557 // not completely clear why we want to leak them in the loops above. This
558 // code is replicating legacy behavior, and should not be considered
559 // absolutely "correct" behavior. See TODO above about deleting all tasks
560 // when it's safe.
561 should_leak_tasks_ = false;
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900562 while (!delayed_work_queue_.empty()) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900563 delayed_work_queue_.pop();
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900564 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900565 should_leak_tasks_ = true;
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900566 return did_work;
initial.commit3f4a7322008-07-27 06:49:38 +0900567}
568
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900569TimeTicks MessageLoop::CalculateDelayedRuntime(int64 delay_ms) {
570 TimeTicks delayed_run_time;
erg@google.com67a25432011-01-08 05:23:43 +0900571 if (delay_ms > 0) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900572 delayed_run_time =
erg@google.com67a25432011-01-08 05:23:43 +0900573 TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
574
575#if defined(OS_WIN)
576 if (high_resolution_timer_expiration_.is_null()) {
577 // Windows timers are granular to 15.6ms. If we only set high-res
578 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
579 // which as a percentage is pretty inaccurate. So enable high
580 // res timers for any timer which is within 2x of the granularity.
581 // This is a tradeoff between accuracy and power management.
582 bool needs_high_res_timers =
583 delay_ms < (2 * base::Time::kMinLowResolutionThresholdMs);
584 if (needs_high_res_timers) {
mbelshe@chromium.orgbee85b32011-05-16 04:20:49 +0900585 if (base::Time::ActivateHighResolutionTimer(true)) {
586 high_resolution_timer_expiration_ = TimeTicks::Now() +
587 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs);
588 }
erg@google.com67a25432011-01-08 05:23:43 +0900589 }
590 }
591#endif
592 } else {
593 DCHECK_EQ(delay_ms, 0) << "delay should not be negative";
594 }
595
596#if defined(OS_WIN)
597 if (!high_resolution_timer_expiration_.is_null()) {
598 if (TimeTicks::Now() > high_resolution_timer_expiration_) {
599 base::Time::ActivateHighResolutionTimer(false);
600 high_resolution_timer_expiration_ = TimeTicks();
601 }
602 }
603#endif
604
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900605 return delayed_run_time;
606}
607
608// Possibly called on a background thread!
609void MessageLoop::AddToIncomingQueue(PendingTask* pending_task) {
erg@google.com67a25432011-01-08 05:23:43 +0900610 // Warning: Don't try to short-circuit, and handle this thread's tasks more
611 // directly, as it could starve handling of foreign threads. Put every task
612 // into this queue.
613
614 scoped_refptr<base::MessagePump> pump;
615 {
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900616 base::AutoLock locked(incoming_queue_lock_);
erg@google.com67a25432011-01-08 05:23:43 +0900617
618 bool was_empty = incoming_queue_.empty();
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900619 incoming_queue_.push(*pending_task);
620 pending_task->task.Reset();
erg@google.com67a25432011-01-08 05:23:43 +0900621 if (!was_empty)
622 return; // Someone else should have started the sub-pump.
623
624 pump = pump_;
625 }
626 // Since the incoming_queue_ may contain a task that destroys this message
627 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
628 // We use a stack-based reference to the message pump so that we can call
629 // ScheduleWork outside of incoming_queue_lock_.
630
631 pump->ScheduleWork();
632}
633
634//------------------------------------------------------------------------------
635// Method and data for histogramming events and actions taken by each instance
636// on each thread.
637
638void MessageLoop::StartHistogrammer() {
jar@chromium.org34571142011-04-05 13:48:53 +0900639 if (enable_histogrammer_ && !message_histogram_
erg@google.com67a25432011-01-08 05:23:43 +0900640 && base::StatisticsRecorder::IsActive()) {
641 DCHECK(!thread_name_.empty());
642 message_histogram_ = base::LinearHistogram::FactoryGet(
643 "MsgLoop:" + thread_name_,
644 kLeastNonZeroMessageId, kMaxMessageId,
645 kNumberOfDistinctMessagesDisplayed,
646 message_histogram_->kHexRangePrintingFlag);
647 message_histogram_->SetRangeDescriptions(event_descriptions_);
648 }
649}
650
651void MessageLoop::HistogramEvent(int event) {
jar@chromium.org34571142011-04-05 13:48:53 +0900652 if (message_histogram_)
erg@google.com67a25432011-01-08 05:23:43 +0900653 message_histogram_->Add(event);
654}
655
darin@google.com981f3552008-08-16 12:09:05 +0900656bool MessageLoop::DoWork() {
darin@google.combe165ae2008-09-07 17:08:29 +0900657 if (!nestable_tasks_allowed_) {
658 // Task can't be executed right now.
659 return false;
660 }
661
662 for (;;) {
663 ReloadWorkQueue();
664 if (work_queue_.empty())
665 break;
666
667 // Execute oldest task.
668 do {
669 PendingTask pending_task = work_queue_.front();
670 work_queue_.pop();
671 if (!pending_task.delayed_run_time.is_null()) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900672 AddToDelayedWorkQueue(pending_task);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900673 // If we changed the topmost task, then it is time to reschedule.
674 if (delayed_work_queue_.top().task.Equals(pending_task.task))
darin@google.combe165ae2008-09-07 17:08:29 +0900675 pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
676 } else {
677 if (DeferOrRunPendingTask(pending_task))
678 return true;
679 }
680 } while (!work_queue_.empty());
681 }
682
683 // Nothing happened.
684 return false;
darin@google.com981f3552008-08-16 12:09:05 +0900685}
686
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900687bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
jar@chromium.org40355072010-10-21 15:32:33 +0900688 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
jar@chromium.org9b0fb062010-11-07 07:23:29 +0900689 recent_time_ = *next_delayed_work_time = TimeTicks();
darin@google.combe165ae2008-09-07 17:08:29 +0900690 return false;
691 }
jeremy@chromium.org2ed223c2008-12-09 02:36:06 +0900692
jar@chromium.org9b0fb062010-11-07 07:23:29 +0900693 // When we "fall behind," there will be a lot of tasks in the delayed work
jar@chromium.org94f73832010-11-05 08:23:42 +0900694 // queue that are ready to run. To increase efficiency when we fall behind,
695 // we will only call Time::Now() intermittently, and then process all tasks
696 // that are ready to run before calling it again. As a result, the more we
697 // fall behind (and have a lot of ready-to-run delayed tasks), the more
698 // efficient we'll be at handling the tasks.
jar@chromium.org9b0fb062010-11-07 07:23:29 +0900699
700 TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
jar@chromium.org94f73832010-11-05 08:23:42 +0900701 if (next_run_time > recent_time_) {
jar@chromium.org9b0fb062010-11-07 07:23:29 +0900702 recent_time_ = TimeTicks::Now(); // Get a better view of Now();
jar@chromium.org94f73832010-11-05 08:23:42 +0900703 if (next_run_time > recent_time_) {
704 *next_delayed_work_time = next_run_time;
705 return false;
706 }
darin@google.combe165ae2008-09-07 17:08:29 +0900707 }
darin@google.com981f3552008-08-16 12:09:05 +0900708
jar@chromium.org40355072010-10-21 15:32:33 +0900709 PendingTask pending_task = delayed_work_queue_.top();
710 delayed_work_queue_.pop();
jeremy@chromium.org2ed223c2008-12-09 02:36:06 +0900711
jar@chromium.org40355072010-10-21 15:32:33 +0900712 if (!delayed_work_queue_.empty())
darin@google.combe165ae2008-09-07 17:08:29 +0900713 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
darin@google.com981f3552008-08-16 12:09:05 +0900714
darin@google.combe165ae2008-09-07 17:08:29 +0900715 return DeferOrRunPendingTask(pending_task);
darin@google.com981f3552008-08-16 12:09:05 +0900716}
717
718bool MessageLoop::DoIdleWork() {
719 if (ProcessNextDelayedNonNestableTask())
720 return true;
721
722 if (state_->quit_received)
723 pump_->Quit();
724
725 return false;
726}
727
728//------------------------------------------------------------------------------
729// MessageLoop::AutoRunState
730
731MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
732 // Make the loop reference us.
733 previous_state_ = loop_->state_;
734 if (previous_state_) {
735 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900736 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900737 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900738 }
darin@google.com981f3552008-08-16 12:09:05 +0900739 loop_->state_ = this;
740
741 // Initialize the other fields:
742 quit_received = false;
michaelbai@google.com686190b2011-08-03 01:11:16 +0900743#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
darin@google.com981f3552008-08-16 12:09:05 +0900744 dispatcher = NULL;
745#endif
746}
747
748MessageLoop::AutoRunState::~AutoRunState() {
749 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900750}
751
initial.commit3f4a7322008-07-27 06:49:38 +0900752//------------------------------------------------------------------------------
darin@google.combe165ae2008-09-07 17:08:29 +0900753// MessageLoop::PendingTask
initial.commit3f4a7322008-07-27 06:49:38 +0900754
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900755MessageLoop::PendingTask::PendingTask(
756 const base::Closure& task,
757 const tracked_objects::Location& posted_from,
758 TimeTicks delayed_run_time,
759 bool nestable)
760 : task(task),
761 time_posted(TimeTicks::Now()),
762 delayed_run_time(delayed_run_time),
763 sequence_num(0),
apatrick@chromium.org87164042011-05-20 07:28:25 +0900764 nestable(nestable),
765 birth_program_counter(posted_from.program_counter()) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900766#if defined(TRACK_ALL_TASK_OBJECTS)
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900767 post_births = tracked_objects::ThreadData::TallyABirthIfActive(posted_from);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900768#endif // defined(TRACK_ALL_TASK_OBJECTS)
769}
770
771MessageLoop::PendingTask::~PendingTask() {
772}
773
darin@google.combe165ae2008-09-07 17:08:29 +0900774bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
775 // Since the top of a priority queue is defined as the "greatest" element, we
776 // need to invert the comparison here. We want the smaller time to be at the
777 // top of the heap.
initial.commit3f4a7322008-07-27 06:49:38 +0900778
darin@google.combe165ae2008-09-07 17:08:29 +0900779 if (delayed_run_time < other.delayed_run_time)
780 return false;
initial.commit3f4a7322008-07-27 06:49:38 +0900781
darin@google.combe165ae2008-09-07 17:08:29 +0900782 if (delayed_run_time > other.delayed_run_time)
783 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900784
darin@google.combe165ae2008-09-07 17:08:29 +0900785 // If the times happen to match, then we use the sequence number to decide.
786 // Compare the difference to support integer roll-over.
787 return (sequence_num - other.sequence_num) > 0;
initial.commit3f4a7322008-07-27 06:49:38 +0900788}
789
790//------------------------------------------------------------------------------
darin@google.comd936b5b2008-08-26 14:53:57 +0900791// MessageLoopForUI
792
793#if defined(OS_WIN)
darin@google.comd936b5b2008-08-26 14:53:57 +0900794void MessageLoopForUI::DidProcessMessage(const MSG& message) {
795 pump_win()->DidProcessMessage(message);
796}
darin@google.comd936b5b2008-08-26 14:53:57 +0900797#endif // defined(OS_WIN)
798
michaelbai@google.com686190b2011-08-03 01:11:16 +0900799#if defined(OS_ANDROID)
800void MessageLoopForUI::Start() {
801 // No Histogram support for UI message loop as it is managed by Java side
802 static_cast<base::MessagePumpForUI*>(pump_.get())->Start(this);
803}
804#endif
805
806#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
jcampan@chromium.org05423582009-08-01 07:53:37 +0900807void MessageLoopForUI::AddObserver(Observer* observer) {
808 pump_ui()->AddObserver(observer);
809}
810
811void MessageLoopForUI::RemoveObserver(Observer* observer) {
812 pump_ui()->RemoveObserver(observer);
813}
814
815void MessageLoopForUI::Run(Dispatcher* dispatcher) {
816 AutoRunState save_state(this);
817 state_->dispatcher = dispatcher;
818 RunHandler();
819}
michaelbai@google.com686190b2011-08-03 01:11:16 +0900820#endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
jcampan@chromium.org05423582009-08-01 07:53:37 +0900821
darin@google.comd936b5b2008-08-26 14:53:57 +0900822//------------------------------------------------------------------------------
823// MessageLoopForIO
824
825#if defined(OS_WIN)
826
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900827void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
828 pump_io()->RegisterIOHandler(file, handler);
829}
830
rvargas@google.com73887542008-11-08 06:52:15 +0900831bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
832 return pump_io()->WaitForIOCompletion(timeout, filter);
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900833}
834
abarth@chromium.org1f1c2172010-12-01 17:45:51 +0900835#elif defined(OS_POSIX) && !defined(OS_NACL)
dkegel@google.com9e044ae2008-09-19 03:46:26 +0900836
jeremy@chromium.orgefc0db02008-12-16 07:02:17 +0900837bool MessageLoopForIO::WatchFileDescriptor(int fd,
838 bool persistent,
839 Mode mode,
840 FileDescriptorWatcher *controller,
841 Watcher *delegate) {
842 return pump_libevent()->WatchFileDescriptor(
843 fd,
844 persistent,
845 static_cast<base::MessagePumpLibevent::Mode>(mode),
846 controller,
847 delegate);
dkegel@google.com9e044ae2008-09-19 03:46:26 +0900848}
849
dkegel@google.com9e044ae2008-09-19 03:46:26 +0900850#endif