|
1 // Copyright (c) 2008 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 "base/message_pump_glib.h" |
|
6 |
|
7 #include <fcntl.h> |
|
8 #include <math.h> |
|
9 |
|
10 #include <gtk/gtk.h> |
|
11 #include <glib.h> |
|
12 |
|
13 #include "base/eintr_wrapper.h" |
|
14 #include "base/logging.h" |
|
15 #include "base/platform_thread.h" |
|
16 |
|
17 namespace { |
|
18 |
|
19 // We send a byte across a pipe to wakeup the event loop. |
|
20 const char kWorkScheduled = '\0'; |
|
21 |
|
22 // Return a timeout suitable for the glib loop, -1 to block forever, |
|
23 // 0 to return right away, or a timeout in milliseconds from now. |
|
24 int GetTimeIntervalMilliseconds(const base::TimeTicks& from) { |
|
25 if (from.is_null()) |
|
26 return -1; |
|
27 |
|
28 // Be careful here. TimeDelta has a precision of microseconds, but we want a |
|
29 // value in milliseconds. If there are 5.5ms left, should the delay be 5 or |
|
30 // 6? It should be 6 to avoid executing delayed work too early. |
|
31 int delay = static_cast<int>( |
|
32 ceil((from - base::TimeTicks::Now()).InMillisecondsF())); |
|
33 |
|
34 // If this value is negative, then we need to run delayed work soon. |
|
35 return delay < 0 ? 0 : delay; |
|
36 } |
|
37 |
|
38 // A brief refresher on GLib: |
|
39 // GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize. |
|
40 // On each iteration of the GLib pump, it calls each source's Prepare function. |
|
41 // This function should return TRUE if it wants GLib to call its Dispatch, and |
|
42 // FALSE otherwise. It can also set a timeout in this case for the next time |
|
43 // Prepare should be called again (it may be called sooner). |
|
44 // After the Prepare calls, GLib does a poll to check for events from the |
|
45 // system. File descriptors can be attached to the sources. The poll may block |
|
46 // if none of the Prepare calls returned TRUE. It will block indefinitely, or |
|
47 // by the minimum time returned by a source in Prepare. |
|
48 // After the poll, GLib calls Check for each source that returned FALSE |
|
49 // from Prepare. The return value of Check has the same meaning as for Prepare, |
|
50 // making Check a second chance to tell GLib we are ready for Dispatch. |
|
51 // Finally, GLib calls Dispatch for each source that is ready. If Dispatch |
|
52 // returns FALSE, GLib will destroy the source. Dispatch calls may be recursive |
|
53 // (i.e., you can call Run from them), but Prepare and Check cannot. |
|
54 // Finalize is called when the source is destroyed. |
|
55 // NOTE: It is common for subsytems to want to process pending events while |
|
56 // doing intensive work, for example the flash plugin. They usually use the |
|
57 // following pattern (recommended by the GTK docs): |
|
58 // while (gtk_events_pending()) { |
|
59 // gtk_main_iteration(); |
|
60 // } |
|
61 // |
|
62 // gtk_events_pending just calls g_main_context_pending, which does the |
|
63 // following: |
|
64 // - Call prepare on all the sources. |
|
65 // - Do the poll with a timeout of 0 (not blocking). |
|
66 // - Call check on all the sources. |
|
67 // - *Does not* call dispatch on the sources. |
|
68 // - Return true if any of prepare() or check() returned true. |
|
69 // |
|
70 // gtk_main_iteration just calls g_main_context_iteration, which does the whole |
|
71 // thing, respecting the timeout for the poll (and block, although it is |
|
72 // expected not to if gtk_events_pending returned true), and call dispatch. |
|
73 // |
|
74 // Thus it is important to only return true from prepare or check if we |
|
75 // actually have events or work to do. We also need to make sure we keep |
|
76 // internal state consistent so that if prepare/check return true when called |
|
77 // from gtk_events_pending, they will still return true when called right |
|
78 // after, from gtk_main_iteration. |
|
79 // |
|
80 // For the GLib pump we try to follow the Windows UI pump model: |
|
81 // - Whenever we receive a wakeup event or the timer for delayed work expires, |
|
82 // we run DoWork and/or DoDelayedWork. That part will also run in the other |
|
83 // event pumps. |
|
84 // - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main |
|
85 // loop, around event handling. |
|
86 |
|
87 struct WorkSource : public GSource { |
|
88 base::MessagePumpForUI* pump; |
|
89 }; |
|
90 |
|
91 gboolean WorkSourcePrepare(GSource* source, |
|
92 gint* timeout_ms) { |
|
93 *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare(); |
|
94 // We always return FALSE, so that our timeout is honored. If we were |
|
95 // to return TRUE, the timeout would be considered to be 0 and the poll |
|
96 // would never block. Once the poll is finished, Check will be called. |
|
97 return FALSE; |
|
98 } |
|
99 |
|
100 gboolean WorkSourceCheck(GSource* source) { |
|
101 // Only return TRUE if Dispatch should be called. |
|
102 return static_cast<WorkSource*>(source)->pump->HandleCheck(); |
|
103 } |
|
104 |
|
105 gboolean WorkSourceDispatch(GSource* source, |
|
106 GSourceFunc unused_func, |
|
107 gpointer unused_data) { |
|
108 |
|
109 static_cast<WorkSource*>(source)->pump->HandleDispatch(); |
|
110 // Always return TRUE so our source stays registered. |
|
111 return TRUE; |
|
112 } |
|
113 |
|
114 // I wish these could be const, but g_source_new wants non-const. |
|
115 GSourceFuncs WorkSourceFuncs = { |
|
116 WorkSourcePrepare, |
|
117 WorkSourceCheck, |
|
118 WorkSourceDispatch, |
|
119 NULL |
|
120 }; |
|
121 |
|
122 } // namespace |
|
123 |
|
124 |
|
125 namespace base { |
|
126 |
|
127 MessagePumpForUI::MessagePumpForUI() |
|
128 : state_(NULL), |
|
129 context_(g_main_context_default()), |
|
130 wakeup_gpollfd_(new GPollFD) { |
|
131 // Create our wakeup pipe, which is used to flag when work was scheduled. |
|
132 int fds[2]; |
|
133 CHECK(pipe(fds) == 0); |
|
134 wakeup_pipe_read_ = fds[0]; |
|
135 wakeup_pipe_write_ = fds[1]; |
|
136 wakeup_gpollfd_->fd = wakeup_pipe_read_; |
|
137 wakeup_gpollfd_->events = G_IO_IN; |
|
138 |
|
139 work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); |
|
140 static_cast<WorkSource*>(work_source_)->pump = this; |
|
141 g_source_add_poll(work_source_, wakeup_gpollfd_.get()); |
|
142 // Use a low priority so that we let other events in the queue go first. |
|
143 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); |
|
144 // This is needed to allow Run calls inside Dispatch. |
|
145 g_source_set_can_recurse(work_source_, TRUE); |
|
146 g_source_attach(work_source_, context_); |
|
147 gdk_event_handler_set(&EventDispatcher, this, NULL); |
|
148 } |
|
149 |
|
150 MessagePumpForUI::~MessagePumpForUI() { |
|
151 gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), |
|
152 this, NULL); |
|
153 g_source_destroy(work_source_); |
|
154 g_source_unref(work_source_); |
|
155 close(wakeup_pipe_read_); |
|
156 close(wakeup_pipe_write_); |
|
157 } |
|
158 |
|
159 void MessagePumpForUI::RunWithDispatcher(Delegate* delegate, |
|
160 Dispatcher* dispatcher) { |
|
161 #ifndef NDEBUG |
|
162 // Make sure we only run this on one thread. GTK only has one message pump |
|
163 // so we can only have one UI loop per process. |
|
164 static PlatformThreadId thread_id = PlatformThread::CurrentId(); |
|
165 DCHECK(thread_id == PlatformThread::CurrentId()) << |
|
166 "Running MessagePumpForUI on two different threads; " |
|
167 "this is unsupported by GLib!"; |
|
168 #endif |
|
169 |
|
170 RunState state; |
|
171 state.delegate = delegate; |
|
172 state.dispatcher = dispatcher; |
|
173 state.should_quit = false; |
|
174 state.run_depth = state_ ? state_->run_depth + 1 : 1; |
|
175 state.has_work = false; |
|
176 |
|
177 RunState* previous_state = state_; |
|
178 state_ = &state; |
|
179 |
|
180 // We really only do a single task for each iteration of the loop. If we |
|
181 // have done something, assume there is likely something more to do. This |
|
182 // will mean that we don't block on the message pump until there was nothing |
|
183 // more to do. We also set this to true to make sure not to block on the |
|
184 // first iteration of the loop, so RunAllPending() works correctly. |
|
185 bool more_work_is_plausible = true; |
|
186 |
|
187 // We run our own loop instead of using g_main_loop_quit in one of the |
|
188 // callbacks. This is so we only quit our own loops, and we don't quit |
|
189 // nested loops run by others. TODO(deanm): Is this what we want? |
|
190 for (;;) { |
|
191 // Don't block if we think we have more work to do. |
|
192 bool block = !more_work_is_plausible; |
|
193 |
|
194 // g_main_context_iteration returns true if events have been dispatched. |
|
195 more_work_is_plausible = g_main_context_iteration(context_, block); |
|
196 if (state_->should_quit) |
|
197 break; |
|
198 |
|
199 more_work_is_plausible |= state_->delegate->DoWork(); |
|
200 if (state_->should_quit) |
|
201 break; |
|
202 |
|
203 more_work_is_plausible |= |
|
204 state_->delegate->DoDelayedWork(&delayed_work_time_); |
|
205 if (state_->should_quit) |
|
206 break; |
|
207 |
|
208 if (more_work_is_plausible) |
|
209 continue; |
|
210 |
|
211 more_work_is_plausible = state_->delegate->DoIdleWork(); |
|
212 if (state_->should_quit) |
|
213 break; |
|
214 } |
|
215 |
|
216 state_ = previous_state; |
|
217 } |
|
218 |
|
219 // Return the timeout we want passed to poll. |
|
220 int MessagePumpForUI::HandlePrepare() { |
|
221 // We know we have work, but we haven't called HandleDispatch yet. Don't let |
|
222 // the pump block so that we can do some processing. |
|
223 if (state_ && // state_ may be null during tests. |
|
224 state_->has_work) |
|
225 return 0; |
|
226 |
|
227 // We don't think we have work to do, but make sure not to block |
|
228 // longer than the next time we need to run delayed work. |
|
229 return GetTimeIntervalMilliseconds(delayed_work_time_); |
|
230 } |
|
231 |
|
232 bool MessagePumpForUI::HandleCheck() { |
|
233 if (!state_) // state_ may be null during tests. |
|
234 return false; |
|
235 |
|
236 // We should only ever have a single message on the wakeup pipe, since we |
|
237 // are only signaled when the queue went from empty to non-empty. The glib |
|
238 // poll will tell us whether there was data, so this read shouldn't block. |
|
239 if (wakeup_gpollfd_->revents & G_IO_IN) { |
|
240 char msg; |
|
241 if (HANDLE_EINTR(read(wakeup_pipe_read_, &msg, 1)) != 1 || msg != '!') { |
|
242 NOTREACHED() << "Error reading from the wakeup pipe."; |
|
243 } |
|
244 // Since we ate the message, we need to record that we have more work, |
|
245 // because HandleCheck() may be called without HandleDispatch being called |
|
246 // afterwards. |
|
247 state_->has_work = true; |
|
248 } |
|
249 |
|
250 if (state_->has_work) |
|
251 return true; |
|
252 |
|
253 if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) { |
|
254 // The timer has expired. That condition will stay true until we process |
|
255 // that delayed work, so we don't need to record this differently. |
|
256 return true; |
|
257 } |
|
258 |
|
259 return false; |
|
260 } |
|
261 |
|
262 void MessagePumpForUI::HandleDispatch() { |
|
263 state_->has_work = false; |
|
264 if (state_->delegate->DoWork()) { |
|
265 // NOTE: on Windows at this point we would call ScheduleWork (see |
|
266 // MessagePumpForUI::HandleWorkMessage in message_pump_win.cc). But here, |
|
267 // instead of posting a message on the wakeup pipe, we can avoid the |
|
268 // syscalls and just signal that we have more work. |
|
269 state_->has_work = true; |
|
270 } |
|
271 |
|
272 if (state_->should_quit) |
|
273 return; |
|
274 |
|
275 state_->delegate->DoDelayedWork(&delayed_work_time_); |
|
276 } |
|
277 |
|
278 void MessagePumpForUI::AddObserver(Observer* observer) { |
|
279 observers_.AddObserver(observer); |
|
280 } |
|
281 |
|
282 void MessagePumpForUI::RemoveObserver(Observer* observer) { |
|
283 observers_.RemoveObserver(observer); |
|
284 } |
|
285 |
|
286 void MessagePumpForUI::WillProcessEvent(GdkEvent* event) { |
|
287 FOR_EACH_OBSERVER(Observer, observers_, WillProcessEvent(event)); |
|
288 } |
|
289 |
|
290 void MessagePumpForUI::DidProcessEvent(GdkEvent* event) { |
|
291 FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event)); |
|
292 } |
|
293 |
|
294 void MessagePumpForUI::Quit() { |
|
295 if (state_) { |
|
296 state_->should_quit = true; |
|
297 } else { |
|
298 NOTREACHED() << "Quit called outside Run!"; |
|
299 } |
|
300 } |
|
301 |
|
302 void MessagePumpForUI::ScheduleWork() { |
|
303 // This can be called on any thread, so we don't want to touch any state |
|
304 // variables as we would then need locks all over. This ensures that if |
|
305 // we are sleeping in a poll that we will wake up. |
|
306 char msg = '!'; |
|
307 if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) { |
|
308 NOTREACHED() << "Could not write to the UI message loop wakeup pipe!"; |
|
309 } |
|
310 } |
|
311 |
|
312 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
|
313 // We need to wake up the loop in case the poll timeout needs to be |
|
314 // adjusted. This will cause us to try to do work, but that's ok. |
|
315 delayed_work_time_ = delayed_work_time; |
|
316 ScheduleWork(); |
|
317 } |
|
318 |
|
319 // static |
|
320 void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) { |
|
321 MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data); |
|
322 |
|
323 message_pump->WillProcessEvent(event); |
|
324 if (message_pump->state_ && // state_ may be null during tests. |
|
325 message_pump->state_->dispatcher) { |
|
326 if (!message_pump->state_->dispatcher->Dispatch(event)) |
|
327 message_pump->state_->should_quit = true; |
|
328 } else { |
|
329 gtk_main_do_event(event); |
|
330 } |
|
331 message_pump->DidProcessEvent(event); |
|
332 } |
|
333 |
|
334 } // namespace base |