1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 
7 #include "base/message_pump_android.h"
8 
9 #include <fcntl.h>
10 #include <math.h>
11 
12 #include "base/eintr_wrapper.h"
13 #include "base/logging.h"
14 #include "base/platform_thread.h"
15 
16 namespace mozilla {
17 bool ProcessNextEvent();
18 void NotifyEvent();
19 }  // namespace mozilla
20 
21 namespace base {
22 
MessagePumpForUI()23 MessagePumpForUI::MessagePumpForUI() : state_(NULL) {}
24 
~MessagePumpForUI()25 MessagePumpForUI::~MessagePumpForUI() {}
26 
Run(Delegate * delegate)27 void MessagePumpForUI::Run(Delegate* delegate) {
28   RunState state;
29   state.delegate = delegate;
30   state.should_quit = false;
31   state.run_depth = state_ ? state_->run_depth + 1 : 1;
32   // We really only do a single task for each iteration of the loop.  If we
33   // have done something, assume there is likely something more to do.  This
34   // will mean that we don't block on the message pump until there was nothing
35   // more to do.  We also set this to true to make sure not to block on the
36   // first iteration of the loop, so RunAllPending() works correctly.
37   state.more_work_is_plausible = true;
38 
39   RunState* previous_state = state_;
40   state_ = &state;
41 
42   // We run our own loop instead of using g_main_loop_quit in one of the
43   // callbacks.  This is so we only quit our own loops, and we don't quit
44   // nested loops run by others.  TODO(deanm): Is this what we want?
45 
46   while (!state_->should_quit) {
47     mozilla::ProcessNextEvent();
48     if (work_scheduled) {
49       work_scheduled = false;
50       HandleDispatch();
51     }
52   }
53 
54   state_ = previous_state;
55 }
56 
HandleDispatch()57 void MessagePumpForUI::HandleDispatch() {
58   // We should only ever have a single message on the wakeup pipe, since we
59   // are only signaled when the queue went from empty to non-empty.  The qApp
60   // poll will tell us whether there was data, so this read shouldn't block.
61   if (state_->should_quit) return;
62 
63   state_->more_work_is_plausible = false;
64 
65   if (state_->delegate->DoWork()) state_->more_work_is_plausible = true;
66 
67   if (state_->should_quit) return;
68 
69   if (state_->delegate->DoDelayedWork(&delayed_work_time_))
70     state_->more_work_is_plausible = true;
71   if (state_->should_quit) return;
72 
73   // Don't do idle work if we think there are more important things
74   // that we could be doing.
75   if (state_->more_work_is_plausible) return;
76 
77   if (state_->delegate->DoIdleWork()) state_->more_work_is_plausible = true;
78   if (state_->should_quit) return;
79 }
80 
Quit()81 void MessagePumpForUI::Quit() {
82   if (state_) {
83     state_->should_quit = true;
84   } else {
85     NOTREACHED() << "Quit called outside Run!";
86   }
87 }
88 
ScheduleWork()89 void MessagePumpForUI::ScheduleWork() {
90   // This can be called on any thread, so we don't want to touch any state
91   // variables as we would then need locks all over.  This ensures that if
92   // we are sleeping in a poll that we will wake up.
93   work_scheduled = true;
94   mozilla::NotifyEvent();
95 }
96 
ScheduleDelayedWork(const TimeTicks & delayed_work_time)97 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
98   // We need to wake up the loop in case the poll timeout needs to be
99   // adjusted.  This will cause us to try to do work, but that's ok.
100   delayed_work_time_ = delayed_work_time;
101   ScheduleWork();
102 }
103 
104 }  // namespace base
105