Merge pull request #624 from lvxnull/native-read

This commit is contained in:
Jakob P. Liljenberg 2024-01-03 17:04:56 +01:00 committed by GitHub
commit 27c6f11e80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 97 deletions

View file

@ -176,7 +176,7 @@ void term_resize(bool force) {
static atomic<bool> resizing (false);
if (Input::polling) {
Global::resized = true;
Input::interrupt = true;
Input::interrupt();
return;
}
atomic_lock lck(resizing, true);
@ -246,7 +246,7 @@ void term_resize(bool force) {
else if (not Term::refresh()) break;
}
Input::interrupt = true;
Input::interrupt();
}
//* Exit handler; stops threads, restores terminal and saves config changes
@ -321,7 +321,7 @@ void _signal_handler(const int sig) {
if (Runner::active) {
Global::should_quit = true;
Runner::stopping = true;
Input::interrupt = true;
Input::interrupt();
}
else {
clean_quit(0);
@ -331,7 +331,7 @@ void _signal_handler(const int sig) {
if (Runner::active) {
Global::should_sleep = true;
Runner::stopping = true;
Input::interrupt = true;
Input::interrupt();
}
else {
_sleep();
@ -343,6 +343,9 @@ void _signal_handler(const int sig) {
case SIGWINCH:
term_resize();
break;
case SIGUSR1:
// Input::poll interrupt
break;
}
}
@ -477,7 +480,7 @@ namespace Runner {
if (pt_lck.status != 0) {
Global::exit_error_msg = "Exception in runner thread -> pthread_mutex_lock error id: " + to_string(pt_lck.status);
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
@ -488,7 +491,7 @@ namespace Runner {
if (active) {
Global::exit_error_msg = "Runner thread failed to get active lock!";
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
if (stopping or Global::resized) {
@ -558,7 +561,7 @@ namespace Runner {
coreNum_reset = false;
Cpu::core_mapping = Cpu::get_core_mapping();
Global::resized = true;
Input::interrupt = true;
Input::interrupt();
continue;
}
@ -655,7 +658,7 @@ namespace Runner {
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in runner thread -> " + string{e.what()};
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
@ -1014,6 +1017,12 @@ int main(int argc, char **argv) {
std::signal(SIGTSTP, _signal_handler);
std::signal(SIGCONT, _signal_handler);
std::signal(SIGWINCH, _signal_handler);
std::signal(SIGUSR1, _signal_handler);
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, &Input::signal_mask);
//? Start runner thread
Runner::thread_sem_init();
@ -1035,9 +1044,10 @@ int main(int argc, char **argv) {
{
const auto [x, y] = Term::get_min_size(Config::getS("shown_boxes"));
if (Term::height < y or Term::width < x) {
pthread_sigmask(SIG_SETMASK, &Input::signal_mask, &mask);
term_resize(true);
pthread_sigmask(SIG_SETMASK, &mask, nullptr);
Global::resized = false;
Input::interrupt = false;
}
}

View file

@ -16,12 +16,13 @@ indent = tab
tab-size = 4
*/
#include <iostream>
#include <limits>
#include <ranges>
#include <vector>
#include <thread>
#include <mutex>
#include <signal.h>
#include <sys/select.h>
#include <utility>
#include "btop_input.hpp"
@ -31,17 +32,6 @@ tab-size = 4
#include "btop_menu.hpp"
#include "btop_draw.hpp"
#include "btop_input.hpp"
#include "btop_tools.hpp"
#include "btop_config.hpp"
#include "btop_shared.hpp"
#include "btop_menu.hpp"
#include "btop_draw.hpp"
using std::cin;
using namespace Tools;
using namespace std::literals; // for operator""s
namespace rng = std::ranges;
@ -89,83 +79,45 @@ namespace Input {
{"[24~", "f12"}
};
std::atomic<bool> interrupt (false);
sigset_t signal_mask;
std::atomic<bool> polling (false);
array<int, 2> mouse_pos;
std::unordered_map<string, Mouse_loc> mouse_mappings;
deque<string> history(50, "");
string old_filter;
string input;
struct InputThr {
InputThr() : thr(run, this) {
}
static void run(InputThr* that) {
that->runImpl();
}
void runImpl() {
char ch = 0;
// TODO(pg83): read whole buffer
while (cin.get(ch)) {
std::lock_guard<std::mutex> g(lock);
current.push_back(ch);
if (current.size() > 100) {
current.clear();
}
}
}
size_t avail() {
std::lock_guard<std::mutex> g(lock);
return current.size();
}
std::string get() {
std::string res;
{
std::lock_guard<std::mutex> g(lock);
res.swap(current);
}
return res;
}
static InputThr& instance() {
// intentional memory leak, to simplify shutdown process
static InputThr* input = new InputThr();
return *input;
}
std::string current;
// TODO(pg83): use std::conditional_variable instead of sleep
std::mutex lock;
std::thread thr;
};
bool poll(int timeout) {
bool poll(const uint64_t timeout) {
atomic_lock lck(polling);
if (timeout < 1) return InputThr::instance().avail() > 0;
while (timeout > 0) {
if (interrupt) {
interrupt = false;
return false;
}
if (InputThr::instance().avail() > 0) return true;
sleep_ms(timeout < 10 ? timeout : 10);
timeout -= 10;
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
struct timespec wait;
struct timespec *waitptr = nullptr;
if(timeout != std::numeric_limits<uint64_t>::max()) {
wait.tv_sec = timeout / 1000;
wait.tv_nsec = (timeout % 1000) * 1000000;
waitptr = &wait;
}
if(pselect(STDIN_FILENO + 1, &fds, nullptr, nullptr, waitptr, &signal_mask) > 0) {
input.clear();
char buf[1024];
ssize_t count = 0;
while((count = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
input.append(std::string_view(buf, count));
}
return true;
}
return false;
}
string get() {
string key = InputThr::instance().get();
string key = input;
if (not key.empty()) {
//? Remove escape code prefix if present
if (key.substr(0, 2) == Fx::e) {
@ -238,12 +190,14 @@ namespace Input {
}
string wait() {
while (InputThr::instance().avail() < 1) {
sleep_ms(10);
}
while(not poll(std::numeric_limits<uint64_t>::max())) {}
return get();
}
void interrupt() {
kill(getpid(), SIGUSR1);
}
void clear() {
// do not need it, actually
}

View file

@ -29,9 +29,9 @@ using std::atomic;
using std::deque;
using std::string;
/* The input functions relies on the following std::cin options being set:
cin.sync_with_stdio(false);
cin.tie(nullptr);
/* The input functions rely on the following termios parameters being set:
Non-canonical mode (c_lflags & ~(ICANON))
VMIN and VTIME (c_cc) set to 0
These will automatically be set when running Term::init() from btop_tools.cpp
*/
@ -45,7 +45,9 @@ namespace Input {
//? line, col, height, width
extern std::unordered_map<string, Mouse_loc> mouse_mappings;
extern atomic<bool> interrupt;
//* Signal mask used during polling read
extern sigset_t signal_mask;
extern atomic<bool> polling;
//* Mouse column and line position
@ -55,7 +57,7 @@ namespace Input {
extern deque<string> history;
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
bool poll(int timeout=0);
bool poll(const uint64_t timeout=0);
//* Get a key or mouse action from input
string get();
@ -63,6 +65,9 @@ namespace Input {
//* Wait until input is available and return key
string wait();
//* Interrupt poll/wait
void interrupt();
//* Clears last entered key
void clear();

View file

@ -37,7 +37,6 @@ tab-size = 4
#include "btop_tools.hpp"
#include "btop_config.hpp"
using std::cin;
using std::cout;
using std::floor;
using std::flush;
@ -77,7 +76,11 @@ namespace Term {
struct termios settings;
if (tcgetattr(STDIN_FILENO, &settings)) return false;
if (on) settings.c_lflag |= ICANON;
else settings.c_lflag &= ~(ICANON);
else {
settings.c_lflag &= ~(ICANON);
settings.c_cc[VMIN] = 0;
settings.c_cc[VTIME] = 0;
}
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
if (on) setlinebuf(stdin);
else setbuf(stdin, nullptr);
@ -152,12 +155,10 @@ namespace Term {
//? Disable stream sync - this does not seem to work on OpenBSD
#ifndef __OpenBSD__
cin.sync_with_stdio(false);
cout.sync_with_stdio(false);
#endif
//? Disable stream ties
cin.tie(nullptr);
cout.tie(nullptr);
echo(false);
linebuffered(false);