diff --git a/CMakeLists.txt b/CMakeLists.txt index ca910d1..8416a09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,4 +92,9 @@ if (COMMANDLINE_TESTS) endif () enable_testing() add_test(NAME commandline_tests COMMAND commandline_tests) + if (UNIX) + add_test(NAME regression_issue42 + COMMAND bash "${CMAKE_SOURCE_DIR}/tests/regression_issue42.sh" "${CMAKE_BINARY_DIR}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + endif () endif () diff --git a/src/backends/InteractiveBackend.cpp b/src/backends/InteractiveBackend.cpp index 21781d9..44a5ed0 100644 --- a/src/backends/InteractiveBackend.cpp +++ b/src/backends/InteractiveBackend.cpp @@ -1,5 +1,7 @@ #include "InteractiveBackend.h" +#include + #include "impls.h" lk::InteractiveBackend::InteractiveBackend(const std::string& prompt) @@ -235,6 +237,10 @@ void lk::InteractiveBackend::input_thread_main() { if (m_key_debug) { fprintf(stderr, "c: 0x%.2x\n", c); } + if (c == EOF) { + m_shutdown.store(true); + break; + } std::unique_lock guard(m_current_buffer_mutex); if (c != '\t') { } diff --git a/tests/regression_issue42.sh b/tests/regression_issue42.sh new file mode 100755 index 0000000..d8134d6 --- /dev/null +++ b/tests/regression_issue42.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Regression test for #42: GNU screen -dmS causes commandline to break and CPU spin. +# +# Forced interactive mode + /dev/null stdin simulates the detached-screen scenario: +# stdin reaches EOF immediately. The input thread must detect EOF and shut down +# instead of spinning. +set -euo pipefail + +if [ ! -e /dev/null ] || ! command -v /usr/bin/time >/dev/null 2>&1; then + echo "SKIP: /usr/bin/time and /dev/null required (Unix-only regression test)" + exit 0 +fi + +BINARY="${1:-build}/commandline_test" + +TIME_OUT=$(mktemp) +trap 'rm -f "$TIME_OUT"' EXIT + +COMMANDLINE_FORCE_INTERACTIVE=1 \ + /usr/bin/time -o "$TIME_OUT" -v timeout 3 "$BINARY" \ + < /dev/null >/dev/null 2>/dev/null || true + +total_cpu=$(awk ' + /User time \(seconds\)/ { u = $NF } + /System time \(seconds\)/ { s = $NF } + END { + if (u == "" || s == "") exit 1 + print u + s + } +' "$TIME_OUT") || { echo "FAIL: could not parse CPU time from /usr/bin/time output"; exit 1; } + +if awk "BEGIN {exit !($total_cpu >= 0.3)}"; then + echo "FAIL: CPU spin detected: ${total_cpu}s CPU in 3s" + exit 1 +fi + +echo "PASS: no CPU spin (${total_cpu}s CPU in 3s)"