diff --git a/src/input_common.cpp b/src/input_common.cpp index d741b96e7..3120363fc 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -2,6 +2,7 @@ #include "config.h" #include +#include #include #include @@ -10,6 +11,7 @@ #endif #include #include +#include #include #include @@ -223,9 +225,27 @@ maybe_t input_event_queue_t::readch_timed() { if (auto evt = try_pop()) { return evt; } - const uint64_t usec_per_msec = 1000; - uint64_t timeout_usec = static_cast(wait_on_escape_ms) * usec_per_msec; - if (fd_readable_set_t::is_fd_readable(in_, timeout_usec)) { + // We are not prepared to handle a signal immediately; we only want to know if we get input on + // our fd before the timeout. Use pselect to block all signals; we will handle signals + // before the next call to getch(). + sigset_t sigs; + sigfillset(&sigs); + + // pselect expects timeouts in nanoseconds. + const uint64_t nsec_per_msec = 1000 * 1000; + const uint64_t nsec_per_sec = nsec_per_msec * 1000; + const uint64_t wait_nsec = wait_on_escape_ms * nsec_per_msec; + struct timespec timeout; + timeout.tv_sec = (wait_nsec) / nsec_per_sec; + timeout.tv_nsec = (wait_nsec) % nsec_per_sec; + + // We have one fd of interest. + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(in_, &fdset); + + int res = pselect(in_ + 1, &fdset, nullptr, nullptr, &timeout, &sigs); + if (res > 0) { return readch(); } return none();