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

Unified Diff: third_party/crashpad/crashpad/util/win/session_end_watcher.cc

Issue 2710663006: Update Crashpad to 4a2043ea65e2641ef1a921801c0aaa15ada02fc7 (Closed)
Patch Set: Update Crashpad to 4a2043ea65e2 Created 3 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/util/win/session_end_watcher.cc
diff --git a/third_party/crashpad/crashpad/util/win/session_end_watcher.cc b/third_party/crashpad/crashpad/util/win/session_end_watcher.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e795f22a582824b58e9f3b5bdcc6425a8e4e3994
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/win/session_end_watcher.cc
@@ -0,0 +1,243 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/win/session_end_watcher.h"
+
+#include "base/logging.h"
+#include "base/scoped_generic.h"
+
+extern "C" {
+extern IMAGE_DOS_HEADER __ImageBase;
+} // extern "C"
+
+namespace crashpad {
+
+namespace {
+
+class ScopedSetEvent {
+ public:
+ explicit ScopedSetEvent(HANDLE event) : event_(event) {}
+ ~ScopedSetEvent() {
+ if (!SetEvent(event_)) {
+ PLOG(ERROR) << "SetEvent";
+ }
+ }
+
+ private:
+ HANDLE event_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetEvent);
+};
+
+// ScopedWindowClass and ScopedWindow operate on ATOM* and HWND*, respectively,
+// instead of ATOM and HWND, so that the actual storage can exist as a local
+// variable or a member variable, and the scoper can be responsible for
+// releasing things only if the actual storage hasn’t been released and zeroed
+// already by something else.
+struct ScopedWindowClassTraits {
+ static ATOM* InvalidValue() { return nullptr; }
+ static void Free(ATOM* window_class) {
+ if (*window_class) {
+ if (!UnregisterClass(MAKEINTATOM(*window_class), 0)) {
+ PLOG(ERROR) << "UnregisterClass";
+ } else {
+ *window_class = 0;
+ }
+ }
+ }
+};
+using ScopedWindowClass = base::ScopedGeneric<ATOM*, ScopedWindowClassTraits>;
+
+struct ScopedWindowTraits {
+ static HWND* InvalidValue() { return nullptr; }
+ static void Free(HWND* window) {
+ if (*window) {
+ if (!DestroyWindow(*window)) {
+ PLOG(ERROR) << "DestroyWindow";
+ } else {
+ *window = nullptr;
+ }
+ }
+ }
+};
+using ScopedWindow = base::ScopedGeneric<HWND*, ScopedWindowTraits>;
+
+// GetWindowLongPtr()’s return value doesn’t unambiguously indicate whether it
+// was successful, because 0 could either represent successful retrieval of the
+// value 0, or failure. This wrapper is more convenient to use.
+bool GetWindowLongPtrAndSuccess(HWND window, int index, LONG_PTR* value) {
+ SetLastError(ERROR_SUCCESS);
+ *value = GetWindowLongPtr(window, index);
+ return *value || GetLastError() == ERROR_SUCCESS;
+}
+
+// SetWindowLongPtr() has the same problem as GetWindowLongPtr(). Use this
+// wrapper instead.
+bool SetWindowLongPtrAndGetSuccess(HWND window, int index, LONG_PTR value) {
+ SetLastError(ERROR_SUCCESS);
+ LONG_PTR previous = SetWindowLongPtr(window, index, value);
+ return previous || GetLastError() == ERROR_SUCCESS;
+}
+
+} // namespace
+
+SessionEndWatcher::SessionEndWatcher()
+ : Thread(),
+ window_(nullptr),
+ started_(nullptr),
+ stopped_(nullptr) {
+ // Set bManualReset for these events so that WaitForStart() and WaitForStop()
+ // can be called multiple times.
+
+ started_.reset(CreateEvent(nullptr, true, false, nullptr));
+ PLOG_IF(ERROR, !started_.get()) << "CreateEvent";
+
+ stopped_.reset(CreateEvent(nullptr, true, false, nullptr));
+ PLOG_IF(ERROR, !stopped_.get()) << "CreateEvent";
+
+ Start();
+}
+
+SessionEndWatcher::~SessionEndWatcher() {
+ // Tear everything down by posting a WM_CLOSE to the window. This obviously
+ // can’t work until the window has been created, and that happens on a
+ // different thread, so wait for the start event to be signaled first.
+ WaitForStart();
+ if (window_) {
+ if (!PostMessage(window_, WM_CLOSE, 0, 0)) {
+ PLOG(ERROR) << "PostMessage";
+ }
+ }
+
+ Join();
+ DCHECK(!window_);
+}
+
+void SessionEndWatcher::WaitForStart() {
+ if (WaitForSingleObject(started_.get(), INFINITE) != WAIT_OBJECT_0) {
+ PLOG(ERROR) << "WaitForSingleObject";
+ }
+}
+
+void SessionEndWatcher::WaitForStop() {
+ if (WaitForSingleObject(stopped_.get(), INFINITE) != WAIT_OBJECT_0) {
+ PLOG(ERROR) << "WaitForSingleObject";
+ }
+}
+
+void SessionEndWatcher::ThreadMain() {
+ ATOM atom = 0;
+ ScopedWindowClass window_class(&atom);
+ ScopedWindow window(&window_);
+
+ ScopedSetEvent call_set_stop(stopped_.get());
+
+ {
+ ScopedSetEvent call_set_start(started_.get());
+
+ WNDCLASS wndclass = {};
+ wndclass.lpfnWndProc = WindowProc;
+ wndclass.hInstance = reinterpret_cast<HMODULE>(&__ImageBase);
+ wndclass.lpszClassName = L"crashpad_SessionEndWatcher";
+ atom = RegisterClass(&wndclass);
+ if (!atom) {
+ PLOG(ERROR) << "RegisterClass";
+ return;
+ }
+
+ window_ = CreateWindow(MAKEINTATOM(atom), // lpClassName
+ nullptr, // lpWindowName
+ 0, // dwStyle
+ 0, // x
+ 0, // y
+ 0, // nWidth
+ 0, // nHeight
+ nullptr, // hWndParent
+ nullptr, // hMenu
+ nullptr, // hInstance
+ this); // lpParam
+ if (!window_) {
+ PLOG(ERROR) << "CreateWindow";
+ return;
+ }
+ }
+
+ MSG message;
+ BOOL rv = 0;
+ while (window_ && (rv = GetMessage(&message, window_, 0, 0)) > 0) {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ if (window_ && rv == -1) {
+ PLOG(ERROR) << "GetMessage";
+ return;
+ }
+}
+
+// static
+LRESULT CALLBACK SessionEndWatcher::WindowProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // Figure out which object this is. A pointer to it is stuffed into the last
+ // parameter of CreateWindow(), which shows up as CREATESTRUCT::lpCreateParams
+ // in a WM_CREATE message. That should be processed before any of the other
+ // messages of interest to this function. Once the object is known, save a
+ // pointer to it in the GWLP_USERDATA slot for later retrieval when processing
+ // other messages.
+ SessionEndWatcher* self;
+ if (!GetWindowLongPtrAndSuccess(
+ window, GWLP_USERDATA, reinterpret_cast<LONG_PTR*>(&self))) {
+ PLOG(ERROR) << "GetWindowLongPtr";
+ }
+ if (!self && message == WM_CREATE) {
+ CREATESTRUCT* create = reinterpret_cast<CREATESTRUCT*>(l_param);
+ self = reinterpret_cast<SessionEndWatcher*>(create->lpCreateParams);
+ if (!SetWindowLongPtrAndGetSuccess(
+ window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self))) {
+ PLOG(ERROR) << "SetWindowLongPtr";
+ }
+ }
+
+ if (self) {
+ if (message == WM_ENDSESSION) {
+ // If w_param is false, this WM_ENDSESSION message cancels a previous
+ // WM_QUERYENDSESSION.
+ if (w_param) {
+ self->SessionEnding();
+
+ // If the session is ending, post a close message which will kick off
+ // window destruction and cause the message loop thread to terminate.
+ if (!PostMessage(self->window_, WM_CLOSE, 0, 0)) {
+ PLOG(ERROR) << "PostMessage";
+ }
+ }
+ } else if (message == WM_DESTROY) {
+ // The window is being destroyed. Clear GWLP_USERDATA so that |self| won’t
+ // be found during a subsequent call into this function for this window.
+ // Clear self->window_ too, because it refers to an object that soon won’t
+ // exist. That signals the message loop to stop processing messages.
+ if (!SetWindowLongPtrAndGetSuccess(window, GWLP_USERDATA, 0)) {
+ PLOG(ERROR) << "SetWindowLongPtr";
+ }
+ self->window_ = nullptr;
+ }
+ }
+
+ // If the message is WM_CLOSE, DefWindowProc() will call DestroyWindow(), and
+ // this function will be called again with a WM_DESTROY message.
+ return DefWindowProc(window, message, w_param, l_param);
+}
+
+} // namespace crashpad

Powered by Google App Engine
This is Rietveld 408576698