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(!first_pipe_instance_.is_valid()); |
| 281 |
| 282 int tries = 5; |
| 283 std::string pipe_name_base = |
| 284 base::StringPrintf("\\\\.\\pipe\\crashpad_%d_", GetCurrentProcessId()); |
| 285 std::wstring pipe_name; |
| 286 do { |
| 287 pipe_name = base::UTF8ToUTF16(pipe_name_base); |
| 288 for (int index = 0; index < 16; ++index) { |
| 289 pipe_name.append(1, static_cast<wchar_t>(base::RandInt('A', 'Z'))); |
| 290 } |
| 291 |
| 292 first_pipe_instance_.reset(CreateNamedPipeInstance(pipe_name, true)); |
| 293 |
| 294 // CreateNamedPipe() is documented as setting the error to |
| 295 // ERROR_ACCESS_DENIED if FILE_FLAG_FIRST_PIPE_INSTANCE is specified and the |
| 296 // pipe name is already in use. However it may set the error to other codes |
| 297 // such as ERROR_PIPE_BUSY (if the pipe already exists and has reached its |
| 298 // maximum instance count) or ERROR_INVALID_PARAMETER (if the pipe already |
| 299 // exists and its attributes differ from those specified to |
| 300 // CreateNamedPipe()). Some of these errors may be ambiguous: for example, |
| 301 // ERROR_INVALID_PARAMETER may also occur if CreateNamedPipe() is called |
| 302 // incorrectly even in the absence of an existing pipe by the same name. |
| 303 // |
| 304 // Rather than chasing down all of the possible errors that might indicate |
| 305 // that a pipe name is already in use, retry up to a few times on any error. |
| 306 } while (!first_pipe_instance_.is_valid() && --tries); |
| 307 |
| 308 PCHECK(first_pipe_instance_.is_valid()) << "CreateNamedPipe"; |
| 309 |
| 310 SetPipeName(pipe_name); |
| 311 return pipe_name; |
| 312 } |
| 313 |
249 void ExceptionHandlerServer::Run(Delegate* delegate) { | 314 void ExceptionHandlerServer::Run(Delegate* delegate) { |
250 uint64_t shutdown_token = base::RandUint64(); | 315 uint64_t shutdown_token = base::RandUint64(); |
251 // We create two pipe instances, so that there's one listening while the | 316 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) { | 317 for (int i = 0; i < arraysize(thread_handles); ++i) { |
256 HANDLE pipe = | 318 HANDLE pipe; |
257 CreateNamedPipe(pipe_name_16.c_str(), | 319 if (first_pipe_instance_.is_valid()) { |
258 PIPE_ACCESS_DUPLEX, | 320 pipe = first_pipe_instance_.release(); |
259 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | 321 } else { |
260 arraysize(thread_handles), | 322 pipe = CreateNamedPipeInstance(pipe_name_, false); |
261 512, | 323 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe"; |
262 512, | 324 } |
263 0, | |
264 nullptr); | |
265 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe"; | |
266 | 325 |
267 // Ownership of this object (and the pipe instance) is given to the new | 326 // 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 | 327 // 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. | 328 // up the context object and the pipe instance on termination. |
270 internal::PipeServiceContext* context = | 329 internal::PipeServiceContext* context = |
271 new internal::PipeServiceContext(port_.get(), | 330 new internal::PipeServiceContext(port_.get(), |
272 pipe, | 331 pipe, |
273 delegate, | 332 delegate, |
274 &clients_lock_, | 333 &clients_lock_, |
275 &clients_, | 334 &clients_, |
(...skipping 30 matching lines...) Expand all Loading... |
306 break; | 365 break; |
307 } | 366 } |
308 | 367 |
309 // Signal to the named pipe instances that they should terminate. | 368 // Signal to the named pipe instances that they should terminate. |
310 for (int i = 0; i < arraysize(thread_handles); ++i) { | 369 for (int i = 0; i < arraysize(thread_handles); ++i) { |
311 ClientToServerMessage message; | 370 ClientToServerMessage message; |
312 memset(&message, 0, sizeof(message)); | 371 memset(&message, 0, sizeof(message)); |
313 message.type = ClientToServerMessage::kShutdown; | 372 message.type = ClientToServerMessage::kShutdown; |
314 message.shutdown.token = shutdown_token; | 373 message.shutdown.token = shutdown_token; |
315 ServerToClientMessage response; | 374 ServerToClientMessage response; |
316 SendToCrashHandlerServer(pipe_name_16, | 375 SendToCrashHandlerServer(pipe_name_, |
317 reinterpret_cast<ClientToServerMessage&>(message), | 376 reinterpret_cast<ClientToServerMessage&>(message), |
318 &response); | 377 &response); |
319 } | 378 } |
320 | 379 |
321 for (auto& handle : thread_handles) | 380 for (auto& handle : thread_handles) |
322 WaitForSingleObject(handle.get(), INFINITE); | 381 WaitForSingleObject(handle.get(), INFINITE); |
323 | 382 |
324 // Deleting ClientData does a blocking wait until the threadpool executions | 383 // Deleting ClientData does a blocking wait until the threadpool executions |
325 // have terminated when unregistering them. | 384 // have terminated when unregistering them. |
326 { | 385 { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { | 560 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { |
502 // This function is executed on the thread pool. | 561 // This function is executed on the thread pool. |
503 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); | 562 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); |
504 base::AutoLock lock(*client->lock()); | 563 base::AutoLock lock(*client->lock()); |
505 | 564 |
506 // Post back to the main thread to have it delete this client record. | 565 // Post back to the main thread to have it delete this client record. |
507 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); | 566 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); |
508 } | 567 } |
509 | 568 |
510 } // namespace crashpad | 569 } // namespace crashpad |
OLD | NEW |