| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 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 | 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_pump_glib.h" | 5 #include "base/message_pump_glib.h" |
| 6 | 6 |
| 7 #include <errno.h> |
| 7 #include <fcntl.h> | 8 #include <fcntl.h> |
| 8 #include <math.h> | 9 #include <math.h> |
| 9 | 10 |
| 10 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/platform_thread.h" | 13 #include "base/platform_thread.h" |
| 14 #include "base/scoped_ptr.h" |
| 13 | 15 |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 16 // We send a byte across a pipe to wakeup the event loop. | 18 // We send a byte across a pipe to wakeup the event loop. |
| 17 const char kWorkScheduled = '\0'; | 19 const char kWorkScheduled = '\0'; |
| 18 | 20 |
| 19 // Return a timeout suitable for the glib loop, -1 to block forever, | 21 // Return a timeout suitable for the glib loop, -1 to block forever, |
| 20 // 0 to return right away, or a timeout in milliseconds from now. | 22 // 0 to return right away, or a timeout in milliseconds from now. |
| 21 int GetTimeIntervalMilliseconds(base::Time from) { | 23 int GetTimeIntervalMilliseconds(base::Time from) { |
| 22 if (from.is_null()) | 24 if (from.is_null()) |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 WorkSourceCheck, | 85 WorkSourceCheck, |
| 84 WorkSourceDispatch, | 86 WorkSourceDispatch, |
| 85 NULL | 87 NULL |
| 86 }; | 88 }; |
| 87 | 89 |
| 88 } // namespace | 90 } // namespace |
| 89 | 91 |
| 90 | 92 |
| 91 namespace base { | 93 namespace base { |
| 92 | 94 |
| 95 // static |
| 96 Lock MessagePumpForUI::glib_main_loop_lock_; |
| 97 |
| 93 MessagePumpForUI::MessagePumpForUI() | 98 MessagePumpForUI::MessagePumpForUI() |
| 94 : state_(NULL), | 99 : state_(NULL), |
| 95 context_(g_main_context_default()) { | 100 context_(g_main_context_default()) { |
| 96 // Create our wakeup pipe, which is used to flag when work was scheduled. | 101 // Create our wakeup pipe, which is used to flag when work was scheduled. |
| 97 int fds[2]; | 102 int fds[2]; |
| 98 CHECK(pipe(fds) == 0); | 103 CHECK(pipe(fds) == 0); |
| 99 wakeup_pipe_read_ = fds[0]; | 104 wakeup_pipe_read_ = fds[0]; |
| 100 wakeup_pipe_write_ = fds[1]; | 105 wakeup_pipe_write_ = fds[1]; |
| 101 wakeup_gpollfd_.fd = wakeup_pipe_read_; | 106 wakeup_gpollfd_.fd = wakeup_pipe_read_; |
| 102 wakeup_gpollfd_.events = G_IO_IN; | 107 wakeup_gpollfd_.events = G_IO_IN; |
| 103 | 108 |
| 104 work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); | 109 work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); |
| 105 static_cast<WorkSource*>(work_source_)->pump = this; | 110 static_cast<WorkSource*>(work_source_)->pump = this; |
| 106 g_source_add_poll(work_source_, &wakeup_gpollfd_); | 111 g_source_add_poll(work_source_, &wakeup_gpollfd_); |
| 107 // Use a low priority so that we let other events in the queue go first. | 112 // Use a low priority so that we let other events in the queue go first. |
| 108 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); | 113 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); |
| 109 // This is needed to allow Run calls inside Dispatch. | 114 // This is needed to allow Run calls inside Dispatch. |
| 110 g_source_set_can_recurse(work_source_, TRUE); | 115 g_source_set_can_recurse(work_source_, TRUE); |
| 111 g_source_attach(work_source_, context_); | 116 g_source_attach(work_source_, context_); |
| 112 } | 117 } |
| 113 | 118 |
| 114 MessagePumpForUI::~MessagePumpForUI() { | 119 MessagePumpForUI::~MessagePumpForUI() { |
| 115 g_source_destroy(work_source_); | 120 g_source_destroy(work_source_); |
| 116 g_source_unref(work_source_); | 121 g_source_unref(work_source_); |
| 117 close(wakeup_pipe_read_); | 122 close(wakeup_pipe_read_); |
| 118 close(wakeup_pipe_write_); | 123 close(wakeup_pipe_write_); |
| 119 } | 124 } |
| 120 | 125 |
| 126 // Runs a glib main loop iteration. Grabs glib_main_loop_lock_ while |
| 127 // calling glib functions, but releases it while polling. |
| 128 static void GMainIterate(GMainContext* context) { |
| 129 AutoLock locked(MessagePumpForUI::glib_main_loop_lock_); |
| 130 int fds_array_size = 50; |
| 131 scoped_array<GPollFD> fds(new GPollFD[fds_array_size]); |
| 132 |
| 133 // We use the lower-level component functions and do the poll |
| 134 // ourselves so that we can release glib_main_loop_lock_ while |
| 135 // polling, otherwise waiters might starve. |
| 136 |
| 137 // I'll assume no other thread will g_main_context_acquire the |
| 138 // context away from this thread. We cannot g_main_context_wait as |
| 139 // we can't get to the condition and mutex in the context (which is |
| 140 // externally opaque). |
| 141 |
| 142 gint max_priority, timeout; |
| 143 g_main_context_prepare(context, &max_priority); |
| 144 int number_of_fds = g_main_context_query(context, max_priority, &timeout, |
| 145 fds.get(), fds_array_size); |
| 146 // We could reallocate instead, then we'd want to cache the array size... |
| 147 CHECK(number_of_fds <= fds_array_size); |
| 148 GPollFunc poll_func = g_main_context_get_poll_func(context); |
| 149 |
| 150 { |
| 151 // Release the lock while polling |
| 152 AutoUnlock locked(MessagePumpForUI::glib_main_loop_lock_); |
| 153 |
| 154 if ((*poll_func) (fds.get(), number_of_fds, timeout) < 0) { |
| 155 if (errno != EINTR) |
| 156 LOG(ERROR) << "g_main_loop poll error: " << strerror(errno); |
| 157 // Just carry on. |
| 158 } |
| 159 } |
| 160 |
| 161 g_main_context_check(context, max_priority, fds.get(), number_of_fds); |
| 162 g_main_context_dispatch(context); |
| 163 } |
| 164 |
| 121 void MessagePumpForUI::Run(Delegate* delegate) { | 165 void MessagePumpForUI::Run(Delegate* delegate) { |
| 122 #ifndef NDEBUG | 166 #ifndef NDEBUG |
| 123 // Make sure we only run this on one thread. GTK only has one message pump | 167 // Make sure we only run this on one thread. GTK only has one message pump |
| 124 // so we can only have one UI loop per process. | 168 // so we can only have one UI loop per process. |
| 125 static PlatformThreadId thread_id = PlatformThread::CurrentId(); | 169 static PlatformThreadId thread_id = PlatformThread::CurrentId(); |
| 126 DCHECK(thread_id == PlatformThread::CurrentId()) << | 170 DCHECK(thread_id == PlatformThread::CurrentId()) << |
| 127 "Running MessagePumpForUI on two different threads; " | 171 "Running MessagePumpForUI on two different threads; " |
| 128 "this is unsupported by GLib!"; | 172 "this is unsupported by GLib!"; |
| 129 #endif | 173 #endif |
| 130 | 174 |
| 131 RunState state; | 175 RunState state; |
| 132 state.delegate = delegate; | 176 state.delegate = delegate; |
| 133 state.should_quit = false; | 177 state.should_quit = false; |
| 134 state.run_depth = state_ ? state_->run_depth + 1 : 1; | 178 state.run_depth = state_ ? state_->run_depth + 1 : 1; |
| 135 // We really only do a single task for each iteration of the loop. If we | 179 // We really only do a single task for each iteration of the loop. If we |
| 136 // have done something, assume there is likely something more to do. This | 180 // have done something, assume there is likely something more to do. This |
| 137 // will mean that we don't block on the message pump until there was nothing | 181 // will mean that we don't block on the message pump until there was nothing |
| 138 // more to do. We also set this to true to make sure not to block on the | 182 // more to do. We also set this to true to make sure not to block on the |
| 139 // first iteration of the loop, so RunAllPending() works correctly. | 183 // first iteration of the loop, so RunAllPending() works correctly. |
| 140 state.more_work_is_plausible = true; | 184 state.more_work_is_plausible = true; |
| 141 | 185 |
| 142 RunState* previous_state = state_; | 186 RunState* previous_state = state_; |
| 143 state_ = &state; | 187 state_ = &state; |
| 144 | 188 |
| 145 // We run our own loop instead of using g_main_loop_quit in one of the | 189 // We run our own loop instead of using g_main_loop_quit in one of the |
| 146 // callbacks. This is so we only quit our own loops, and we don't quit | 190 // callbacks. This is so we only quit our own loops, and we don't quit |
| 147 // nested loops run by others. TODO(deanm): Is this what we want? | 191 // nested loops run by others. TODO(deanm): Is this what we want? |
| 148 while (!state_->should_quit) | 192 while (!state_->should_quit) |
| 149 g_main_context_iteration(context_, true); | 193 GMainIterate(context_); |
| 150 | 194 |
| 151 state_ = previous_state; | 195 state_ = previous_state; |
| 152 } | 196 } |
| 153 | 197 |
| 154 // Return the timeout we want passed to poll. | 198 // Return the timeout we want passed to poll. |
| 155 int MessagePumpForUI::HandlePrepare() { | 199 int MessagePumpForUI::HandlePrepare() { |
| 156 // If it's likely that we have more work, don't let the pump | 200 // If it's likely that we have more work, don't let the pump |
| 157 // block so that we can do some processing. | 201 // block so that we can do some processing. |
| 158 if (state_->more_work_is_plausible) | 202 if (state_->more_work_is_plausible) |
| 159 return 0; | 203 return 0; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 } | 272 } |
| 229 | 273 |
| 230 void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { | 274 void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { |
| 231 // We need to wake up the loop in case the poll timeout needs to be | 275 // We need to wake up the loop in case the poll timeout needs to be |
| 232 // adjusted. This will cause us to try to do work, but that's ok. | 276 // adjusted. This will cause us to try to do work, but that's ok. |
| 233 delayed_work_time_ = delayed_work_time; | 277 delayed_work_time_ = delayed_work_time; |
| 234 ScheduleWork(); | 278 ScheduleWork(); |
| 235 } | 279 } |
| 236 | 280 |
| 237 } // namespace base | 281 } // namespace base |
| OLD | NEW |