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

Side by Side Diff: content/browser/power_save_blocker_x11.cc

Issue 1141913002: Make X11 power save suspension calls asynchronous. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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
« no previous file with comments | « no previous file | no next file » | 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) 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 "content/browser/power_save_blocker_impl.h" 5 #include "content/browser/power_save_blocker_impl.h"
6 6
7 #include <X11/Xlib.h> 7 #include <X11/Xlib.h>
8 #include <X11/extensions/dpms.h> 8 #include <X11/extensions/dpms.h>
9 // Xlib #defines Status, but we can't have that for some of our headers. 9 // Xlib #defines Status, but we can't have that for some of our headers.
10 #ifdef Status 10 #ifdef Status
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // enqueues a call back to ApplyBlock() if it is true. See the comments for 86 // enqueues a call back to ApplyBlock() if it is true. See the comments for
87 // enqueue_apply_ below. 87 // enqueue_apply_ below.
88 void InitOnUIThread(); 88 void InitOnUIThread();
89 89
90 // Apply or remove the power save block, respectively. These methods should be 90 // Apply or remove the power save block, respectively. These methods should be
91 // called once each, on the same thread, per instance. They block waiting for 91 // called once each, on the same thread, per instance. They block waiting for
92 // the action to complete (with a timeout); the thread must thus allow I/O. 92 // the action to complete (with a timeout); the thread must thus allow I/O.
93 void ApplyBlock(DBusAPI api); 93 void ApplyBlock(DBusAPI api);
94 void RemoveBlock(DBusAPI api); 94 void RemoveBlock(DBusAPI api);
95 95
96 // Asynchronous callback functions for ApplyBlock and RemoveBlock.
97 // Functions do not receive ownership of |response|.
98 void ApplyBlockFinished(DBusAPI api, dbus::Response* response);
99 void RemoveBlockFinished(dbus::Response* response);
100
96 // If DPMS (the power saving system in X11) is not enabled, then we don't want 101 // If DPMS (the power saving system in X11) is not enabled, then we don't want
97 // to try to disable power saving, since on some desktop environments that may 102 // to try to disable power saving, since on some desktop environments that may
98 // enable DPMS with very poor default settings (e.g. turning off the display 103 // enable DPMS with very poor default settings (e.g. turning off the display
99 // after only 1 second). Must be called on the UI thread. 104 // after only 1 second). Must be called on the UI thread.
100 static bool DPMSEnabled(); 105 static bool DPMSEnabled();
101 106
102 // Returns an appropriate D-Bus API to use based on the desktop environment. 107 // Returns an appropriate D-Bus API to use based on the desktop environment.
103 // Must be called on the UI thread, as it may call DPMSEnabled() above. 108 // Must be called on the UI thread, as it may call DPMSEnabled() above.
104 static DBusAPI SelectAPI(); 109 static DBusAPI SelectAPI();
105 110
106 const PowerSaveBlockerType type_; 111 const PowerSaveBlockerType type_;
107 const std::string description_; 112 const std::string description_;
108 113
109 // Initially, we post a message to the UI thread to select an API. When it 114 // Initially, we post a message to the UI thread to select an API. When it
110 // finishes, it will post a message to the FILE thread to perform the actual 115 // finishes, it will post a message to the FILE thread to perform the actual
111 // application of the block, unless enqueue_apply_ is false. We set it to 116 // application of the block, unless enqueue_apply_ is false. We set it to
112 // false when we post that message, or when RemoveBlock() is called before 117 // false when we post that message, or when RemoveBlock() is called before
113 // ApplyBlock() has run. Both api_ and enqueue_apply_ are guarded by lock_. 118 // ApplyBlock() has run. Both api_ and enqueue_apply_ are guarded by lock_.
114 DBusAPI api_; 119 DBusAPI api_;
115 bool enqueue_apply_; 120 bool enqueue_apply_;
116 base::Lock lock_; 121 base::Lock lock_;
117 122
123 // Indicates that a D-Bus power save blocking request is in flight.
124 bool block_inflight_;
125 // Used to detect erronous redundant calls to RemoveBlock().
126 bool unblock_inflight_;
127 // Indicates that RemoveBlock() is called before ApplyBlock() has finished.
128 // If it's true, then the RemoveBlock() call will be processed immediately
129 // after ApplyBlock() has finished.
130 bool unblock_enqueued_;
131
118 scoped_refptr<dbus::Bus> bus_; 132 scoped_refptr<dbus::Bus> bus_;
119 133
120 // The cookie that identifies our inhibit request, 134 // The cookie that identifies our inhibit request,
121 // or 0 if there is no active inhibit request. 135 // or 0 if there is no active inhibit request.
122 uint32 inhibit_cookie_; 136 uint32 inhibit_cookie_;
123 137
124 DISALLOW_COPY_AND_ASSIGN(Delegate); 138 DISALLOW_COPY_AND_ASSIGN(Delegate);
125 }; 139 };
126 140
127 PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type, 141 PowerSaveBlockerImpl::Delegate::Delegate(PowerSaveBlockerType type,
128 const std::string& description) 142 const std::string& description)
129 : type_(type), 143 : type_(type),
130 description_(description), 144 description_(description),
131 api_(NO_API), 145 api_(NO_API),
132 enqueue_apply_(false), 146 enqueue_apply_(false),
133 inhibit_cookie_(0) { 147 inhibit_cookie_(0) {
134 // We're on the client's thread here, so we don't allocate the dbus::Bus 148 // We're on the client's thread here, so we don't allocate the dbus::Bus
135 // object yet. We'll do it later in ApplyBlock(), on the FILE thread. 149 // object yet. We'll do it later in ApplyBlock(), on the FILE thread.
136 } 150 }
137 151
138 void PowerSaveBlockerImpl::Delegate::Init() { 152 void PowerSaveBlockerImpl::Delegate::Init() {
139 base::AutoLock lock(lock_); 153 base::AutoLock lock(lock_);
140 DCHECK(!enqueue_apply_); 154 DCHECK(!enqueue_apply_);
141 enqueue_apply_ = true; 155 enqueue_apply_ = true;
156 block_inflight_ = false;
157 unblock_inflight_ = false;
158 unblock_enqueued_ = false;
142 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 159 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
143 base::Bind(&Delegate::InitOnUIThread, this)); 160 base::Bind(&Delegate::InitOnUIThread, this));
144 } 161 }
145 162
146 void PowerSaveBlockerImpl::Delegate::CleanUp() { 163 void PowerSaveBlockerImpl::Delegate::CleanUp() {
147 base::AutoLock lock(lock_); 164 base::AutoLock lock(lock_);
148 if (enqueue_apply_) { 165 if (enqueue_apply_) {
149 // If a call to ApplyBlock() has not yet been enqueued because we are still 166 // If a call to ApplyBlock() has not yet been enqueued because we are still
150 // initializing on the UI thread, then just cancel it. We don't need to 167 // initializing on the UI thread, then just cancel it. We don't need to
151 // remove the block because we haven't even applied it yet. 168 // remove the block because we haven't even applied it yet.
(...skipping 13 matching lines...) Expand all
165 // library, so we need to use the same thread above for RemoveBlock(). It 182 // library, so we need to use the same thread above for RemoveBlock(). It
166 // must be a thread that allows I/O operations, so we use the FILE thread. 183 // must be a thread that allows I/O operations, so we use the FILE thread.
167 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 184 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
168 base::Bind(&Delegate::ApplyBlock, this, api_)); 185 base::Bind(&Delegate::ApplyBlock, this, api_));
169 } 186 }
170 enqueue_apply_ = false; 187 enqueue_apply_ = false;
171 } 188 }
172 189
173 void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) { 190 void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
174 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 191 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
175 DCHECK(!bus_.get()); // ApplyBlock() should only be called once. 192 DCHECK(!bus_); // ApplyBlock() should only be called once.
193 DCHECK(!block_inflight_);
176 194
177 dbus::Bus::Options options; 195 dbus::Bus::Options options;
178 options.bus_type = dbus::Bus::SESSION; 196 options.bus_type = dbus::Bus::SESSION;
179 options.connection_type = dbus::Bus::PRIVATE; 197 options.connection_type = dbus::Bus::PRIVATE;
180 bus_ = new dbus::Bus(options); 198 bus_ = new dbus::Bus(options);
181 199
182 scoped_refptr<dbus::ObjectProxy> object_proxy; 200 scoped_refptr<dbus::ObjectProxy> object_proxy;
183 scoped_ptr<dbus::MethodCall> method_call; 201 scoped_ptr<dbus::MethodCall> method_call;
184 scoped_ptr<dbus::MessageWriter> message_writer; 202 scoped_ptr<dbus::MessageWriter> message_writer;
185 203
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 message_writer.reset(new dbus::MessageWriter(method_call.get())); 244 message_writer.reset(new dbus::MessageWriter(method_call.get()));
227 // The arguments of the method are: 245 // The arguments of the method are:
228 // app_id: The application identifier 246 // app_id: The application identifier
229 // reason: The reason for the inhibit 247 // reason: The reason for the inhibit
230 message_writer->AppendString( 248 message_writer->AppendString(
231 base::CommandLine::ForCurrentProcess()->GetProgram().value()); 249 base::CommandLine::ForCurrentProcess()->GetProgram().value());
232 message_writer->AppendString(description_); 250 message_writer->AppendString(description_);
233 break; 251 break;
234 } 252 }
235 253
236 // We could do this method call asynchronously, but if we did, we'd need to 254 block_inflight_ = true;
237 // handle the case where we want to cancel the block before we get a reply. 255 object_proxy->CallMethod(
238 // We're on the FILE thread so it should be OK to block briefly here. 256 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
239 scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( 257 base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this,
240 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); 258 api));
259 }
260
261 void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished(
262 DBusAPI api,
263 dbus::Response* response) {
264 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
265 DCHECK(bus_);
266 DCHECK(block_inflight_);
267 block_inflight_ = false;
268
241 if (response) { 269 if (response) {
242 // The method returns an inhibit_cookie, used to uniquely identify 270 // The method returns an inhibit_cookie, used to uniquely identify
243 // this request. It should be used as an argument to Uninhibit() 271 // this request. It should be used as an argument to Uninhibit()
244 // in order to remove the request. 272 // in order to remove the request.
245 dbus::MessageReader message_reader(response.get()); 273 dbus::MessageReader message_reader(response);
246 if (!message_reader.PopUint32(&inhibit_cookie_)) 274 if (!message_reader.PopUint32(&inhibit_cookie_))
247 LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString(); 275 LOG(ERROR) << "Invalid Inhibit() response: " << response->ToString();
248 } else { 276 } else {
249 LOG(ERROR) << "No response to Inhibit() request!"; 277 LOG(ERROR) << "No response to Inhibit() request!";
250 } 278 }
279
280 if (unblock_enqueued_) {
281 unblock_enqueued_ = false;
282 // RemoveBlock() was called while the Inhibit operation was in flight,
283 // so go ahead and remove the block now.
284 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
285 base::Bind(&Delegate::RemoveBlock, this, api_));
286 }
251 } 287 }
252 288
253 void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) { 289 void PowerSaveBlockerImpl::Delegate::RemoveBlock(DBusAPI api) {
254 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 290 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
255 DCHECK(bus_.get()); // RemoveBlock() should only be called once. 291 DCHECK(bus_); // RemoveBlock() should only be called once.
292 DCHECK(!unblock_inflight_);
293
294 if (block_inflight_) {
295 // Can't call RemoveBlock until ApplyBlock's asynchronous operation has
296 // finished. Enqueue it for execution once ApplyBlock is done.
297 unblock_enqueued_ = true;
miu 2015/05/15 18:43:31 Should you DCHECK(!unblock_enqueued) before this l
Kevin M 2015/05/15 18:55:25 Good idea, done.
298 return;
299 }
256 300
257 scoped_refptr<dbus::ObjectProxy> object_proxy; 301 scoped_refptr<dbus::ObjectProxy> object_proxy;
258 scoped_ptr<dbus::MethodCall> method_call; 302 scoped_ptr<dbus::MethodCall> method_call;
259 303
260 switch (api) { 304 switch (api) {
261 case NO_API: 305 case NO_API:
262 NOTREACHED(); // We should never call this method with this value. 306 NOTREACHED(); // We should never call this method with this value.
263 return; 307 return;
264 case GNOME_API: 308 case GNOME_API:
265 object_proxy = bus_->GetObjectProxy( 309 object_proxy = bus_->GetObjectProxy(
266 kGnomeAPIServiceName, 310 kGnomeAPIServiceName,
267 dbus::ObjectPath(kGnomeAPIObjectPath)); 311 dbus::ObjectPath(kGnomeAPIObjectPath));
268 method_call.reset( 312 method_call.reset(
269 new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit")); 313 new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
270 break; 314 break;
271 case FREEDESKTOP_API: 315 case FREEDESKTOP_API:
272 object_proxy = bus_->GetObjectProxy( 316 object_proxy = bus_->GetObjectProxy(
273 kFreeDesktopAPIServiceName, 317 kFreeDesktopAPIServiceName,
274 dbus::ObjectPath(kFreeDesktopAPIObjectPath)); 318 dbus::ObjectPath(kFreeDesktopAPIObjectPath));
275 method_call.reset( 319 method_call.reset(
276 new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit")); 320 new dbus::MethodCall(kFreeDesktopAPIInterfaceName, "UnInhibit"));
277 break; 321 break;
278 } 322 }
279 323
280 dbus::MessageWriter message_writer(method_call.get()); 324 dbus::MessageWriter message_writer(method_call.get());
281 message_writer.AppendUint32(inhibit_cookie_); 325 message_writer.AppendUint32(inhibit_cookie_);
282 scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock( 326 unblock_inflight_ = true;
283 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); 327 object_proxy->CallMethod(
328 method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
329 base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this));
330 }
331
332 void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
333 dbus::Response* response) {
334 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
335 DCHECK(bus_);
336 unblock_inflight_ = false;
337
284 if (!response) 338 if (!response)
285 LOG(ERROR) << "No response to Uninhibit() request!"; 339 LOG(ERROR) << "No response to Uninhibit() request!";
286 // We don't care about checking the result. We assume it works; we can't 340 // We don't care about checking the result. We assume it works; we can't
287 // really do anything about it anyway if it fails. 341 // really do anything about it anyway if it fails.
288 inhibit_cookie_ = 0;
miu 2015/05/15 18:43:31 nit: Either leave this in, or adjust the header fi
Kevin M 2015/05/15 18:55:25 Done.
289 342
290 bus_->ShutdownAndBlock(); 343 bus_->ShutdownAndBlock();
291 bus_ = NULL; 344 bus_ = NULL;
292 } 345 }
293 346
294 // static 347 // static
295 bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() { 348 bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
296 XDisplay* display = gfx::GetXDisplay(); 349 XDisplay* display = gfx::GetXDisplay();
297 BOOL enabled = false; 350 BOOL enabled = false;
298 int dummy; 351 int dummy;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 const std::string& description) 383 const std::string& description)
331 : delegate_(new Delegate(type, description)) { 384 : delegate_(new Delegate(type, description)) {
332 delegate_->Init(); 385 delegate_->Init();
333 } 386 }
334 387
335 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { 388 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
336 delegate_->CleanUp(); 389 delegate_->CleanUp();
337 } 390 }
338 391
339 } // namespace content 392 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698