OLD | NEW |
(Empty) | |
| 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 "base/lazy_instance.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/platform_thread.h" |
| 13 |
| 14 namespace base { |
| 15 |
| 16 static const char kWorkScheduled = '\0'; |
| 17 static const char kDelayedWorkScheduled = '\1'; |
| 18 |
| 19 // I wish these could be const, but g_source_new wants a non-const GSourceFunc |
| 20 // pointer. |
| 21 |
| 22 // static |
| 23 GSourceFuncs MessagePumpForUI::WorkSourceFuncs = { |
| 24 WorkSourcePrepare, |
| 25 WorkSourceCheck, |
| 26 WorkSourceDispatch, |
| 27 NULL |
| 28 }; |
| 29 |
| 30 // static |
| 31 GSourceFuncs MessagePumpForUI::IdleSourceFuncs = { |
| 32 IdleSourcePrepare, |
| 33 IdleSourceCheck, |
| 34 IdleSourceDispatch, |
| 35 NULL |
| 36 }; |
| 37 |
| 38 static int GetTimeIntervalMilliseconds(Time from) { |
| 39 if (from.is_null()) |
| 40 return -1; |
| 41 |
| 42 // Be careful here. TimeDelta has a precision of microseconds, but we want a |
| 43 // value in milliseconds. If there are 5.5ms left, should the delay be 5 or |
| 44 // 6? It should be 6 to avoid executing delayed work too early. |
| 45 double timeout = ceil((from - Time::Now()).InMillisecondsF()); |
| 46 |
| 47 // If this value is negative, then we need to run delayed work soon. |
| 48 int delay = static_cast<int>(timeout); |
| 49 if (delay < 0) |
| 50 delay = 0; |
| 51 |
| 52 return delay; |
| 53 } |
| 54 |
| 55 MessagePumpForUI::MessagePumpForUI() |
| 56 : state_(NULL), |
| 57 context_(g_main_context_default()) { |
| 58 // Create a pipe with a non-blocking read end for use by ScheduleWork to |
| 59 // break us out of a poll. Create the work source and attach the file |
| 60 // descriptor to it. |
| 61 int pipe_fd[2]; |
| 62 CHECK(0 == pipe(pipe_fd)) << "Could not create pipe!"; |
| 63 write_fd_work_scheduled_ = pipe_fd[1]; |
| 64 read_fd_work_scheduled_ = pipe_fd[0]; |
| 65 int flags = fcntl(read_fd_work_scheduled_, F_GETFL, 0); |
| 66 if (-1 == flags) |
| 67 flags = 0; |
| 68 CHECK(0 == fcntl(read_fd_work_scheduled_, F_SETFL, flags | O_NONBLOCK)) << |
| 69 "Could not set file descriptor to non-blocking!"; |
| 70 GPollFD poll_fd; |
| 71 poll_fd.fd = read_fd_work_scheduled_; |
| 72 poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; |
| 73 work_source_ = AddSource(&WorkSourceFuncs, G_PRIORITY_DEFAULT, &poll_fd); |
| 74 } |
| 75 |
| 76 MessagePumpForUI::~MessagePumpForUI() { |
| 77 close(read_fd_work_scheduled_); |
| 78 close(write_fd_work_scheduled_); |
| 79 g_source_destroy(work_source_); |
| 80 g_source_unref(work_source_); |
| 81 } |
| 82 |
| 83 struct ThreadIdTraits { |
| 84 static void New(void* instance) { |
| 85 int* thread_id = static_cast<int*>(instance); |
| 86 *thread_id = PlatformThread::CurrentId(); |
| 87 } |
| 88 static void Delete(void* instance) { |
| 89 } |
| 90 }; |
| 91 |
| 92 void MessagePumpForUI::Run(Delegate* delegate) { |
| 93 // Make sure we only run this on one thread. GTK only has one message pump |
| 94 // so we can only have one UI loop per process. |
| 95 static LazyInstance<int, ThreadIdTraits> thread_id(base::LINKER_INITIALIZED); |
| 96 DCHECK(thread_id.Get() == PlatformThread::CurrentId()) << |
| 97 "Running MessagePumpForUI on two different threads; " |
| 98 "this is unsupported by GLib!"; |
| 99 |
| 100 RunState state; |
| 101 state.delegate = delegate; |
| 102 state.keep_running = true; |
| 103 // We emulate the behavior of MessagePumpDefault and try to do work at once. |
| 104 state.should_do_work = true; |
| 105 state.should_do_idle_work = false; |
| 106 state.idle_source = NULL; |
| 107 |
| 108 RunState* previous_state = state_; |
| 109 state_ = &state; |
| 110 |
| 111 while (state.keep_running) |
| 112 g_main_context_iteration(context_, true); |
| 113 |
| 114 if (state.idle_source) { |
| 115 // This removes the source from the context and releases GLib's hold on it. |
| 116 g_source_destroy(state.idle_source); |
| 117 // This releases our hold and destroys the source. |
| 118 g_source_unref(state.idle_source); |
| 119 } |
| 120 |
| 121 state_ = previous_state; |
| 122 } |
| 123 |
| 124 void MessagePumpForUI::Quit() { |
| 125 DCHECK(state_) << "Quit called outside Run!"; |
| 126 state_->keep_running = false; |
| 127 } |
| 128 |
| 129 void MessagePumpForUI::ScheduleWork() { |
| 130 // This can be called on any thread, so we don't want to touch any state |
| 131 // variables as we would then need locks all over. This ensures that if |
| 132 // we are sleeping in a poll that we will wake up, and we check the pipe |
| 133 // so we know when work was scheduled. |
| 134 CHECK(1 == write(write_fd_work_scheduled_, &kWorkScheduled, 1)) << |
| 135 "Could not write to pipe!"; |
| 136 } |
| 137 |
| 138 void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { |
| 139 delayed_work_time_ = delayed_work_time; |
| 140 // This is an optimization. Delayed work may not be imminent, we may just |
| 141 // need to update our timeout to poll. Hence we don't want to go overkill |
| 142 // with kWorkScheduled. |
| 143 CHECK(1 == write(write_fd_work_scheduled_, &kDelayedWorkScheduled, 1)) << |
| 144 "Could not write to pipe!"; |
| 145 } |
| 146 |
| 147 // A brief refresher on GLib: |
| 148 // GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize. |
| 149 // On each iteration of the GLib pump, it calls each source's Prepare function. |
| 150 // This function should return TRUE if it wants GLib to call its Dispatch, and |
| 151 // FALSE otherwise. It can also set a timeout in this case for the next time |
| 152 // Prepare should be called again (it may be called sooner). |
| 153 // After the Prepare calls, GLib does a poll to check for events from the |
| 154 // system. File descriptors can be attached to the sources. The poll may block |
| 155 // if none of the Prepare calls returned TRUE. It will block indefinitely, or |
| 156 // by the minimum time returned by a source in Prepare. |
| 157 // After the poll, GLib calls Check for each source that returned FALSE |
| 158 // from Prepare. The return value of Check has the same meaning as for Prepare, |
| 159 // making Check a second chance to tell GLib we are ready for Dispatch. |
| 160 // Finally, GLib calls Dispatch for each source that is ready. If Dispatch |
| 161 // returns FALSE, GLib will destroy the source. Dispatch calls may be recursive |
| 162 // (i.e., you can call Run from them), but Prepare and Check cannot. |
| 163 // Finalize is called when the source is destroyed. |
| 164 |
| 165 // static |
| 166 gboolean MessagePumpForUI::WorkSourcePrepare(GSource* source, |
| 167 gint* timeout_ms) { |
| 168 MessagePumpForUI* self = static_cast<WorkSource*>(source)->self; |
| 169 RunState* state = self->state_; |
| 170 |
| 171 if (state->should_do_work) { |
| 172 state->should_do_idle_work = false; |
| 173 *timeout_ms = 0; |
| 174 return TRUE; |
| 175 } |
| 176 |
| 177 *timeout_ms = GetTimeIntervalMilliseconds(self->delayed_work_time_); |
| 178 |
| 179 state->should_do_idle_work = true; |
| 180 // We want to do idle work right before poll goes to sleep. Obviously |
| 181 // we are not currently asleep, but we may be about to since we have |
| 182 // no work to do. If we don't have an idle source ready to go it's |
| 183 // probably because it fired already (or we just started and it hasn't |
| 184 // been added yet) and we should add one for when we are ready. Note |
| 185 // that this new source will get Prepare called on this current pump |
| 186 // iteration since it gets added at the end of the source list. |
| 187 if (!state->idle_source) { |
| 188 state->idle_source = |
| 189 self->AddSource(&IdleSourceFuncs, G_PRIORITY_DEFAULT_IDLE, NULL); |
| 190 } |
| 191 |
| 192 return FALSE; |
| 193 } |
| 194 |
| 195 // static |
| 196 gboolean MessagePumpForUI::WorkSourceCheck(GSource* source) { |
| 197 MessagePumpForUI* self = static_cast<WorkSource*>(source)->self; |
| 198 RunState* state = self->state_; |
| 199 |
| 200 // Make sure we don't attempt idle work until we are really sure we don't |
| 201 // have other work to do. We'll know this in the call to Prepare. |
| 202 state->should_do_idle_work = false; |
| 203 |
| 204 // Check if ScheduleWork or ScheduleDelayedWork was called. This is a |
| 205 // non-blocking read. |
| 206 char byte; |
| 207 while (0 < read(self->read_fd_work_scheduled_, &byte, 1)) { |
| 208 // Don't assume we actually have work yet unless the stronger ScheduleWork |
| 209 // was called. |
| 210 if (byte == kWorkScheduled) |
| 211 state->should_do_work = true; |
| 212 } |
| 213 |
| 214 if (state->should_do_work) |
| 215 return TRUE; |
| 216 |
| 217 if (!self->delayed_work_time_.is_null()) |
| 218 return self->delayed_work_time_ <= Time::Now(); |
| 219 |
| 220 return FALSE; |
| 221 } |
| 222 |
| 223 // static |
| 224 gboolean MessagePumpForUI::WorkSourceDispatch(GSource* source, |
| 225 GSourceFunc unused_func, |
| 226 gpointer unused_data) { |
| 227 MessagePumpForUI* self = static_cast<WorkSource*>(source)->self; |
| 228 RunState* state = self->state_; |
| 229 DCHECK(!state->should_do_idle_work) << |
| 230 "Idle work should not be flagged while regular work exists."; |
| 231 |
| 232 // Note that in this function we never return FALSE. This source is owned |
| 233 // by GLib and shared by multiple calls to Run. It will only finally get |
| 234 // destroyed when the loop is destroyed. |
| 235 |
| 236 state->should_do_work = state->delegate->DoWork(); |
| 237 if (!state->keep_running) |
| 238 return TRUE; |
| 239 |
| 240 state->should_do_work |= |
| 241 state->delegate->DoDelayedWork(&self->delayed_work_time_); |
| 242 |
| 243 return TRUE; |
| 244 } |
| 245 |
| 246 // static |
| 247 gboolean MessagePumpForUI::IdleSourcePrepare(GSource* source, |
| 248 gint* timeout_ms) { |
| 249 RunState* state = static_cast<WorkSource*>(source)->self->state_; |
| 250 *timeout_ms = 0; |
| 251 return state->should_do_idle_work; |
| 252 } |
| 253 |
| 254 // static |
| 255 gboolean MessagePumpForUI::IdleSourceCheck(GSource* source) { |
| 256 RunState* state = static_cast<WorkSource*>(source)->self->state_; |
| 257 return state->should_do_idle_work; |
| 258 } |
| 259 |
| 260 // static |
| 261 gboolean MessagePumpForUI::IdleSourceDispatch(GSource* source, |
| 262 GSourceFunc unused_func, |
| 263 gpointer unused_data) { |
| 264 RunState* state = static_cast<WorkSource*>(source)->self->state_; |
| 265 // We should not do idle work unless we didn't have other work to do. |
| 266 DCHECK(!state->should_do_work) << "Doing idle work in non-idle time!"; |
| 267 state->should_do_idle_work = false; |
| 268 state->should_do_work = state->delegate->DoIdleWork(); |
| 269 |
| 270 // This is an optimization. We could always remove ourselves right now, |
| 271 // but we will just get re-added when WorkSourceCheck eventually returns |
| 272 // FALSE. |
| 273 if (!state->should_do_work) { |
| 274 // This is so that when we return FALSE, GLib will not only remove us |
| 275 // from the context, but since it holds the last reference, it will |
| 276 // destroy us as well. |
| 277 g_source_unref(source); |
| 278 state->idle_source = NULL; |
| 279 } |
| 280 |
| 281 return state->should_do_work; |
| 282 } |
| 283 |
| 284 GSource* MessagePumpForUI::AddSource(GSourceFuncs* funcs, gint priority, |
| 285 GPollFD *optional_poll_fd) { |
| 286 GSource* source = g_source_new(funcs, sizeof(WorkSource)); |
| 287 |
| 288 // Setting the priority is actually a bit expensive since it causes GLib |
| 289 // to resort an internal list. |
| 290 if (priority != G_PRIORITY_DEFAULT) |
| 291 g_source_set_priority(source, priority); |
| 292 |
| 293 // This is needed to allow Run calls inside Dispatch. |
| 294 g_source_set_can_recurse(source, TRUE); |
| 295 static_cast<WorkSource*>(source)->self = this; |
| 296 |
| 297 if (optional_poll_fd) |
| 298 g_source_add_poll(source, optional_poll_fd); |
| 299 |
| 300 g_source_attach(source, context_); |
| 301 return source; |
| 302 } |
| 303 |
| 304 } // namespace base |
OLD | NEW |