OLD | NEW |
---|---|
1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 //! \brief The context data for registered threadpool waits. | 96 //! \brief The context data for registered threadpool waits. |
97 //! | 97 //! |
98 //! This object must be created and destroyed on the main thread. Access must be | 98 //! This object must be created and destroyed on the main thread. Access must be |
99 //! guarded by use of the lock() with the exception of the threadpool wait | 99 //! guarded by use of the lock() with the exception of the threadpool wait |
100 //! variables which are accessed only by the main thread. | 100 //! variables which are accessed only by the main thread. |
101 class ClientData { | 101 class ClientData { |
102 public: | 102 public: |
103 ClientData(HANDLE port, | 103 ClientData(HANDLE port, |
104 ExceptionHandlerServer::Delegate* delegate, | 104 ExceptionHandlerServer::Delegate* delegate, |
105 ScopedKernelHANDLE process, | 105 ScopedKernelHANDLE process, |
106 WinVMAddress exception_information_address, | 106 WinVMAddress crash_exception_information_address, |
107 WAITORTIMERCALLBACK dump_request_callback, | 107 WinVMAddress non_crash_exception_information_address, |
108 WAITORTIMERCALLBACK crash_dump_request_callback, | |
109 WAITORTIMERCALLBACK non_crash_dump_request_callback, | |
108 WAITORTIMERCALLBACK process_end_callback) | 110 WAITORTIMERCALLBACK process_end_callback) |
109 : dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), | 111 : crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), |
112 non_crash_dump_request_thread_pool_wait_(INVALID_HANDLE_VALUE), | |
110 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), | 113 process_end_thread_pool_wait_(INVALID_HANDLE_VALUE), |
111 lock_(), | 114 lock_(), |
112 port_(port), | 115 port_(port), |
113 delegate_(delegate), | 116 delegate_(delegate), |
114 dump_requested_event_( | 117 crash_dump_requested_event_( |
118 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | |
119 non_crash_dump_requested_event_( | |
120 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | |
121 non_crash_dump_completed_event_( | |
Mark Mentovai
2015/09/25 17:21:01
Duplicate initialization?
scottmg
2015/09/25 19:41:05
Sorry? Do you mean making a helper function that d
Mark Mentovai
2015/09/25 20:32:05
scottmg wrote:
scottmg
2015/09/25 20:46:47
I did the same thing a couple times. Maybe I shoul
| |
115 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), | 122 CreateEvent(nullptr, false /* auto reset */, false, nullptr)), |
116 process_(process.Pass()), | 123 process_(process.Pass()), |
117 exception_information_address_(exception_information_address) { | 124 crash_exception_information_address_( |
118 RegisterThreadPoolWaits(dump_request_callback, process_end_callback); | 125 crash_exception_information_address), |
126 non_crash_exception_information_address_( | |
127 non_crash_exception_information_address) { | |
128 RegisterThreadPoolWaits(crash_dump_request_callback, | |
129 non_crash_dump_request_callback, | |
130 process_end_callback); | |
119 } | 131 } |
120 | 132 |
121 ~ClientData() { | 133 ~ClientData() { |
122 // It is important that this only access the threadpool waits (it's called | 134 // It is important that this only access the threadpool waits (it's called |
123 // from the main thread) until the waits are unregistered, to ensure that | 135 // from the main thread) until the waits are unregistered, to ensure that |
124 // any outstanding callbacks are complete. | 136 // any outstanding callbacks are complete. |
125 UnregisterThreadPoolWaits(); | 137 UnregisterThreadPoolWaits(); |
126 } | 138 } |
127 | 139 |
128 base::Lock* lock() { return &lock_; } | 140 base::Lock* lock() { return &lock_; } |
129 HANDLE port() const { return port_; } | 141 HANDLE port() const { return port_; } |
130 ExceptionHandlerServer::Delegate* delegate() const { return delegate_; } | 142 ExceptionHandlerServer::Delegate* delegate() const { return delegate_; } |
131 HANDLE dump_requested_event() const { return dump_requested_event_.get(); } | 143 HANDLE crash_dump_requested_event() const { |
132 WinVMAddress exception_information_address() const { | 144 return crash_dump_requested_event_.get(); |
133 return exception_information_address_; | 145 } |
146 HANDLE non_crash_dump_requested_event() const { | |
147 return non_crash_dump_requested_event_.get(); | |
148 } | |
149 HANDLE non_crash_dump_completed_event() const { | |
150 return non_crash_dump_completed_event_.get(); | |
151 } | |
152 WinVMAddress crash_exception_information_address() const { | |
153 return crash_exception_information_address_; | |
154 } | |
155 WinVMAddress non_crash_exception_information_address() const { | |
156 return non_crash_exception_information_address_; | |
134 } | 157 } |
135 HANDLE process() const { return process_.get(); } | 158 HANDLE process() const { return process_.get(); } |
136 | 159 |
137 private: | 160 private: |
138 void RegisterThreadPoolWaits(WAITORTIMERCALLBACK dump_request_callback, | 161 void RegisterThreadPoolWaits( |
139 WAITORTIMERCALLBACK process_end_callback) { | 162 WAITORTIMERCALLBACK crash_dump_request_callback, |
140 if (!RegisterWaitForSingleObject(&dump_request_thread_pool_wait_, | 163 WAITORTIMERCALLBACK non_crash_dump_request_callback, |
141 dump_requested_event_.get(), | 164 WAITORTIMERCALLBACK process_end_callback) { |
142 dump_request_callback, | 165 if (!RegisterWaitForSingleObject(&crash_dump_request_thread_pool_wait_, |
166 crash_dump_requested_event_.get(), | |
167 crash_dump_request_callback, | |
143 this, | 168 this, |
144 INFINITE, | 169 INFINITE, |
145 WT_EXECUTEDEFAULT)) { | 170 WT_EXECUTEDEFAULT)) { |
146 LOG(ERROR) << "RegisterWaitForSingleObject dump requested"; | 171 LOG(ERROR) << "RegisterWaitForSingleObject crash dump requested"; |
172 } | |
173 | |
174 if (!RegisterWaitForSingleObject(&non_crash_dump_request_thread_pool_wait_, | |
175 non_crash_dump_requested_event_.get(), | |
176 non_crash_dump_request_callback, | |
177 this, | |
178 INFINITE, | |
179 WT_EXECUTEDEFAULT)) { | |
180 LOG(ERROR) << "RegisterWaitForSingleObject non-crash dump requested"; | |
147 } | 181 } |
148 | 182 |
149 if (!RegisterWaitForSingleObject(&process_end_thread_pool_wait_, | 183 if (!RegisterWaitForSingleObject(&process_end_thread_pool_wait_, |
150 process_.get(), | 184 process_.get(), |
151 process_end_callback, | 185 process_end_callback, |
152 this, | 186 this, |
153 INFINITE, | 187 INFINITE, |
154 WT_EXECUTEONLYONCE)) { | 188 WT_EXECUTEONLYONCE)) { |
155 LOG(ERROR) << "RegisterWaitForSingleObject process end"; | 189 LOG(ERROR) << "RegisterWaitForSingleObject process end"; |
156 } | 190 } |
157 } | 191 } |
158 | 192 |
159 // This blocks until outstanding calls complete so that we know it's safe to | 193 // This blocks until outstanding calls complete so that we know it's safe to |
160 // delete this object. Because of this, it must be executed on the main | 194 // delete this object. Because of this, it must be executed on the main |
161 // thread, not a threadpool thread. | 195 // thread, not a threadpool thread. |
162 void UnregisterThreadPoolWaits() { | 196 void UnregisterThreadPoolWaits() { |
163 UnregisterWaitEx(dump_request_thread_pool_wait_, INVALID_HANDLE_VALUE); | 197 UnregisterWaitEx(crash_dump_request_thread_pool_wait_, |
164 dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; | 198 INVALID_HANDLE_VALUE); |
199 crash_dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; | |
200 UnregisterWaitEx(non_crash_dump_request_thread_pool_wait_, | |
201 INVALID_HANDLE_VALUE); | |
202 non_crash_dump_request_thread_pool_wait_ = INVALID_HANDLE_VALUE; | |
165 UnregisterWaitEx(process_end_thread_pool_wait_, INVALID_HANDLE_VALUE); | 203 UnregisterWaitEx(process_end_thread_pool_wait_, INVALID_HANDLE_VALUE); |
166 process_end_thread_pool_wait_ = INVALID_HANDLE_VALUE; | 204 process_end_thread_pool_wait_ = INVALID_HANDLE_VALUE; |
167 } | 205 } |
168 | 206 |
169 // These are only accessed on the main thread. | 207 // These are only accessed on the main thread. |
170 HANDLE dump_request_thread_pool_wait_; | 208 HANDLE crash_dump_request_thread_pool_wait_; |
209 HANDLE non_crash_dump_request_thread_pool_wait_; | |
171 HANDLE process_end_thread_pool_wait_; | 210 HANDLE process_end_thread_pool_wait_; |
172 | 211 |
173 base::Lock lock_; | 212 base::Lock lock_; |
174 // Access to these fields must be guarded by lock_. | 213 // Access to these fields must be guarded by lock_. |
175 HANDLE port_; // weak | 214 HANDLE port_; // weak |
176 ExceptionHandlerServer::Delegate* delegate_; // weak | 215 ExceptionHandlerServer::Delegate* delegate_; // weak |
177 ScopedKernelHANDLE dump_requested_event_; | 216 ScopedKernelHANDLE crash_dump_requested_event_; |
217 ScopedKernelHANDLE non_crash_dump_requested_event_; | |
218 ScopedKernelHANDLE non_crash_dump_completed_event_; | |
178 ScopedKernelHANDLE process_; | 219 ScopedKernelHANDLE process_; |
179 WinVMAddress exception_information_address_; | 220 WinVMAddress crash_exception_information_address_; |
221 WinVMAddress non_crash_exception_information_address_; | |
180 | 222 |
181 DISALLOW_COPY_AND_ASSIGN(ClientData); | 223 DISALLOW_COPY_AND_ASSIGN(ClientData); |
182 }; | 224 }; |
183 | 225 |
184 } // namespace internal | 226 } // namespace internal |
185 | 227 |
186 ExceptionHandlerServer::Delegate::~Delegate() { | 228 ExceptionHandlerServer::Delegate::~Delegate() { |
187 } | 229 } |
188 | 230 |
189 ExceptionHandlerServer::ExceptionHandlerServer() | 231 ExceptionHandlerServer::ExceptionHandlerServer() |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 PCHECK(RevertToSelf()); | 399 PCHECK(RevertToSelf()); |
358 if (!client_process) { | 400 if (!client_process) { |
359 LOG(ERROR) << "failed to open " << message.registration.client_process_id; | 401 LOG(ERROR) << "failed to open " << message.registration.client_process_id; |
360 return false; | 402 return false; |
361 } | 403 } |
362 } | 404 } |
363 | 405 |
364 internal::ClientData* client; | 406 internal::ClientData* client; |
365 { | 407 { |
366 base::AutoLock lock(*service_context.clients_lock()); | 408 base::AutoLock lock(*service_context.clients_lock()); |
367 client = | 409 client = new internal::ClientData( |
368 new internal::ClientData(service_context.port(), | 410 service_context.port(), |
369 service_context.delegate(), | 411 service_context.delegate(), |
370 ScopedKernelHANDLE(client_process), | 412 ScopedKernelHANDLE(client_process), |
371 message.registration.exception_information, | 413 message.registration.crash_exception_information, |
372 &OnDumpEvent, | 414 message.registration.non_crash_exception_information, |
373 &OnProcessEnd); | 415 &OnCrashDumpEvent, |
416 &OnNonCrashDumpEvent, | |
417 &OnProcessEnd); | |
374 service_context.clients()->insert(client); | 418 service_context.clients()->insert(client); |
375 } | 419 } |
376 | 420 |
377 // Duplicate the events back to the client so they can request a dump. | 421 // Duplicate the events back to the client so they can request a dump. |
378 ServerToClientMessage response; | 422 ServerToClientMessage response; |
379 response.registration.request_report_event = | 423 response.registration.request_crash_dump_event = |
380 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>( | 424 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( |
381 DuplicateEvent(client->process(), client->dump_requested_event()))); | 425 client->process(), client->crash_dump_requested_event()))); |
426 response.registration.request_non_crash_dump_event = | |
427 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( | |
428 client->process(), client->non_crash_dump_requested_event()))); | |
429 response.registration.non_crash_dump_completed_event = | |
430 base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent( | |
431 client->process(), client->non_crash_dump_completed_event()))); | |
382 | 432 |
383 if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) | 433 if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response))) |
384 return false; | 434 return false; |
385 | 435 |
386 return false; | 436 return false; |
387 } | 437 } |
388 | 438 |
389 // static | 439 // static |
390 DWORD __stdcall ExceptionHandlerServer::PipeServiceProc(void* ctx) { | 440 DWORD __stdcall ExceptionHandlerServer::PipeServiceProc(void* ctx) { |
391 internal::PipeServiceContext* service_context = | 441 internal::PipeServiceContext* service_context = |
392 reinterpret_cast<internal::PipeServiceContext*>(ctx); | 442 reinterpret_cast<internal::PipeServiceContext*>(ctx); |
393 DCHECK(service_context); | 443 DCHECK(service_context); |
394 | 444 |
395 for (;;) { | 445 for (;;) { |
396 bool ret = ConnectNamedPipe(service_context->pipe(), nullptr); | 446 bool ret = ConnectNamedPipe(service_context->pipe(), nullptr); |
397 if (!ret && GetLastError() != ERROR_PIPE_CONNECTED) { | 447 if (!ret && GetLastError() != ERROR_PIPE_CONNECTED) { |
398 PLOG(ERROR) << "ConnectNamedPipe"; | 448 PLOG(ERROR) << "ConnectNamedPipe"; |
399 } else if (ServiceClientConnection(*service_context)) { | 449 } else if (ServiceClientConnection(*service_context)) { |
400 break; | 450 break; |
401 } | 451 } |
402 DisconnectNamedPipe(service_context->pipe()); | 452 DisconnectNamedPipe(service_context->pipe()); |
403 } | 453 } |
404 | 454 |
405 delete service_context; | 455 delete service_context; |
406 | 456 |
407 return 0; | 457 return 0; |
408 } | 458 } |
409 | 459 |
410 // static | 460 // static |
411 void __stdcall ExceptionHandlerServer::OnDumpEvent(void* ctx, BOOLEAN) { | 461 void __stdcall ExceptionHandlerServer::OnCrashDumpEvent(void* ctx, BOOLEAN) { |
412 // This function is executed on the thread pool. | 462 // This function is executed on the thread pool. |
413 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 463 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
414 base::AutoLock lock(*client->lock()); | 464 base::AutoLock lock(*client->lock()); |
415 | 465 |
416 // Capture the exception. | 466 // Capture the exception. |
417 unsigned int exit_code = client->delegate()->ExceptionHandlerServerException( | 467 unsigned int exit_code = client->delegate()->ExceptionHandlerServerException( |
418 client->process(), client->exception_information_address()); | 468 client->process(), client->crash_exception_information_address()); |
419 | 469 |
420 TerminateProcess(client->process(), exit_code); | 470 TerminateProcess(client->process(), exit_code); |
421 } | 471 } |
422 | 472 |
423 // static | 473 // static |
474 void __stdcall ExceptionHandlerServer::OnNonCrashDumpEvent(void* ctx, BOOLEAN) { | |
475 // This function is executed on the thread pool. | |
476 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | |
477 base::AutoLock lock(*client->lock()); | |
478 | |
479 // Capture the exception. | |
480 client->delegate()->ExceptionHandlerServerException( | |
481 client->process(), client->non_crash_exception_information_address()); | |
482 | |
483 bool result = SetEvent(client->non_crash_dump_completed_event()); | |
484 PLOG_IF(ERROR, !result) << "SetEvent"; | |
485 } | |
486 | |
487 // static | |
424 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { | 488 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { |
425 // This function is executed on the thread pool. | 489 // This function is executed on the thread pool. |
426 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 490 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
427 base::AutoLock lock(*client->lock()); | 491 base::AutoLock lock(*client->lock()); |
428 | 492 |
429 // Post back to the main thread to have it delete this client record. | 493 // Post back to the main thread to have it delete this client record. |
430 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); | 494 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); |
431 } | 495 } |
432 | 496 |
433 } // namespace crashpad | 497 } // namespace crashpad |
OLD | NEW |