When a USB-serial adapter disappears mid-run, writes to the open handle
fail with PermissionError, but serial.close() can block forever. Cleanup
then wedged after the second port closed and Ctrl+C could not break out,
because the main thread was stuck inside a blocking Windows call.
Close on a daemon thread and give up after CLOSE_TIMEOUT_S, so an
abandoned port can never hold up the exit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>