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 |