libutil/libmain: never mask SIGWINCH
we need to cache the current terminal size for progress bar reasons, but we don't want to catch SIGWINCH to update the current terminal size from a dedicated thread for repl reasons. a SIGWINCH handler function is much easier to square with these requirements than communication with another thread to have it change its signal mask, and since any races in handler code affect only progress bar output and only very rarely (if ever) we'd better chose the simplest approach. the progress bar could set a handler of its own for this purpose, but we would much rather replace it instead fixes #1246 Change-Id: I814d9aaf1b6fbb6a8cefc5af675a3aa372549dc8
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "libutil/fmt.hh"
|
||||
#include "libutil/terminal.hh"
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/file-system.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
@@ -65,6 +66,9 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT
|
||||
{
|
||||
auto s = rl->ask(promptForType(promptType));
|
||||
|
||||
// rustyline temporarily sets a SIGWINCH handler
|
||||
KJ_DEFER(invalidateWindowSize());
|
||||
|
||||
return match_result(
|
||||
std::move(s),
|
||||
[&](rust::String ok) {
|
||||
|
||||
@@ -176,12 +176,6 @@ void initNix()
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
/* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH.
|
||||
* Instead, add a dummy sigaction handler, and signalHandlerThread
|
||||
* can handle the rest. */
|
||||
act.sa_handler = sigHandler;
|
||||
if (sigaction(SIGWINCH, &act, 0)) throw SysError("handling SIGWINCH");
|
||||
|
||||
/* Disable SA_RESTART for interrupts, so that system calls on this thread
|
||||
* error with EINTR like they do on Linux.
|
||||
* Most signals on BSD systems default to SA_RESTART on, but Nix
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <atomic>
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -118,8 +119,6 @@ static void signalHandlerThread(sigset_t set)
|
||||
}
|
||||
} else if (signal == SIGTERM || signal == SIGHUP) {
|
||||
triggerInterrupt();
|
||||
} else if (signal == SIGWINCH) {
|
||||
updateWindowSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,7 +163,7 @@ void saveSignalMask() {
|
||||
|
||||
void startSignalHandlerThread()
|
||||
{
|
||||
updateWindowSize();
|
||||
invalidateWindowSize();
|
||||
saveSignalMask();
|
||||
|
||||
sigset_t set;
|
||||
@@ -173,10 +172,11 @@ void startSignalHandlerThread()
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGHUP);
|
||||
sigaddset(&set, SIGPIPE);
|
||||
sigaddset(&set, SIGWINCH);
|
||||
if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
|
||||
throw SysError("blocking signals");
|
||||
|
||||
signal(SIGWINCH, [](int) { invalidateWindowSize(); });
|
||||
|
||||
std::thread(signalHandlerThread, set).detach();
|
||||
}
|
||||
|
||||
|
||||
+16
-9
@@ -183,22 +183,29 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
|
||||
return t;
|
||||
}
|
||||
|
||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize{{0, 0}};
|
||||
static volatile sig_atomic_t windowSizeInvalid = 0;
|
||||
static Sync<std::pair<unsigned short, unsigned short>> windowSize;
|
||||
|
||||
void updateWindowSize()
|
||||
void invalidateWindowSize()
|
||||
{
|
||||
struct winsize ws;
|
||||
if (ioctl(2, TIOCGWINSZ, &ws) == 0 || ioctl(1, TIOCGWINSZ, &ws) == 0) {
|
||||
auto windowSize_(windowSize.lock());
|
||||
windowSize_->first = ws.ws_row;
|
||||
windowSize_->second = ws.ws_col;
|
||||
}
|
||||
windowSizeInvalid = 1;
|
||||
}
|
||||
|
||||
|
||||
std::pair<unsigned short, unsigned short> getWindowSize()
|
||||
{
|
||||
return *windowSize.lock();
|
||||
auto windowSize_(windowSize.lock());
|
||||
// this is racy, but given that window sizes change very rarely we'll just accept it
|
||||
if (windowSizeInvalid) {
|
||||
windowSizeInvalid = 0;
|
||||
struct winsize ws;
|
||||
if (ioctl(2, TIOCGWINSZ, &ws) == 0 || ioctl(1, TIOCGWINSZ, &ws) == 0) {
|
||||
windowSize_->first = ws.ws_row;
|
||||
windowSize_->second = ws.ws_col;
|
||||
}
|
||||
}
|
||||
|
||||
return *windowSize_;
|
||||
}
|
||||
|
||||
std::string makeHyperlink(std::string_view linkText, std::string_view target)
|
||||
|
||||
@@ -57,10 +57,10 @@ std::string filterANSIEscapes(std::string_view s,
|
||||
bool eatTabs = true);
|
||||
|
||||
/**
|
||||
* Recalculate the window size, updating a global variable. Used in the
|
||||
* Invalidate the window size, updating a global variable. Used in the
|
||||
* `SIGWINCH` signal handler.
|
||||
*/
|
||||
void updateWindowSize();
|
||||
void invalidateWindowSize();
|
||||
|
||||
/**
|
||||
* @return the number of rows and columns of the terminal.
|
||||
|
||||
Reference in New Issue
Block a user