Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 16 matching lines...) Expand all Loading... | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 #include "client/windows/crash_generation/crash_generation_server.h" | 30 #include "client/windows/crash_generation/crash_generation_server.h" |
31 #include <windows.h> | 31 #include <windows.h> |
32 #include <cassert> | 32 #include <cassert> |
33 #include <list> | 33 #include <list> |
34 #include "client/windows/common/auto_critical_section.h" | 34 #include "client/windows/common/auto_critical_section.h" |
35 #include "processor/scoped_ptr.h" | 35 #include "processor/scoped_ptr.h" |
36 | 36 |
37 #include "client/windows/crash_generation/client_info.h" | |
Erik Wright
2010/09/16 21:06:59
Changed to a forward-decl in crash_generation_serv
| |
38 | |
37 namespace google_breakpad { | 39 namespace google_breakpad { |
38 | 40 |
41 // How long to wait for the server thread to begin listening or die trying | |
42 static const DWORD kMaxStartDelayMs = INFINITE; | |
43 | |
39 // Output buffer size. | 44 // Output buffer size. |
40 static const size_t kOutBufferSize = 64; | 45 static const size_t kOutBufferSize = 64; |
41 | 46 |
42 // Input buffer size. | 47 // Input buffer size. |
43 static const size_t kInBufferSize = 64; | 48 static const size_t kInBufferSize = 64; |
44 | 49 |
45 // Access flags for the client on the dump request event. | 50 // Access flags for the client on the dump request event. |
46 static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE; | 51 static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE; |
47 | 52 |
48 // Access flags for the client on the dump generated event. | 53 // Access flags for the client on the dump generated event. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 dump_callback_(dump_callback), | 115 dump_callback_(dump_callback), |
111 dump_context_(dump_context), | 116 dump_context_(dump_context), |
112 exit_callback_(exit_callback), | 117 exit_callback_(exit_callback), |
113 exit_context_(exit_context), | 118 exit_context_(exit_context), |
114 generate_dumps_(generate_dumps), | 119 generate_dumps_(generate_dumps), |
115 dump_generator_(NULL), | 120 dump_generator_(NULL), |
116 server_state_(IPC_SERVER_STATE_INITIAL), | 121 server_state_(IPC_SERVER_STATE_INITIAL), |
117 shutting_down_(false), | 122 shutting_down_(false), |
118 overlapped_(), | 123 overlapped_(), |
119 client_info_(NULL), | 124 client_info_(NULL), |
120 cleanup_item_count_(0) { | 125 cleanup_item_count_(0), |
126 server_start_complete_event_(NULL) { | |
121 InitializeCriticalSection(&clients_sync_); | 127 InitializeCriticalSection(&clients_sync_); |
122 | 128 |
123 if (dump_path) { | 129 if (dump_path) { |
124 dump_generator_.reset(new MinidumpGenerator(*dump_path)); | 130 dump_generator_.reset(new MinidumpGenerator(*dump_path)); |
125 } | 131 } |
126 } | 132 } |
127 | 133 |
128 CrashGenerationServer::~CrashGenerationServer() { | 134 CrashGenerationServer::~CrashGenerationServer() { |
129 // Indicate to existing threads that server is shutting down. | 135 // Indicate to existing threads that server is shutting down. |
130 shutting_down_ = true; | 136 shutting_down_ = true; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 if (server_alive_handle_) { | 199 if (server_alive_handle_) { |
194 // Release the mutex before closing the handle so that clients requesting | 200 // Release the mutex before closing the handle so that clients requesting |
195 // dumps wait for a long time for the server to generate a dump. | 201 // dumps wait for a long time for the server to generate a dump. |
196 ReleaseMutex(server_alive_handle_); | 202 ReleaseMutex(server_alive_handle_); |
197 CloseHandle(server_alive_handle_); | 203 CloseHandle(server_alive_handle_); |
198 } | 204 } |
199 | 205 |
200 DeleteCriticalSection(&clients_sync_); | 206 DeleteCriticalSection(&clients_sync_); |
201 } | 207 } |
202 | 208 |
203 bool CrashGenerationServer::Start() { | 209 bool CrashGenerationServer::Start() { |
Erik Wright
2010/09/16 21:06:59
A non-negligible change in this function's behavio
| |
204 server_state_ = IPC_SERVER_STATE_INITIAL; | 210 server_state_ = IPC_SERVER_STATE_INITIAL; |
205 | 211 |
212 server_start_complete_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | |
213 if (!server_start_complete_event_) { | |
214 return false; | |
215 } | |
216 | |
206 server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); | 217 server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); |
207 if (!server_alive_handle_) { | 218 if (!server_alive_handle_) { |
208 return false; | 219 return false; |
209 } | 220 } |
210 | 221 |
211 // Event to signal the client connection and pipe reads and writes. | 222 // Event to signal the client connection and pipe reads and writes. |
212 overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. | 223 overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. |
213 TRUE, // Manual reset. | 224 TRUE, // Manual reset. |
214 FALSE, // Initially signaled. | 225 FALSE, // Initially signaled. |
215 NULL); // Name. | 226 NULL); // Name. |
(...skipping 18 matching lines...) Expand all Loading... | |
234 kOutBufferSize, | 245 kOutBufferSize, |
235 kInBufferSize, | 246 kInBufferSize, |
236 0, | 247 0, |
237 pipe_sec_attrs_); | 248 pipe_sec_attrs_); |
238 if (pipe_ == INVALID_HANDLE_VALUE) { | 249 if (pipe_ == INVALID_HANDLE_VALUE) { |
239 return false; | 250 return false; |
240 } | 251 } |
241 | 252 |
242 // Signal the event to start a separate thread to handle | 253 // Signal the event to start a separate thread to handle |
243 // client connections. | 254 // client connections. |
244 return SetEvent(overlapped_.hEvent) != FALSE; | 255 if (SetEvent(overlapped_.hEvent) == FALSE) { |
256 return false; | |
257 } | |
258 | |
259 if (WaitForSingleObject(server_start_complete_event_, kMaxStartDelayMs) != | |
Erik Wright
2010/09/16 21:06:59
I don't think it is possible for the worker thread
| |
260 WAIT_OBJECT_0) { | |
261 return false; | |
262 } | |
263 | |
264 // If we are in error state, it's probably because we failed to start, | |
265 // though it could theoretically be due to a failure between succesful start | |
266 // and our return from the above wait. | |
267 return server_state_ != IPC_SERVER_STATE_ERROR; | |
245 } | 268 } |
246 | 269 |
247 // If the server thread serving clients ever gets into the | 270 // If the server thread serving clients ever gets into the |
248 // ERROR state, reset the event, close the pipe and remain | 271 // ERROR state, reset the event, close the pipe and remain |
249 // in the error state forever. Error state means something | 272 // in the error state forever. Error state means something |
250 // that we didn't account for has happened, and it's dangerous | 273 // that we didn't account for has happened, and it's dangerous |
251 // to do anything unknowingly. | 274 // to do anything unknowingly. |
252 void CrashGenerationServer::HandleErrorState() { | 275 void CrashGenerationServer::HandleErrorState() { |
253 assert(server_state_ == IPC_SERVER_STATE_ERROR); | 276 assert(server_state_ == IPC_SERVER_STATE_ERROR); |
254 | 277 |
(...skipping 21 matching lines...) Expand all Loading... | |
276 | 299 |
277 // When the server thread serving clients is in the INITIAL state, | 300 // When the server thread serving clients is in the INITIAL state, |
278 // try to connect to the pipe asynchronously. If the connection | 301 // try to connect to the pipe asynchronously. If the connection |
279 // finishes synchronously, directly go into the CONNECTED state; | 302 // finishes synchronously, directly go into the CONNECTED state; |
280 // otherwise go into the CONNECTING state. For any problems, go | 303 // otherwise go into the CONNECTING state. For any problems, go |
281 // into the ERROR state. | 304 // into the ERROR state. |
282 void CrashGenerationServer::HandleInitialState() { | 305 void CrashGenerationServer::HandleInitialState() { |
283 assert(server_state_ == IPC_SERVER_STATE_INITIAL); | 306 assert(server_state_ == IPC_SERVER_STATE_INITIAL); |
284 | 307 |
285 if (!ResetEvent(overlapped_.hEvent)) { | 308 if (!ResetEvent(overlapped_.hEvent)) { |
286 server_state_ = IPC_SERVER_STATE_ERROR; | 309 EnterErrorState(); |
287 return; | 310 } else { |
311 bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE; | |
312 | |
313 // From MSDN, it is not clear that when ConnectNamedPipe is used | |
314 // in an overlapped mode, will it ever return non-zero value, and | |
315 // if so, in what cases. | |
316 assert(!success); | |
317 | |
318 DWORD error_code = GetLastError(); | |
319 switch (error_code) { | |
320 case ERROR_IO_PENDING: | |
321 EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING); | |
322 break; | |
323 | |
324 case ERROR_PIPE_CONNECTED: | |
325 EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); | |
326 break; | |
327 | |
328 default: | |
329 EnterErrorState(); | |
330 break; | |
331 } | |
288 } | 332 } |
289 | 333 |
290 bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE; | 334 if (!SetEvent(server_start_complete_event_)) { |
291 | 335 EnterErrorState(); |
292 // From MSDN, it is not clear that when ConnectNamedPipe is used | |
293 // in an overlapped mode, will it ever return non-zero value, and | |
294 // if so, in what cases. | |
295 assert(!success); | |
296 | |
297 DWORD error_code = GetLastError(); | |
298 switch (error_code) { | |
299 case ERROR_IO_PENDING: | |
300 server_state_ = IPC_SERVER_STATE_CONNECTING; | |
301 break; | |
302 | |
303 case ERROR_PIPE_CONNECTED: | |
304 if (SetEvent(overlapped_.hEvent)) { | |
305 server_state_ = IPC_SERVER_STATE_CONNECTED; | |
306 } else { | |
307 server_state_ = IPC_SERVER_STATE_ERROR; | |
308 } | |
309 break; | |
310 | |
311 default: | |
312 server_state_ = IPC_SERVER_STATE_ERROR; | |
313 break; | |
314 } | 336 } |
315 } | 337 } |
316 | 338 |
317 // When the server thread serving the clients is in the CONNECTING state, | 339 // When the server thread serving the clients is in the CONNECTING state, |
318 // try to get the result of the asynchronous connection request using | 340 // try to get the result of the asynchronous connection request using |
319 // the OVERLAPPED object. If the result indicates the connection is done, | 341 // the OVERLAPPED object. If the result indicates the connection is done, |
320 // go into the CONNECTED state. If the result indicates I/O is still | 342 // go into the CONNECTED state. If the result indicates I/O is still |
321 // INCOMPLETE, remain in the CONNECTING state. For any problems, | 343 // INCOMPLETE, remain in the CONNECTING state. For any problems, |
322 // go into the DISCONNECTING state. | 344 // go into the DISCONNECTING state. |
323 void CrashGenerationServer::HandleConnectingState() { | 345 void CrashGenerationServer::HandleConnectingState() { |
324 assert(server_state_ == IPC_SERVER_STATE_CONNECTING); | 346 assert(server_state_ == IPC_SERVER_STATE_CONNECTING); |
325 | 347 |
326 DWORD bytes_count = 0; | 348 DWORD bytes_count = 0; |
327 bool success = GetOverlappedResult(pipe_, | 349 bool success = GetOverlappedResult(pipe_, |
328 &overlapped_, | 350 &overlapped_, |
329 &bytes_count, | 351 &bytes_count, |
330 FALSE) != FALSE; | 352 FALSE) != FALSE; |
331 | 353 |
332 if (success) { | 354 if (success) { |
333 server_state_ = IPC_SERVER_STATE_CONNECTED; | 355 EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); |
334 return; | 356 } else if (GetLastError() != ERROR_IO_INCOMPLETE) { |
335 } | 357 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
336 | |
337 if (GetLastError() != ERROR_IO_INCOMPLETE) { | |
338 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | |
339 } | 358 } |
340 } | 359 } |
341 | 360 |
342 // When the server thread serving the clients is in the CONNECTED state, | 361 // When the server thread serving the clients is in the CONNECTED state, |
343 // try to issue an asynchronous read from the pipe. If read completes | 362 // try to issue an asynchronous read from the pipe. If read completes |
344 // synchronously or if I/O is pending then go into the READING state. | 363 // synchronously or if I/O is pending then go into the READING state. |
345 // For any problems, go into the DISCONNECTING state. | 364 // For any problems, go into the DISCONNECTING state. |
346 void CrashGenerationServer::HandleConnectedState() { | 365 void CrashGenerationServer::HandleConnectedState() { |
347 assert(server_state_ == IPC_SERVER_STATE_CONNECTED); | 366 assert(server_state_ == IPC_SERVER_STATE_CONNECTED); |
348 | 367 |
349 DWORD bytes_count = 0; | 368 DWORD bytes_count = 0; |
350 memset(&msg_, 0, sizeof(msg_)); | 369 memset(&msg_, 0, sizeof(msg_)); |
351 bool success = ReadFile(pipe_, | 370 bool success = ReadFile(pipe_, |
352 &msg_, | 371 &msg_, |
353 sizeof(msg_), | 372 sizeof(msg_), |
354 &bytes_count, | 373 &bytes_count, |
355 &overlapped_) != FALSE; | 374 &overlapped_) != FALSE; |
356 | 375 |
357 // Note that the asynchronous read issued above can finish before the | 376 // Note that the asynchronous read issued above can finish before the |
358 // code below executes. But, it is okay to change state after issuing | 377 // code below executes. But, it is okay to change state after issuing |
359 // the asynchronous read. This is because even if the asynchronous read | 378 // the asynchronous read. This is because even if the asynchronous read |
360 // is done, the callback for it would not be executed until the current | 379 // is done, the callback for it would not be executed until the current |
361 // thread finishes its execution. | 380 // thread finishes its execution. |
362 if (success || GetLastError() == ERROR_IO_PENDING) { | 381 if (success || GetLastError() == ERROR_IO_PENDING) { |
363 server_state_ = IPC_SERVER_STATE_READING; | 382 EnterStateWhenSignaled(IPC_SERVER_STATE_READING); |
364 } else { | 383 } else { |
365 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 384 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
366 } | 385 } |
367 } | 386 } |
368 | 387 |
369 // When the server thread serving the clients is in the READING state, | 388 // When the server thread serving the clients is in the READING state, |
370 // try to get the result of the async read. If async read is done, | 389 // try to get the result of the async read. If async read is done, |
371 // go into the READ_DONE state. For any problems, go into the | 390 // go into the READ_DONE state. For any problems, go into the |
372 // DISCONNECTING state. | 391 // DISCONNECTING state. |
373 void CrashGenerationServer::HandleReadingState() { | 392 void CrashGenerationServer::HandleReadingState() { |
374 assert(server_state_ == IPC_SERVER_STATE_READING); | 393 assert(server_state_ == IPC_SERVER_STATE_READING); |
375 | 394 |
376 DWORD bytes_count = 0; | 395 DWORD bytes_count = 0; |
377 bool success = GetOverlappedResult(pipe_, | 396 bool success = GetOverlappedResult(pipe_, |
378 &overlapped_, | 397 &overlapped_, |
379 &bytes_count, | 398 &bytes_count, |
380 FALSE) != FALSE; | 399 FALSE) != FALSE; |
381 | 400 |
382 if (success && bytes_count == sizeof(ProtocolMessage)) { | 401 if (success && bytes_count == sizeof(ProtocolMessage)) { |
383 server_state_ = IPC_SERVER_STATE_READ_DONE; | 402 EnterStateImmediately(IPC_SERVER_STATE_READ_DONE); |
384 return; | 403 } else { |
404 // We should never get an I/O incomplete since we should not execute this | |
405 // unless the Read has finished and the overlapped event is signaled. If | |
406 // we do get INCOMPLETE, we have a bug in our code. | |
407 assert(GetLastError() != ERROR_IO_INCOMPLETE); | |
408 | |
409 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); | |
385 } | 410 } |
386 | |
387 DWORD error_code; | |
388 error_code = GetLastError(); | |
389 | |
390 // We should never get an I/O incomplete since we should not execute this | |
391 // unless the Read has finished and the overlapped event is signaled. If | |
392 // we do get INCOMPLETE, we have a bug in our code. | |
393 assert(error_code != ERROR_IO_INCOMPLETE); | |
394 | |
395 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | |
396 } | 411 } |
397 | 412 |
398 // When the server thread serving the client is in the READ_DONE state, | 413 // When the server thread serving the client is in the READ_DONE state, |
399 // validate the client's request message, register the client by | 414 // validate the client's request message, register the client by |
400 // creating appropriate objects and prepare the response. Then try to | 415 // creating appropriate objects and prepare the response. Then try to |
401 // write the response to the pipe asynchronously. If that succeeds, | 416 // write the response to the pipe asynchronously. If that succeeds, |
402 // go into the WRITING state. For any problems, go into the DISCONNECTING | 417 // go into the WRITING state. For any problems, go into the DISCONNECTING |
403 // state. | 418 // state. |
404 void CrashGenerationServer::HandleReadDoneState() { | 419 void CrashGenerationServer::HandleReadDoneState() { |
405 assert(server_state_ == IPC_SERVER_STATE_READ_DONE); | 420 assert(server_state_ == IPC_SERVER_STATE_READ_DONE); |
406 | 421 |
407 if (!IsClientRequestValid(msg_)) { | 422 if (!IsClientRequestValid(msg_)) { |
408 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 423 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
409 return; | 424 return; |
410 } | 425 } |
411 | 426 |
412 scoped_ptr<ClientInfo> client_info( | 427 scoped_ptr<ClientInfo> client_info( |
413 new ClientInfo(this, | 428 new ClientInfo(this, |
414 msg_.pid, | 429 msg_.pid, |
415 msg_.dump_type, | 430 msg_.dump_type, |
416 msg_.thread_id, | 431 msg_.thread_id, |
417 msg_.exception_pointers, | 432 msg_.exception_pointers, |
418 msg_.assert_info, | 433 msg_.assert_info, |
419 msg_.custom_client_info)); | 434 msg_.custom_client_info)); |
420 | 435 |
421 if (!client_info->Initialize()) { | 436 if (!client_info->Initialize()) { |
422 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 437 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
423 return; | 438 return; |
424 } | 439 } |
425 | 440 |
441 // Issues an asynchronous WriteFile call if successful. | |
442 // Iff successful, assigns ownership of the client_info pointer to the server | |
443 // instance, in which case we must be sure not to free it in this function. | |
426 if (!RespondToClient(client_info.get())) { | 444 if (!RespondToClient(client_info.get())) { |
427 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 445 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
428 return; | 446 return; |
429 } | 447 } |
430 | 448 |
449 client_info_ = client_info.release(); | |
450 | |
431 // Note that the asynchronous write issued by RespondToClient function | 451 // Note that the asynchronous write issued by RespondToClient function |
432 // can finish before the code below executes. But it is okay to change | 452 // can finish before the code below executes. But it is okay to change |
433 // state after issuing the asynchronous write. This is because even if | 453 // state after issuing the asynchronous write. This is because even if |
434 // the asynchronous write is done, the callback for it would not be | 454 // the asynchronous write is done, the callback for it would not be |
435 // executed until the current thread finishes its execution. | 455 // executed until the current thread finishes its execution. |
436 server_state_ = IPC_SERVER_STATE_WRITING; | 456 EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING); |
437 client_info_ = client_info.release(); | |
438 } | 457 } |
439 | 458 |
440 // When the server thread serving the clients is in the WRITING state, | 459 // When the server thread serving the clients is in the WRITING state, |
441 // try to get the result of the async write. If the async write is done, | 460 // try to get the result of the async write. If the async write is done, |
442 // go into the WRITE_DONE state. For any problems, go into the | 461 // go into the WRITE_DONE state. For any problems, go into the |
443 // DISONNECTING state. | 462 // DISONNECTING state. |
444 void CrashGenerationServer::HandleWritingState() { | 463 void CrashGenerationServer::HandleWritingState() { |
445 assert(server_state_ == IPC_SERVER_STATE_WRITING); | 464 assert(server_state_ == IPC_SERVER_STATE_WRITING); |
446 | 465 |
447 DWORD bytes_count = 0; | 466 DWORD bytes_count = 0; |
448 bool success = GetOverlappedResult(pipe_, | 467 bool success = GetOverlappedResult(pipe_, |
449 &overlapped_, | 468 &overlapped_, |
450 &bytes_count, | 469 &bytes_count, |
451 FALSE) != FALSE; | 470 FALSE) != FALSE; |
452 | 471 |
453 if (success) { | 472 if (success) { |
454 server_state_ = IPC_SERVER_STATE_WRITE_DONE; | 473 EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE); |
455 return; | 474 return; |
456 } | 475 } |
457 | 476 |
458 DWORD error_code; | |
459 error_code = GetLastError(); | |
460 | |
461 // We should never get an I/O incomplete since we should not execute this | 477 // We should never get an I/O incomplete since we should not execute this |
462 // unless the Write has finished and the overlapped event is signaled. If | 478 // unless the Write has finished and the overlapped event is signaled. If |
463 // we do get INCOMPLETE, we have a bug in our code. | 479 // we do get INCOMPLETE, we have a bug in our code. |
464 assert(error_code != ERROR_IO_INCOMPLETE); | 480 assert(GetLastError() != ERROR_IO_INCOMPLETE); |
465 | 481 |
466 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 482 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
467 } | 483 } |
468 | 484 |
469 // When the server thread serving the clients is in the WRITE_DONE state, | 485 // When the server thread serving the clients is in the WRITE_DONE state, |
470 // try to issue an async read on the pipe. If the read completes synchronously | 486 // try to issue an async read on the pipe. If the read completes synchronously |
471 // or if I/O is still pending then go into the READING_ACK state. For any | 487 // or if I/O is still pending then go into the READING_ACK state. For any |
472 // issues, go into the DISCONNECTING state. | 488 // issues, go into the DISCONNECTING state. |
473 void CrashGenerationServer::HandleWriteDoneState() { | 489 void CrashGenerationServer::HandleWriteDoneState() { |
474 assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE); | 490 assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE); |
475 | 491 |
476 server_state_ = IPC_SERVER_STATE_READING_ACK; | |
477 | |
478 DWORD bytes_count = 0; | 492 DWORD bytes_count = 0; |
479 bool success = ReadFile(pipe_, | 493 bool success = ReadFile(pipe_, |
480 &msg_, | 494 &msg_, |
481 sizeof(msg_), | 495 sizeof(msg_), |
482 &bytes_count, | 496 &bytes_count, |
483 &overlapped_) != FALSE; | 497 &overlapped_) != FALSE; |
484 | 498 |
485 if (success) { | 499 if (success) { |
486 return; | 500 EnterStateImmediately(IPC_SERVER_STATE_READING_ACK); |
487 } | 501 } else if (GetLastError() == ERROR_IO_PENDING) { |
488 | 502 EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK); |
489 DWORD error_code = GetLastError(); | 503 } else { |
490 | 504 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
491 if (error_code != ERROR_IO_PENDING) { | |
492 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | |
493 } | 505 } |
494 } | 506 } |
495 | 507 |
496 // When the server thread serving the clients is in the READING_ACK state, | 508 // When the server thread serving the clients is in the READING_ACK state, |
497 // try to get result of async read. Go into the DISCONNECTING state. | 509 // try to get result of async read. Go into the DISCONNECTING state. |
498 void CrashGenerationServer::HandleReadingAckState() { | 510 void CrashGenerationServer::HandleReadingAckState() { |
499 assert(server_state_ == IPC_SERVER_STATE_READING_ACK); | 511 assert(server_state_ == IPC_SERVER_STATE_READING_ACK); |
500 | 512 |
501 DWORD bytes_count = 0; | 513 DWORD bytes_count = 0; |
502 bool success = GetOverlappedResult(pipe_, | 514 bool success = GetOverlappedResult(pipe_, |
503 &overlapped_, | 515 &overlapped_, |
504 &bytes_count, | 516 &bytes_count, |
505 FALSE) != FALSE; | 517 FALSE) != FALSE; |
506 | 518 |
507 if (success) { | 519 if (success) { |
508 // The connection handshake with the client is now complete; perform | 520 // The connection handshake with the client is now complete; perform |
509 // the callback. | 521 // the callback. |
510 if (connect_callback_) { | 522 if (connect_callback_) { |
511 connect_callback_(connect_context_, client_info_); | 523 connect_callback_(connect_context_, client_info_); |
512 } | 524 } |
513 } else { | 525 } else { |
514 DWORD error_code = GetLastError(); | |
515 | |
516 // We should never get an I/O incomplete since we should not execute this | 526 // We should never get an I/O incomplete since we should not execute this |
517 // unless the Read has finished and the overlapped event is signaled. If | 527 // unless the Read has finished and the overlapped event is signaled. If |
518 // we do get INCOMPLETE, we have a bug in our code. | 528 // we do get INCOMPLETE, we have a bug in our code. |
519 assert(error_code != ERROR_IO_INCOMPLETE); | 529 assert(GetLastError() != ERROR_IO_INCOMPLETE); |
520 } | 530 } |
521 | 531 |
522 server_state_ = IPC_SERVER_STATE_DISCONNECTING; | 532 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |
523 } | 533 } |
524 | 534 |
525 // When the server thread serving the client is in the DISCONNECTING state, | 535 // When the server thread serving the client is in the DISCONNECTING state, |
526 // disconnect from the pipe and reset the event. If anything fails, go into | 536 // disconnect from the pipe and reset the event. If anything fails, go into |
527 // the ERROR state. If it goes well, go into the INITIAL state and set the | 537 // the ERROR state. If it goes well, go into the INITIAL state and set the |
528 // event to start all over again. | 538 // event to start all over again. |
529 void CrashGenerationServer::HandleDisconnectingState() { | 539 void CrashGenerationServer::HandleDisconnectingState() { |
530 assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); | 540 assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); |
531 | 541 |
532 // Done serving the client. | 542 // Done serving the client. |
533 client_info_ = NULL; | 543 client_info_ = NULL; |
534 | 544 |
535 overlapped_.Internal = NULL; | 545 overlapped_.Internal = NULL; |
536 overlapped_.InternalHigh = NULL; | 546 overlapped_.InternalHigh = NULL; |
537 overlapped_.Offset = 0; | 547 overlapped_.Offset = 0; |
538 overlapped_.OffsetHigh = 0; | 548 overlapped_.OffsetHigh = 0; |
539 overlapped_.Pointer = NULL; | 549 overlapped_.Pointer = NULL; |
540 | 550 |
541 if (!ResetEvent(overlapped_.hEvent)) { | 551 if (!ResetEvent(overlapped_.hEvent)) { |
542 server_state_ = IPC_SERVER_STATE_ERROR; | 552 EnterErrorState(); |
543 return; | 553 return; |
544 } | 554 } |
545 | 555 |
546 if (!DisconnectNamedPipe(pipe_)) { | 556 if (!DisconnectNamedPipe(pipe_)) { |
547 server_state_ = IPC_SERVER_STATE_ERROR; | 557 EnterErrorState(); |
548 return; | 558 return; |
549 } | 559 } |
550 | 560 |
551 // If the server is shutting down do not connect to the | 561 // If the server is shutting down do not connect to the |
552 // next client. | 562 // next client. |
553 if (shutting_down_) { | 563 if (shutting_down_) { |
554 return; | 564 return; |
555 } | 565 } |
556 | 566 |
557 server_state_ = IPC_SERVER_STATE_INITIAL; | 567 EnterStateImmediately(IPC_SERVER_STATE_INITIAL); |
568 } | |
569 | |
570 void CrashGenerationServer::EnterErrorState() { | |
Erik Wright
2010/09/16 21:06:59
May these functions aid in readability, and preven
| |
571 SetEvent(overlapped_.hEvent); | |
572 server_state_ = IPC_SERVER_STATE_ERROR; | |
573 } | |
574 | |
575 void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) { | |
576 server_state_ = state; | |
577 } | |
578 | |
579 void CrashGenerationServer::EnterStateImmediately(IPCServerState state) { | |
580 server_state_ = state; | |
581 | |
558 if (!SetEvent(overlapped_.hEvent)) { | 582 if (!SetEvent(overlapped_.hEvent)) { |
559 server_state_ = IPC_SERVER_STATE_ERROR; | 583 server_state_ = IPC_SERVER_STATE_ERROR; |
560 } | 584 } |
561 } | 585 } |
562 | 586 |
563 bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, | 587 bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, |
564 ProtocolMessage* reply) const { | 588 ProtocolMessage* reply) const { |
565 reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE; | 589 reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE; |
566 reply->pid = GetCurrentProcessId(); | 590 reply->pid = GetCurrentProcessId(); |
567 | 591 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
613 &reply->server_alive_handle, | 637 &reply->server_alive_handle, |
614 kMutexAccess, | 638 kMutexAccess, |
615 FALSE, | 639 FALSE, |
616 0)) { | 640 0)) { |
617 return false; | 641 return false; |
618 } | 642 } |
619 | 643 |
620 return true; | 644 return true; |
621 } | 645 } |
622 | 646 |
623 bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) { | 647 bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) { |
Erik Wright
2010/09/16 21:06:59
There was a bug in this function where it could ta
| |
624 ProtocolMessage reply; | 648 ProtocolMessage reply; |
625 if (!PrepareReply(*client_info, &reply)) { | 649 if (!PrepareReply(*client_info, &reply)) { |
626 return false; | 650 return false; |
627 } | 651 } |
628 | 652 |
629 if (!AddClient(client_info)) { | |
630 return false; | |
631 } | |
632 | |
633 DWORD bytes_count = 0; | 653 DWORD bytes_count = 0; |
634 bool success = WriteFile(pipe_, | 654 bool success = WriteFile(pipe_, |
635 &reply, | 655 &reply, |
636 sizeof(reply), | 656 sizeof(reply), |
637 &bytes_count, | 657 &bytes_count, |
638 &overlapped_) != FALSE; | 658 &overlapped_) != FALSE; |
639 | 659 |
640 return success || GetLastError() == ERROR_IO_PENDING; | 660 if (!success && GetLastError() != ERROR_IO_PENDING) { |
661 return false; | |
662 } | |
663 | |
664 // Takes over ownership of client_info. We MUST return true if AddClient | |
665 // succeeds. | |
666 if (!AddClient(client_info)) { | |
667 return false; | |
668 } | |
669 | |
670 return true; | |
641 } | 671 } |
642 | 672 |
643 // The server thread servicing the clients runs this method. The method | 673 // The server thread servicing the clients runs this method. The method |
644 // implements the state machine described in ReadMe.txt along with the | 674 // implements the state machine described in ReadMe.txt along with the |
645 // helper methods HandleXXXState. | 675 // helper methods HandleXXXState. |
646 void CrashGenerationServer::HandleConnectionRequest() { | 676 void CrashGenerationServer::HandleConnectionRequest() { |
647 // If we are shutting doen then get into ERROR state, reset the event so more | 677 // If we are shutting doen then get into ERROR state, reset the event so more |
648 // workers don't run and return immediately. | 678 // workers don't run and return immediately. |
649 if (shutting_down_) { | 679 if (shutting_down_) { |
650 server_state_ = IPC_SERVER_STATE_ERROR; | 680 server_state_ = IPC_SERVER_STATE_ERROR; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
732 { | 762 { |
733 AutoCriticalSection lock(&clients_sync_); | 763 AutoCriticalSection lock(&clients_sync_); |
734 clients_.push_back(client_info); | 764 clients_.push_back(client_info); |
735 } | 765 } |
736 | 766 |
737 return true; | 767 return true; |
738 } | 768 } |
739 | 769 |
740 // static | 770 // static |
741 void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { | 771 void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { |
742 assert (context); | 772 assert(context); |
743 | 773 |
744 CrashGenerationServer* obj = | 774 CrashGenerationServer* obj = |
745 reinterpret_cast<CrashGenerationServer*>(context); | 775 reinterpret_cast<CrashGenerationServer*>(context); |
746 obj->HandleConnectionRequest(); | 776 obj->HandleConnectionRequest(); |
747 } | 777 } |
748 | 778 |
749 // static | 779 // static |
750 void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { | 780 void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { |
751 assert(context); | 781 assert(context); |
752 ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context); | 782 ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
845 client_thread_id, | 875 client_thread_id, |
846 GetCurrentThreadId(), | 876 GetCurrentThreadId(), |
847 client_ex_info, | 877 client_ex_info, |
848 client.assert_info(), | 878 client.assert_info(), |
849 client.dump_type(), | 879 client.dump_type(), |
850 true, | 880 true, |
851 dump_path); | 881 dump_path); |
852 } | 882 } |
853 | 883 |
854 } // namespace google_breakpad | 884 } // namespace google_breakpad |
OLD | NEW |