Chromium Code Reviews| 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 17 matching lines...) Expand all Loading... | |
| 28 #include "util/misc/tri_state.h" | 28 #include "util/misc/tri_state.h" |
| 29 #include "util/misc/uuid.h" | 29 #include "util/misc/uuid.h" |
| 30 #include "util/win/get_function.h" | 30 #include "util/win/get_function.h" |
| 31 #include "util/win/registration_protocol_win.h" | 31 #include "util/win/registration_protocol_win.h" |
| 32 #include "util/win/xp_compat.h" | 32 #include "util/win/xp_compat.h" |
| 33 | 33 |
| 34 namespace crashpad { | 34 namespace crashpad { |
| 35 | 35 |
| 36 namespace { | 36 namespace { |
| 37 | 37 |
| 38 // We create two pipe instances, so that there's one listening while the | |
| 39 // PipeServiceProc is processing a registration. | |
| 40 const size_t kPipeInstances = 2; | |
| 41 | |
| 42 // Wraps CreateNamedPipe() to create a single named pipe instance. | |
| 43 // | |
| 44 // If first_instance is true, the named pipe instance will be created with | |
| 45 // FILE_FLAG_FIRST_PIPE_INSTANCE. This ensures that the the pipe name is not | |
| 46 // already in use when created. | |
| 47 HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, | |
| 48 bool first_instance) { | |
| 49 return CreateNamedPipe(pipe_name.c_str(), | |
| 50 PIPE_ACCESS_DUPLEX | | |
| 51 (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE | |
| 52 : 0), | |
| 53 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | |
| 54 kPipeInstances, | |
| 55 512, | |
| 56 512, | |
| 57 0, | |
| 58 nullptr); | |
| 59 } | |
| 60 | |
| 38 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() { | 61 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() { |
| 39 static const auto get_named_pipe_client_process_id = | 62 static const auto get_named_pipe_client_process_id = |
| 40 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId); | 63 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId); |
| 41 return get_named_pipe_client_process_id; | 64 return get_named_pipe_client_process_id; |
| 42 } | 65 } |
| 43 | 66 |
| 44 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { | 67 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { |
| 45 HANDLE handle; | 68 HANDLE handle; |
| 46 if (DuplicateHandle(GetCurrentProcess(), | 69 if (DuplicateHandle(GetCurrentProcess(), |
| 47 event, | 70 event, |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 WinVMAddress debug_critical_section_address_; | 250 WinVMAddress debug_critical_section_address_; |
| 228 | 251 |
| 229 DISALLOW_COPY_AND_ASSIGN(ClientData); | 252 DISALLOW_COPY_AND_ASSIGN(ClientData); |
| 230 }; | 253 }; |
| 231 | 254 |
| 232 } // namespace internal | 255 } // namespace internal |
| 233 | 256 |
| 234 ExceptionHandlerServer::Delegate::~Delegate() { | 257 ExceptionHandlerServer::Delegate::~Delegate() { |
| 235 } | 258 } |
| 236 | 259 |
| 237 ExceptionHandlerServer::ExceptionHandlerServer(const std::string& pipe_name, | 260 ExceptionHandlerServer::ExceptionHandlerServer(bool persistent) |
| 238 bool persistent) | 261 : pipe_name_(), |
| 239 : pipe_name_(pipe_name), | |
| 240 port_(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1)), | 262 port_(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1)), |
| 263 first_pipe_instance_(), | |
| 241 clients_lock_(), | 264 clients_lock_(), |
| 242 clients_(), | 265 clients_(), |
| 243 persistent_(persistent) { | 266 persistent_(persistent) { |
| 244 } | 267 } |
| 245 | 268 |
| 246 ExceptionHandlerServer::~ExceptionHandlerServer() { | 269 ExceptionHandlerServer::~ExceptionHandlerServer() { |
| 247 } | 270 } |
| 248 | 271 |
| 272 void ExceptionHandlerServer::SetPipeName(const std::wstring& pipe_name) { | |
| 273 DCHECK(pipe_name_.empty()); | |
| 274 DCHECK(!pipe_name.empty()); | |
| 275 | |
| 276 pipe_name_ = pipe_name; | |
| 277 } | |
| 278 | |
| 279 std::wstring ExceptionHandlerServer::CreatePipe() { | |
| 280 DCHECK(pipe_name_.empty()); | |
| 281 DCHECK(!first_pipe_instance_.is_valid()); | |
| 282 | |
| 283 int tries = 5; | |
| 284 std::string pipe_name_base = | |
| 285 base::StringPrintf("\\\\.\\pipe\\crashpad_%d_", GetCurrentProcessId()); | |
| 286 std::wstring pipe_name; | |
| 287 do { | |
| 288 pipe_name = base::UTF8ToUTF16(pipe_name_base); | |
| 289 for (int index = 0; index < 16; ++index) { | |
| 290 pipe_name.append(1, static_cast<wchar_t>(base::RandInt('A', 'Z'))); | |
| 291 } | |
| 292 | |
| 293 first_pipe_instance_.reset(CreateNamedPipeInstance(pipe_name, true)); | |
| 294 | |
| 295 // CreateNamedPipe() is documented as setting the error to | |
| 296 // ERROR_ACCESS_DENIED if FILE_FLAG_FIRST_PIPE_INSTANCE is specified and the | |
| 297 // pipe name is already in use. However it may set the error to other codes | |
| 298 // such as ERROR_PIPE_BUSY (if the pipe already exists and has reached its | |
| 299 // maximum instance count) or ERROR_INVALID_PARAMETER (if the pipe already | |
| 300 // exists and its attributes differ from those specified to | |
| 301 // CreateNamedPipe()). Some of these errors may be ambiguous: for example, | |
| 302 // ERROR_INVALID_PARAMETER may also occur if CreateNamedPipe() is called | |
| 303 // incorrectly even in the absence of an existing pipe by the same name. | |
| 304 // | |
| 305 // Rather than chasing down all of the possible errors that might indicate | |
| 306 // that a pipe name is already in use, retry up to a few times on any error. | |
| 307 } while (!first_pipe_instance_.is_valid() && --tries); | |
| 308 | |
| 309 PCHECK(first_pipe_instance_.is_valid()) << "CreateNamedPipe"; | |
| 310 | |
| 311 pipe_name_ = pipe_name; | |
|
scottmg
2015/11/03 20:52:07
Maybe call SetPipeName() here (and remove the firs
Mark Mentovai
2015/11/03 23:58:48
scottmg wrote:
| |
| 312 return pipe_name_; | |
| 313 } | |
| 314 | |
| 249 void ExceptionHandlerServer::Run(Delegate* delegate) { | 315 void ExceptionHandlerServer::Run(Delegate* delegate) { |
| 250 uint64_t shutdown_token = base::RandUint64(); | 316 uint64_t shutdown_token = base::RandUint64(); |
| 251 // We create two pipe instances, so that there's one listening while the | 317 ScopedKernelHANDLE thread_handles[kPipeInstances]; |
| 252 // PipeServiceProc is processing a registration. | |
| 253 ScopedKernelHANDLE thread_handles[2]; | |
| 254 base::string16 pipe_name_16(base::UTF8ToUTF16(pipe_name_)); | |
| 255 for (int i = 0; i < arraysize(thread_handles); ++i) { | 318 for (int i = 0; i < arraysize(thread_handles); ++i) { |
| 256 HANDLE pipe = | 319 HANDLE pipe; |
| 257 CreateNamedPipe(pipe_name_16.c_str(), | 320 if (first_pipe_instance_.is_valid()) { |
| 258 PIPE_ACCESS_DUPLEX, | 321 pipe = first_pipe_instance_.release(); |
| 259 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | 322 } else { |
| 260 arraysize(thread_handles), | 323 pipe = CreateNamedPipeInstance(pipe_name_, false); |
| 261 512, | 324 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe"; |
| 262 512, | 325 } |
| 263 0, | |
| 264 nullptr); | |
| 265 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe"; | |
| 266 | 326 |
| 267 // Ownership of this object (and the pipe instance) is given to the new | 327 // Ownership of this object (and the pipe instance) is given to the new |
| 268 // thread. We close the thread handles at the end of the scope. They clean | 328 // thread. We close the thread handles at the end of the scope. They clean |
| 269 // up the context object and the pipe instance on termination. | 329 // up the context object and the pipe instance on termination. |
| 270 internal::PipeServiceContext* context = | 330 internal::PipeServiceContext* context = |
| 271 new internal::PipeServiceContext(port_.get(), | 331 new internal::PipeServiceContext(port_.get(), |
| 272 pipe, | 332 pipe, |
| 273 delegate, | 333 delegate, |
| 274 &clients_lock_, | 334 &clients_lock_, |
| 275 &clients_, | 335 &clients_, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 306 break; | 366 break; |
| 307 } | 367 } |
| 308 | 368 |
| 309 // Signal to the named pipe instances that they should terminate. | 369 // Signal to the named pipe instances that they should terminate. |
| 310 for (int i = 0; i < arraysize(thread_handles); ++i) { | 370 for (int i = 0; i < arraysize(thread_handles); ++i) { |
| 311 ClientToServerMessage message; | 371 ClientToServerMessage message; |
| 312 memset(&message, 0, sizeof(message)); | 372 memset(&message, 0, sizeof(message)); |
| 313 message.type = ClientToServerMessage::kShutdown; | 373 message.type = ClientToServerMessage::kShutdown; |
| 314 message.shutdown.token = shutdown_token; | 374 message.shutdown.token = shutdown_token; |
| 315 ServerToClientMessage response; | 375 ServerToClientMessage response; |
| 316 SendToCrashHandlerServer(pipe_name_16, | 376 SendToCrashHandlerServer(pipe_name_, |
| 317 reinterpret_cast<ClientToServerMessage&>(message), | 377 reinterpret_cast<ClientToServerMessage&>(message), |
| 318 &response); | 378 &response); |
| 319 } | 379 } |
| 320 | 380 |
| 321 for (auto& handle : thread_handles) | 381 for (auto& handle : thread_handles) |
| 322 WaitForSingleObject(handle.get(), INFINITE); | 382 WaitForSingleObject(handle.get(), INFINITE); |
| 323 | 383 |
| 324 // Deleting ClientData does a blocking wait until the threadpool executions | 384 // Deleting ClientData does a blocking wait until the threadpool executions |
| 325 // have terminated when unregistering them. | 385 // have terminated when unregistering them. |
| 326 { | 386 { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 501 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { | 561 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { |
| 502 // This function is executed on the thread pool. | 562 // This function is executed on the thread pool. |
| 503 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 563 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
| 504 base::AutoLock lock(*client->lock()); | 564 base::AutoLock lock(*client->lock()); |
| 505 | 565 |
| 506 // Post back to the main thread to have it delete this client record. | 566 // Post back to the main thread to have it delete this client record. |
| 507 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); | 567 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); |
| 508 } | 568 } |
| 509 | 569 |
| 510 } // namespace crashpad | 570 } // namespace crashpad |
| OLD | NEW |