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

Side by Side Diff: base/message_pump_glib.cc

Issue 99126: Mutual exclusion between gconf and the glib main loop. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 8 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
« no previous file with comments | « base/message_pump_glib.h ('k') | chrome/app/chrome_dll_main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « base/message_pump_glib.h ('k') | chrome/app/chrome_dll_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698