Index: util/win/registration_protocol_win.cc |
diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc |
index 38b1b45195a6b86f2353da09e1da04e8f5f9252d..eff27e2855028e1483fb027e5ae9e38837365f88 100644 |
--- a/util/win/registration_protocol_win.cc |
+++ b/util/win/registration_protocol_win.cc |
@@ -24,8 +24,22 @@ namespace crashpad { |
bool SendToCrashHandlerServer(const base::string16& pipe_name, |
const crashpad::ClientToServerMessage& message, |
crashpad::ServerToClientMessage* response) { |
- int tries = 0; |
- for (;;) { |
+ // Retry CreateFile() in a loop. If the handler isn’t actively waiting in |
+ // ConnectNamedPipe() on a pipe instance because it’s busy doing something |
+ // else, CreateFile() will fail with ERROR_PIPE_BUSY. WaitNamedPipe() waits |
+ // until a pipe instance is ready, but there’s no way to wait for this |
+ // condition and atomically open the client side of the pipe in a single |
+ // operation. CallNamedPipe() implements similar retry logic to this, also in |
+ // user-mode code. |
+ // |
+ // This loop is only intended to retry on ERROR_PIPE_BUSY. Notably, if the |
+ // handler is so lazy that it hasn’t even called CreateNamedPipe() yet, |
+ // CreateFile() will fail with ERROR_FILE_NOT_FOUND, and this function is |
+ // expected to fail without retrying anything. If the handler is started at |
+ // around the same time as its client, something external to this code must be |
+ // done to guarantee correct ordering. When the client starts the handler |
+ // itself, CrashpadClient::StartHandler() provides this synchronization. |
+ for (int tries = 0;;) { |
ScopedFileHANDLE pipe( |
CreateFile(pipe_name.c_str(), |
GENERIC_READ | GENERIC_WRITE, |
@@ -65,12 +79,12 @@ bool SendToCrashHandlerServer(const base::string16& pipe_name, |
&bytes_read, |
nullptr); |
if (!result) { |
- LOG(ERROR) << "TransactNamedPipe: expected " << sizeof(*response) |
- << ", observed " << bytes_read; |
+ PLOG(ERROR) << "TransactNamedPipe"; |
return false; |
} |
if (bytes_read != sizeof(*response)) { |
- LOG(ERROR) << "TransactNamedPipe read incorrect number of bytes"; |
+ LOG(ERROR) << "TransactNamedPipe: expected " << sizeof(*response) |
+ << ", observed " << bytes_read; |
return false; |
} |
return true; |