Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / public / cpp / utility / lib / run_loop.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/cpp/utility/run_loop.h"
6
7 #include <assert.h>
8
9 #include <algorithm>
10 #include <vector>
11
12 #include "mojo/public/cpp/utility/lib/thread_local.h"
13 #include "mojo/public/cpp/utility/run_loop_handler.h"
14
15 namespace mojo {
16 namespace {
17
18 internal::ThreadLocalPointer<RunLoop> current_run_loop;
19
20 const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0);
21
22 }  // namespace
23
24 // State needed for one iteration of WaitMany().
25 struct RunLoop::WaitState {
26   WaitState() : deadline(MOJO_DEADLINE_INDEFINITE) {}
27
28   std::vector<Handle> handles;
29   std::vector<MojoHandleSignals> handle_signals;
30   MojoDeadline deadline;
31 };
32
33 struct RunLoop::RunState {
34   RunState() : should_quit(false) {}
35
36   bool should_quit;
37 };
38
39 RunLoop::RunLoop()
40     : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) {
41   assert(!current());
42   current_run_loop.Set(this);
43 }
44
45 RunLoop::~RunLoop() {
46   assert(current() == this);
47   current_run_loop.Set(NULL);
48 }
49
50 // static
51 void RunLoop::SetUp() {
52   current_run_loop.Allocate();
53 }
54
55 // static
56 void RunLoop::TearDown() {
57   assert(!current());
58   current_run_loop.Free();
59 }
60
61 // static
62 RunLoop* RunLoop::current() {
63   return current_run_loop.Get();
64 }
65
66 void RunLoop::AddHandler(RunLoopHandler* handler,
67                          const Handle& handle,
68                          MojoHandleSignals handle_signals,
69                          MojoDeadline deadline) {
70   assert(current() == this);
71   assert(handler);
72   assert(handle.is_valid());
73   // Assume it's an error if someone tries to reregister an existing handle.
74   assert(0u == handler_data_.count(handle));
75   HandlerData handler_data;
76   handler_data.handler = handler;
77   handler_data.handle_signals = handle_signals;
78   handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ?
79       kInvalidTimeTicks :
80       GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline);
81   handler_data.id = next_handler_id_++;
82   handler_data_[handle] = handler_data;
83 }
84
85 void RunLoop::RemoveHandler(const Handle& handle) {
86   assert(current() == this);
87   handler_data_.erase(handle);
88 }
89
90 bool RunLoop::HasHandler(const Handle& handle) const {
91   return handler_data_.find(handle) != handler_data_.end();
92 }
93
94 void RunLoop::Run() {
95   assert(current() == this);
96   RunState* old_state = run_state_;
97   RunState run_state;
98   run_state_ = &run_state;
99   while (!run_state.should_quit) {
100     DoDelayedWork();
101     Wait(false);
102   }
103   run_state_ = old_state;
104 }
105
106 void RunLoop::RunUntilIdle() {
107   assert(current() == this);
108   RunState* old_state = run_state_;
109   RunState run_state;
110   run_state_ = &run_state;
111   while (!run_state.should_quit) {
112     DoDelayedWork();
113     if (!Wait(true) && delayed_tasks_.empty())
114       break;
115   }
116   run_state_ = old_state;
117 }
118
119 void RunLoop::DoDelayedWork() {
120   MojoTimeTicks now = GetTimeTicksNow();
121   if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) {
122     PendingTask task = delayed_tasks_.top();
123     delayed_tasks_.pop();
124     task.task.Run();
125   }
126 }
127
128 void RunLoop::Quit() {
129   assert(current() == this);
130   if (run_state_)
131     run_state_->should_quit = true;
132 }
133
134 void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) {
135   assert(current() == this);
136   MojoTimeTicks run_time = delay + GetTimeTicksNow();
137   delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++));
138 }
139
140 bool RunLoop::Wait(bool non_blocking) {
141   const WaitState wait_state = GetWaitState(non_blocking);
142   if (wait_state.handles.empty() && delayed_tasks_.empty()) {
143     Quit();
144     return false;
145   }
146
147   const MojoResult result = WaitMany(wait_state.handles,
148                                      wait_state.handle_signals,
149                                      wait_state.deadline);
150   if (result >= 0) {
151     const size_t index = static_cast<size_t>(result);
152     assert(handler_data_.find(wait_state.handles[index]) !=
153            handler_data_.end());
154     handler_data_[wait_state.handles[index]].handler->OnHandleReady(
155         wait_state.handles[index]);
156     return true;
157   }
158
159   switch (result) {
160     case MOJO_RESULT_INVALID_ARGUMENT:
161     case MOJO_RESULT_FAILED_PRECONDITION:
162       return RemoveFirstInvalidHandle(wait_state);
163     case MOJO_RESULT_DEADLINE_EXCEEDED:
164       return NotifyDeadlineExceeded();
165   }
166
167   assert(false);
168   return false;
169 }
170
171 bool RunLoop::NotifyDeadlineExceeded() {
172   bool notified = false;
173
174   // Make a copy in case someone tries to add/remove new handlers as part of
175   // notifying.
176   const HandleToHandlerData cloned_handlers(handler_data_);
177   const MojoTimeTicks now(GetTimeTicksNow());
178   for (HandleToHandlerData::const_iterator i = cloned_handlers.begin();
179        i != cloned_handlers.end(); ++i) {
180     // Since we're iterating over a clone of the handlers, verify the handler is
181     // still valid before notifying.
182     if (i->second.deadline != kInvalidTimeTicks &&
183         i->second.deadline < now &&
184         handler_data_.find(i->first) != handler_data_.end() &&
185         handler_data_[i->first].id == i->second.id) {
186       handler_data_.erase(i->first);
187       i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED);
188       notified = true;
189     }
190   }
191
192   return notified;
193 }
194
195 bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
196   for (size_t i = 0; i < wait_state.handles.size(); ++i) {
197     const MojoResult result =
198         mojo::Wait(wait_state.handles[i], wait_state.handle_signals[i],
199                    static_cast<MojoDeadline>(0));
200     if (result == MOJO_RESULT_INVALID_ARGUMENT ||
201         result == MOJO_RESULT_FAILED_PRECONDITION) {
202       // Remove the handle first, this way if OnHandleError() tries to remove
203       // the handle our iterator isn't invalidated.
204       assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end());
205       RunLoopHandler* handler =
206           handler_data_[wait_state.handles[i]].handler;
207       handler_data_.erase(wait_state.handles[i]);
208       handler->OnHandleError(wait_state.handles[i], result);
209       return true;
210     }
211     assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
212   }
213   return false;
214 }
215
216 RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
217   WaitState wait_state;
218   MojoTimeTicks min_time = kInvalidTimeTicks;
219   for (HandleToHandlerData::const_iterator i = handler_data_.begin();
220        i != handler_data_.end(); ++i) {
221     wait_state.handles.push_back(i->first);
222     wait_state.handle_signals.push_back(i->second.handle_signals);
223     if (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
224         (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
225       min_time = i->second.deadline;
226     }
227   }
228   if (!delayed_tasks_.empty()) {
229     MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time;
230     if (min_time == kInvalidTimeTicks)
231       min_time = delayed_min_time;
232     else
233       min_time = std::min(min_time, delayed_min_time);
234   }
235   if (non_blocking) {
236     wait_state.deadline = static_cast<MojoDeadline>(0);
237   } else if (min_time != kInvalidTimeTicks) {
238     const MojoTimeTicks now = GetTimeTicksNow();
239     if (min_time < now)
240       wait_state.deadline = static_cast<MojoDeadline>(0);
241     else
242       wait_state.deadline = static_cast<MojoDeadline>(min_time - now);
243   }
244   return wait_state;
245 }
246
247 RunLoop::PendingTask::PendingTask(const Closure& task,
248                                   MojoTimeTicks run_time,
249                                   uint64_t sequence_number)
250     : task(task), run_time(run_time), sequence_number(sequence_number) {
251 }
252
253 RunLoop::PendingTask::~PendingTask() {
254 }
255
256 bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const {
257   if (run_time != other.run_time) {
258     // std::priority_queue<> puts the least element at the end of the queue. We
259     // want the soonest eligible task to be at the head of the queue, so
260     // run_times further in the future are considered lesser.
261     return run_time > other.run_time;
262   }
263
264   return sequence_number > other.sequence_number;
265 }
266
267 }  // namespace mojo