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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/win/session_end_watcher.h"
16
17 #include "base/logging.h"
18 #include "base/scoped_generic.h"
19
20 extern "C" {
21 extern IMAGE_DOS_HEADER __ImageBase;
22 } // extern "C"
23
24 namespace crashpad {
25
26 namespace {
27
28 class ScopedSetEvent {
29 public:
30 explicit ScopedSetEvent(HANDLE event) : event_(event) {}
31 ~ScopedSetEvent() {
32 if (!SetEvent(event_)) {
33 PLOG(ERROR) << "SetEvent";
34 }
35 }
36
37 private:
38 HANDLE event_;
39
40 DISALLOW_COPY_AND_ASSIGN(ScopedSetEvent);
41 };
42
43 // ScopedWindowClass and ScopedWindow operate on ATOM* and HWND*, respectively,
44 // instead of ATOM and HWND, so that the actual storage can exist as a local
45 // variable or a member variable, and the scoper can be responsible for
46 // releasing things only if the actual storage hasn’t been released and zeroed
47 // already by something else.
48 struct ScopedWindowClassTraits {
49 static ATOM* InvalidValue() { return nullptr; }
50 static void Free(ATOM* window_class) {
51 if (*window_class) {
52 if (!UnregisterClass(MAKEINTATOM(*window_class), 0)) {
53 PLOG(ERROR) << "UnregisterClass";
54 } else {
55 *window_class = 0;
56 }
57 }
58 }
59 };
60 using ScopedWindowClass = base::ScopedGeneric<ATOM*, ScopedWindowClassTraits>;
61
62 struct ScopedWindowTraits {
63 static HWND* InvalidValue() { return nullptr; }
64 static void Free(HWND* window) {
65 if (*window) {
66 if (!DestroyWindow(*window)) {
67 PLOG(ERROR) << "DestroyWindow";
68 } else {
69 *window = nullptr;
70 }
71 }
72 }
73 };
74 using ScopedWindow = base::ScopedGeneric<HWND*, ScopedWindowTraits>;
75
76 // GetWindowLongPtr()’s return value doesn’t unambiguously indicate whether it
77 // was successful, because 0 could either represent successful retrieval of the
78 // value 0, or failure. This wrapper is more convenient to use.
79 bool GetWindowLongPtrAndSuccess(HWND window, int index, LONG_PTR* value) {
80 SetLastError(ERROR_SUCCESS);
81 *value = GetWindowLongPtr(window, index);
82 return *value || GetLastError() == ERROR_SUCCESS;
83 }
84
85 // SetWindowLongPtr() has the same problem as GetWindowLongPtr(). Use this
86 // wrapper instead.
87 bool SetWindowLongPtrAndGetSuccess(HWND window, int index, LONG_PTR value) {
88 SetLastError(ERROR_SUCCESS);
89 LONG_PTR previous = SetWindowLongPtr(window, index, value);
90 return previous || GetLastError() == ERROR_SUCCESS;
91 }
92
93 } // namespace
94
95 SessionEndWatcher::SessionEndWatcher()
96 : Thread(),
97 window_(nullptr),
98 started_(nullptr),
99 stopped_(nullptr) {
100 // Set bManualReset for these events so that WaitForStart() and WaitForStop()
101 // can be called multiple times.
102
103 started_.reset(CreateEvent(nullptr, true, false, nullptr));
104 PLOG_IF(ERROR, !started_.get()) << "CreateEvent";
105
106 stopped_.reset(CreateEvent(nullptr, true, false, nullptr));
107 PLOG_IF(ERROR, !stopped_.get()) << "CreateEvent";
108
109 Start();
110 }
111
112 SessionEndWatcher::~SessionEndWatcher() {
113 // Tear everything down by posting a WM_CLOSE to the window. This obviously
114 // can’t work until the window has been created, and that happens on a
115 // different thread, so wait for the start event to be signaled first.
116 WaitForStart();
117 if (window_) {
118 if (!PostMessage(window_, WM_CLOSE, 0, 0)) {
119 PLOG(ERROR) << "PostMessage";
120 }
121 }
122
123 Join();
124 DCHECK(!window_);
125 }
126
127 void SessionEndWatcher::WaitForStart() {
128 if (WaitForSingleObject(started_.get(), INFINITE) != WAIT_OBJECT_0) {
129 PLOG(ERROR) << "WaitForSingleObject";
130 }
131 }
132
133 void SessionEndWatcher::WaitForStop() {
134 if (WaitForSingleObject(stopped_.get(), INFINITE) != WAIT_OBJECT_0) {
135 PLOG(ERROR) << "WaitForSingleObject";
136 }
137 }
138
139 void SessionEndWatcher::ThreadMain() {
140 ATOM atom = 0;
141 ScopedWindowClass window_class(&atom);
142 ScopedWindow window(&window_);
143
144 ScopedSetEvent call_set_stop(stopped_.get());
145
146 {
147 ScopedSetEvent call_set_start(started_.get());
148
149 WNDCLASS wndclass = {};
150 wndclass.lpfnWndProc = WindowProc;
151 wndclass.hInstance = reinterpret_cast<HMODULE>(&__ImageBase);
152 wndclass.lpszClassName = L"crashpad_SessionEndWatcher";
153 atom = RegisterClass(&wndclass);
154 if (!atom) {
155 PLOG(ERROR) << "RegisterClass";
156 return;
157 }
158
159 window_ = CreateWindow(MAKEINTATOM(atom), // lpClassName
160 nullptr, // lpWindowName
161 0, // dwStyle
162 0, // x
163 0, // y
164 0, // nWidth
165 0, // nHeight
166 nullptr, // hWndParent
167 nullptr, // hMenu
168 nullptr, // hInstance
169 this); // lpParam
170 if (!window_) {
171 PLOG(ERROR) << "CreateWindow";
172 return;
173 }
174 }
175
176 MSG message;
177 BOOL rv = 0;
178 while (window_ && (rv = GetMessage(&message, window_, 0, 0)) > 0) {
179 TranslateMessage(&message);
180 DispatchMessage(&message);
181 }
182 if (window_ && rv == -1) {
183 PLOG(ERROR) << "GetMessage";
184 return;
185 }
186 }
187
188 // static
189 LRESULT CALLBACK SessionEndWatcher::WindowProc(HWND window,
190 UINT message,
191 WPARAM w_param,
192 LPARAM l_param) {
193 // Figure out which object this is. A pointer to it is stuffed into the last
194 // parameter of CreateWindow(), which shows up as CREATESTRUCT::lpCreateParams
195 // in a WM_CREATE message. That should be processed before any of the other
196 // messages of interest to this function. Once the object is known, save a
197 // pointer to it in the GWLP_USERDATA slot for later retrieval when processing
198 // other messages.
199 SessionEndWatcher* self;
200 if (!GetWindowLongPtrAndSuccess(
201 window, GWLP_USERDATA, reinterpret_cast<LONG_PTR*>(&self))) {
202 PLOG(ERROR) << "GetWindowLongPtr";
203 }
204 if (!self && message == WM_CREATE) {
205 CREATESTRUCT* create = reinterpret_cast<CREATESTRUCT*>(l_param);
206 self = reinterpret_cast<SessionEndWatcher*>(create->lpCreateParams);
207 if (!SetWindowLongPtrAndGetSuccess(
208 window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self))) {
209 PLOG(ERROR) << "SetWindowLongPtr";
210 }
211 }
212
213 if (self) {
214 if (message == WM_ENDSESSION) {
215 // If w_param is false, this WM_ENDSESSION message cancels a previous
216 // WM_QUERYENDSESSION.
217 if (w_param) {
218 self->SessionEnding();
219
220 // If the session is ending, post a close message which will kick off
221 // window destruction and cause the message loop thread to terminate.
222 if (!PostMessage(self->window_, WM_CLOSE, 0, 0)) {
223 PLOG(ERROR) << "PostMessage";
224 }
225 }
226 } else if (message == WM_DESTROY) {
227 // The window is being destroyed. Clear GWLP_USERDATA so that |self| won’t
228 // be found during a subsequent call into this function for this window.
229 // Clear self->window_ too, because it refers to an object that soon won’t
230 // exist. That signals the message loop to stop processing messages.
231 if (!SetWindowLongPtrAndGetSuccess(window, GWLP_USERDATA, 0)) {
232 PLOG(ERROR) << "SetWindowLongPtr";
233 }
234 self->window_ = nullptr;
235 }
236 }
237
238 // If the message is WM_CLOSE, DefWindowProc() will call DestroyWindow(), and
239 // this function will be called again with a WM_DESTROY message.
240 return DefWindowProc(window, message, w_param, l_param);
241 }
242
243 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698