Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: mojo/public/utility/run_loop.cc

Issue 148013006: Mojo: re-org public/utility and public/environment (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: lower similarity factor Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/utility/run_loop.h"
6
7 #include <assert.h>
8
9 #include <algorithm>
10 #include <vector>
11
12 #include "mojo/public/utility/run_loop_handler.h"
13 #include "mojo/public/utility/thread_local.h"
14
15 namespace mojo {
16 namespace {
17
18 ThreadLocalPointer<RunLoop>* tls_run_loop = NULL;
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<MojoWaitFlags> wait_flags;
30 MojoDeadline deadline;
31 };
32
33 struct RunLoop::RunState {
34 RunState() : should_quit(false) {}
35
36 bool should_quit;
37 };
38
39 RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) {
40 assert(tls_run_loop);
41 assert(!tls_run_loop->Get());
42 tls_run_loop->Set(this);
43 }
44
45 RunLoop::~RunLoop() {
46 assert(tls_run_loop->Get() == this);
47 tls_run_loop->Set(NULL);
48 }
49
50 // static
51 void RunLoop::SetUp() {
52 assert(!tls_run_loop);
53 tls_run_loop = new ThreadLocalPointer<RunLoop>;
54 }
55
56 // static
57 void RunLoop::TearDown() {
58 assert(!current());
59 assert(tls_run_loop);
60 delete tls_run_loop;
61 tls_run_loop = NULL;
62 }
63
64 // static
65 RunLoop* RunLoop::current() {
66 assert(tls_run_loop);
67 return tls_run_loop->Get();
68 }
69
70 void RunLoop::AddHandler(RunLoopHandler* handler,
71 const Handle& handle,
72 MojoWaitFlags wait_flags,
73 MojoDeadline deadline) {
74 assert(current() == this);
75 assert(handler);
76 assert(handle.is_valid());
77 // Assume it's an error if someone tries to reregister an existing handle.
78 assert(0u == handler_data_.count(handle));
79 HandlerData handler_data;
80 handler_data.handler = handler;
81 handler_data.wait_flags = wait_flags;
82 handler_data.deadline = (deadline == MOJO_DEADLINE_INDEFINITE) ?
83 kInvalidTimeTicks :
84 GetTimeTicksNow() + static_cast<MojoTimeTicks>(deadline);
85 handler_data.id = next_handler_id_++;
86 handler_data_[handle] = handler_data;
87 }
88
89 void RunLoop::RemoveHandler(const Handle& handle) {
90 assert(current() == this);
91 handler_data_.erase(handle);
92 }
93
94 bool RunLoop::HasHandler(const Handle& handle) const {
95 return handler_data_.find(handle) != handler_data_.end();
96 }
97
98 void RunLoop::Run() {
99 assert(current() == this);
100 // We don't currently support nesting.
101 assert(!run_state_);
102 RunState* old_state = run_state_;
103 RunState run_state;
104 run_state_ = &run_state;
105 while (!run_state.should_quit)
106 Wait(false);
107 run_state_ = old_state;
108 }
109
110 void RunLoop::RunUntilIdle() {
111 assert(current() == this);
112 // We don't currently support nesting.
113 assert(!run_state_);
114 RunState* old_state = run_state_;
115 RunState run_state;
116 run_state_ = &run_state;
117 while (!run_state.should_quit) {
118 if (!Wait(true))
119 break;
120 }
121 run_state_ = old_state;
122 }
123
124 void RunLoop::Quit() {
125 assert(current() == this);
126 if (run_state_)
127 run_state_->should_quit = true;
128 }
129
130 bool RunLoop::Wait(bool non_blocking) {
131 const WaitState wait_state = GetWaitState(non_blocking);
132 if (wait_state.handles.empty()) {
133 Quit();
134 return false;
135 }
136
137 const MojoResult result =
138 WaitMany(wait_state.handles, wait_state.wait_flags, wait_state.deadline);
139 if (result >= 0) {
140 const size_t index = static_cast<size_t>(result);
141 assert(handler_data_.find(wait_state.handles[index]) !=
142 handler_data_.end());
143 handler_data_[wait_state.handles[index]].handler->OnHandleReady(
144 wait_state.handles[index]);
145 return true;
146 }
147
148 switch (result) {
149 case MOJO_RESULT_INVALID_ARGUMENT:
150 case MOJO_RESULT_FAILED_PRECONDITION:
151 return RemoveFirstInvalidHandle(wait_state);
152 case MOJO_RESULT_DEADLINE_EXCEEDED:
153 return NotifyDeadlineExceeded();
154 }
155
156 assert(false);
157 return false;
158 }
159
160 bool RunLoop::NotifyDeadlineExceeded() {
161 bool notified = false;
162
163 // Make a copy in case someone tries to add/remove new handlers as part of
164 // notifying.
165 const HandleToHandlerData cloned_handlers(handler_data_);
166 const MojoTimeTicks now(GetTimeTicksNow());
167 for (HandleToHandlerData::const_iterator i = cloned_handlers.begin();
168 i != cloned_handlers.end(); ++i) {
169 // Since we're iterating over a clone of the handlers, verify the handler is
170 // still valid before notifying.
171 if (i->second.deadline != kInvalidTimeTicks &&
172 i->second.deadline < now &&
173 handler_data_.find(i->first) != handler_data_.end() &&
174 handler_data_[i->first].id == i->second.id) {
175 handler_data_.erase(i->first);
176 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED);
177 notified = true;
178 }
179 }
180
181 return notified;
182 }
183
184 bool RunLoop::RemoveFirstInvalidHandle(const WaitState& wait_state) {
185 for (size_t i = 0; i < wait_state.handles.size(); ++i) {
186 const MojoResult result =
187 mojo::Wait(wait_state.handles[i], wait_state.wait_flags[i],
188 static_cast<MojoDeadline>(0));
189 if (result == MOJO_RESULT_INVALID_ARGUMENT ||
190 result == MOJO_RESULT_FAILED_PRECONDITION) {
191 // Remove the handle first, this way if OnHandleError() tries to remove
192 // the handle our iterator isn't invalidated.
193 assert(handler_data_.find(wait_state.handles[i]) != handler_data_.end());
194 RunLoopHandler* handler =
195 handler_data_[wait_state.handles[i]].handler;
196 handler_data_.erase(wait_state.handles[i]);
197 handler->OnHandleError(wait_state.handles[i], result);
198 return true;
199 }
200 assert(MOJO_RESULT_DEADLINE_EXCEEDED == result);
201 }
202 return false;
203 }
204
205 RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
206 WaitState wait_state;
207 MojoTimeTicks min_time = kInvalidTimeTicks;
208 for (HandleToHandlerData::const_iterator i = handler_data_.begin();
209 i != handler_data_.end(); ++i) {
210 wait_state.handles.push_back(i->first);
211 wait_state.wait_flags.push_back(i->second.wait_flags);
212 if (!non_blocking && i->second.deadline != kInvalidTimeTicks &&
213 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) {
214 min_time = i->second.deadline;
215 }
216 }
217 if (non_blocking) {
218 wait_state.deadline = static_cast<MojoDeadline>(0);
219 } else if (min_time != kInvalidTimeTicks) {
220 const MojoTimeTicks now = GetTimeTicksNow();
221 if (min_time < now)
222 wait_state.deadline = static_cast<MojoDeadline>(0);
223 else
224 wait_state.deadline = static_cast<MojoDeadline>(min_time - now);
225 }
226 return wait_state;
227 }
228
229 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/utility/lib/thread_local_win.cc ('k') | mojo/public/utility/tests/run_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698