OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_loop/message_pump_glib.h" | 5 #include "base/message_loop/message_pump_glib.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <math.h> | 8 #include <math.h> |
9 | 9 |
10 #include <glib.h> | 10 #include <glib.h> |
11 | 11 |
12 #include "base/lazy_instance.h" | |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/posix/eintr_wrapper.h" | 14 #include "base/posix/eintr_wrapper.h" |
15 #include "base/synchronization/lock.h" | |
14 #include "base/threading/platform_thread.h" | 16 #include "base/threading/platform_thread.h" |
15 | 17 |
16 namespace base { | 18 namespace base { |
17 | 19 |
18 namespace { | 20 namespace { |
19 | 21 |
20 // Return a timeout suitable for the glib loop, -1 to block forever, | 22 // Return a timeout suitable for the glib loop, -1 to block forever, |
21 // 0 to return right away, or a timeout in milliseconds from now. | 23 // 0 to return right away, or a timeout in milliseconds from now. |
22 int GetTimeIntervalMilliseconds(const TimeTicks& from) { | 24 int GetTimeIntervalMilliseconds(const TimeTicks& from) { |
23 if (from.is_null()) | 25 if (from.is_null()) |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 } | 112 } |
111 | 113 |
112 // I wish these could be const, but g_source_new wants non-const. | 114 // I wish these could be const, but g_source_new wants non-const. |
113 GSourceFuncs WorkSourceFuncs = { | 115 GSourceFuncs WorkSourceFuncs = { |
114 WorkSourcePrepare, | 116 WorkSourcePrepare, |
115 WorkSourceCheck, | 117 WorkSourceCheck, |
116 WorkSourceDispatch, | 118 WorkSourceDispatch, |
117 NULL | 119 NULL |
118 }; | 120 }; |
119 | 121 |
122 // The following is used to make sure we only run the MessagePumpGlib on one | |
123 // thread. X only has one message pump so we can only have one UI loop per | |
124 // process. | |
125 #ifndef NDEBUG | |
126 | |
127 // Tracks the pump the most recent pump that has been run. | |
128 struct ThreadInfo { | |
129 // The pump. | |
130 MessagePumpGlib* pump; | |
131 | |
132 // ID of the thread the pump was run on. | |
133 PlatformThreadId thread_id; | |
134 }; | |
135 | |
136 // Used for accesing |thread_info|. | |
137 static LazyInstance<Lock>::Leaky thread_info_lock = LAZY_INSTANCE_INITIALIZER; | |
138 | |
139 // If non-NULL it means a MessagePumpGlib exists and has been Run. This is | |
140 // destroyed when the MessagePump is destroyed. | |
141 ThreadInfo* thread_info = NULL; | |
142 | |
143 void CheckThread(MessagePumpGlib* pump) { | |
144 AutoLock auto_lock(thread_info_lock.Get()); | |
145 if (!thread_info) { | |
146 thread_info = new ThreadInfo; | |
147 thread_info->pump = pump; | |
148 thread_info->thread_id = PlatformThread::CurrentId(); | |
149 } | |
150 DCHECK(thread_info->thread_id == PlatformThread::CurrentId()) << | |
151 "Running MessagePumpGlib on two different threads; " | |
152 "this is unsupported by GLib!"; | |
153 } | |
154 | |
155 void PumpDestroyed(MessagePumpGlib* pump) { | |
156 AutoLock auto_lock(thread_info_lock.Get()); | |
157 if (thread_info && thread_info->pump == pump) { | |
sadrul
2014/05/23 21:29:58
Shouldn't thread_info->pump be always be == pump?
sky
2014/05/23 21:54:37
I believe so, but I wanted to make sure if that is
darin (slow to review)
2014/05/23 23:25:13
You might consider a CHECK here.
Did you consider
sky
2014/05/27 15:57:27
This is all to verify we don't start MessagePumpGl
| |
158 delete thread_info; | |
159 thread_info = NULL; | |
160 } | |
161 } | |
162 | |
163 #endif | |
164 | |
120 } // namespace | 165 } // namespace |
121 | 166 |
122 struct MessagePumpGlib::RunState { | 167 struct MessagePumpGlib::RunState { |
123 Delegate* delegate; | 168 Delegate* delegate; |
124 | 169 |
125 // Used to flag that the current Run() invocation should return ASAP. | 170 // Used to flag that the current Run() invocation should return ASAP. |
126 bool should_quit; | 171 bool should_quit; |
127 | 172 |
128 // Used to count how many Run() invocations are on the stack. | 173 // Used to count how many Run() invocations are on the stack. |
129 int run_depth; | 174 int run_depth; |
(...skipping 23 matching lines...) Expand all Loading... | |
153 static_cast<WorkSource*>(work_source_)->pump = this; | 198 static_cast<WorkSource*>(work_source_)->pump = this; |
154 g_source_add_poll(work_source_, wakeup_gpollfd_.get()); | 199 g_source_add_poll(work_source_, wakeup_gpollfd_.get()); |
155 // Use a low priority so that we let other events in the queue go first. | 200 // Use a low priority so that we let other events in the queue go first. |
156 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); | 201 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); |
157 // This is needed to allow Run calls inside Dispatch. | 202 // This is needed to allow Run calls inside Dispatch. |
158 g_source_set_can_recurse(work_source_, TRUE); | 203 g_source_set_can_recurse(work_source_, TRUE); |
159 g_source_attach(work_source_, context_); | 204 g_source_attach(work_source_, context_); |
160 } | 205 } |
161 | 206 |
162 MessagePumpGlib::~MessagePumpGlib() { | 207 MessagePumpGlib::~MessagePumpGlib() { |
208 #ifndef NDEBUG | |
209 PumpDestroyed(this); | |
210 #endif | |
163 g_source_destroy(work_source_); | 211 g_source_destroy(work_source_); |
164 g_source_unref(work_source_); | 212 g_source_unref(work_source_); |
165 close(wakeup_pipe_read_); | 213 close(wakeup_pipe_read_); |
166 close(wakeup_pipe_write_); | 214 close(wakeup_pipe_write_); |
167 } | 215 } |
168 | 216 |
169 // Return the timeout we want passed to poll. | 217 // Return the timeout we want passed to poll. |
170 int MessagePumpGlib::HandlePrepare() { | 218 int MessagePumpGlib::HandlePrepare() { |
171 // We know we have work, but we haven't called HandleDispatch yet. Don't let | 219 // We know we have work, but we haven't called HandleDispatch yet. Don't let |
172 // the pump block so that we can do some processing. | 220 // the pump block so that we can do some processing. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
225 } | 273 } |
226 | 274 |
227 if (state_->should_quit) | 275 if (state_->should_quit) |
228 return; | 276 return; |
229 | 277 |
230 state_->delegate->DoDelayedWork(&delayed_work_time_); | 278 state_->delegate->DoDelayedWork(&delayed_work_time_); |
231 } | 279 } |
232 | 280 |
233 void MessagePumpGlib::Run(Delegate* delegate) { | 281 void MessagePumpGlib::Run(Delegate* delegate) { |
234 #ifndef NDEBUG | 282 #ifndef NDEBUG |
235 // Make sure we only run this on one thread. X only has one message pump | 283 CheckThread(this); |
236 // so we can only have one UI loop per process. | |
237 static PlatformThreadId thread_id = PlatformThread::CurrentId(); | |
238 DCHECK(thread_id == PlatformThread::CurrentId()) << | |
239 "Running MessagePumpGlib on two different threads; " | |
240 "this is unsupported by GLib!"; | |
241 #endif | 284 #endif |
242 | 285 |
243 RunState state; | 286 RunState state; |
244 state.delegate = delegate; | 287 state.delegate = delegate; |
245 state.should_quit = false; | 288 state.should_quit = false; |
246 state.run_depth = state_ ? state_->run_depth + 1 : 1; | 289 state.run_depth = state_ ? state_->run_depth + 1 : 1; |
247 state.has_work = false; | 290 state.has_work = false; |
248 | 291 |
249 RunState* previous_state = state_; | 292 RunState* previous_state = state_; |
250 state_ = &state; | 293 state_ = &state; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 delayed_work_time_ = delayed_work_time; | 354 delayed_work_time_ = delayed_work_time; |
312 ScheduleWork(); | 355 ScheduleWork(); |
313 } | 356 } |
314 | 357 |
315 bool MessagePumpGlib::ShouldQuit() const { | 358 bool MessagePumpGlib::ShouldQuit() const { |
316 CHECK(state_); | 359 CHECK(state_); |
317 return state_->should_quit; | 360 return state_->should_quit; |
318 } | 361 } |
319 | 362 |
320 } // namespace base | 363 } // namespace base |
OLD | NEW |