Skip to content

WebSocket shutdown can forcibly terminate the listener thread

Summary

The WebSocket shutdown path still calls TerminateThread if the listener thread does not exit within 1300 ms. Forced termination in MFC/CRT/networking code can leave locks, heap state, TLS state, or WinSock state corrupted.

This blocks Beta 0.7.3 because forced thread termination is not compatible with the release goal of absolute shutdown stability.

Evidence

  • srchybrid/WebSocket.cpp:631 waits for the listener thread.
  • srchybrid/WebSocket.cpp:634 calls TerminateThread on timeout.
  • srchybrid/WebSocket.cpp:641 deletes the CWinThread object after that path.

Execution Plan

  1. Revalidate why the listener can outlive the current wait.
  2. Make listener shutdown cooperative by combining termination signaling with socket/event wakeup.
  3. Remove the TerminateThread fallback.
  4. If the listener still fails to exit, log a release-grade error and keep ownership safe rather than corrupting process state.
  5. Align this work with BUG-079 so listener and accepted-client ownership use one coherent shutdown model.

Acceptance Criteria

  • No WebSocket shutdown path calls TerminateThread.
  • Listener shutdown is deterministic under normal, idle, and active-client cases.
  • Timeout handling cannot corrupt process state.

Validation

  • 2026-05-08: Done in app commit aa66699.
  • python -m emule_workspace validate --workspace-root .
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main
  • Code validation: StopSockets() no longer calls TerminateThread; listener timeout paths log and preserve ownership instead of forcibly killing MFC/CRT code.