| 424 | } |
| 425 | |
| 426 | void CECSocket::OnOutput() |
| 427 | { |
| 428 | while (!m_output_queue.empty()) { |
| 429 | CQueuedData* data = m_output_queue.front(); |
| 430 | uint32 written = data->WriteToSocket(this); |
| 431 | if (!data->GetUnreadDataLength()) { |
| 432 | m_output_queue.pop_front(); |
| 433 | delete data; |
| 434 | } |
| 435 | if (SocketError()) { |
| 436 | if (!WouldBlock()) { |
| 437 | // real error, abort |
| 438 | AddDebugLogLineN(logEC, "OnOutput: socket error"); |
| 439 | OnError(); |
| 440 | return; |
| 441 | } |
| 442 | // Now it's just a blocked socket. |
| 443 | if ( m_use_events ) { |
| 444 | // Event driven logic: return, OnOutput() will be called again later |
| 445 | return; |
| 446 | } |
| 447 | // Synchronous call: wait (for max 10 secs) |
| 448 | if ( !WaitSocketWrite(10, 0) ) { |
| 449 | // Still not through ? |
| 450 | if (WouldBlock()) { |
| 451 | // WouldBlock() is only EAGAIN or EWOULD_BLOCK, |
| 452 | // and those shouldn't create an infinite wait. |
| 453 | // So give it another chance. |
| 454 | continue; |
| 455 | } else { |
| 456 | AddDebugLogLineN(logEC, "OnOutput: socket error in sync wait"); |
| 457 | OnError(); |
| 458 | break; |
| 459 | } |
| 460 | } |
| 461 | } else if (written == 0) { |
| 462 | // CAsioSocketImpl::Write returns 0 with no SocketError |
| 463 | // set when a previous async send is still in flight |
| 464 | // (m_sendBuffer != null) -- pure backpressure, not a |
| 465 | // real error. Treat as "would block": yield to the |
| 466 | // event loop so the asio HandleSend callback can clear |
| 467 | // m_sendBuffer and re-fire OnOutput via |
| 468 | // CoreNotify_LibSocketSend. Without this, the loop |
| 469 | // re-reads the same queue head and re-calls Write(), |
| 470 | // pegging the main thread at 100% CPU until asio |
| 471 | // catches up. Large EC replies (e.g. status response |
| 472 | // after a batch ed2k-link add) hit this hard because |
| 473 | // they're chopped into many asio-sized chunks and the |
| 474 | // main thread can't service other wx events during |
| 475 | // the spin. |
| 476 | if (m_use_events) { |
| 477 | return; |
| 478 | } |
| 479 | // Synchronous path: same fallback as the SocketError |
| 480 | // case below. |
| 481 | if (!WaitSocketWrite(10, 0)) { |
| 482 | AddDebugLogLineN(logEC, "OnOutput: 10s wait elapsed in zero-write backpressure"); |
| 483 | OnError(); |
no test coverage detected