mirror of https://github.com/aristocratos/btop.git
Added signal handler
This commit is contained in:
parent
dbb5a0599b
commit
10a8bfe39e
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ CPP = g++
|
|||
override CPPFLAGS += -std=c++20 -pthread
|
||||
OPTFLAG = -O3
|
||||
INFOFLAGS += -Wall -Wextra -Wno-stringop-overread -pedantic
|
||||
INCLUDES = -I./src -I./include
|
||||
INCLUDES = -Isrc -Iinclude
|
||||
|
||||
btop: btop.cpp
|
||||
@mkdir -p bin
|
||||
|
|
48
btop.cpp
48
btop.cpp
|
@ -21,6 +21,7 @@ tab-size = 4
|
|||
#include <array>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <csignal>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
|
@ -51,7 +52,7 @@ namespace Global {
|
|||
#include <btop_menu.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#define LINUX 1
|
||||
#define LINUX
|
||||
#include <btop_linux.h>
|
||||
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
|
||||
#include <sys/param.h>
|
||||
|
@ -62,7 +63,7 @@ namespace Global {
|
|||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC == 1
|
||||
#define OSX 1
|
||||
#define OSX
|
||||
// #include <btop_osx.h>
|
||||
#error OSX support not yet implemented!
|
||||
#endif
|
||||
|
@ -113,7 +114,7 @@ void argumentParser(int argc, char **argv){
|
|||
}
|
||||
}
|
||||
|
||||
void clean_quit(int signal){
|
||||
void clean_quit(int sig){
|
||||
if (Global::quitting) return;
|
||||
if (Term::initialized) {
|
||||
Term::restore();
|
||||
|
@ -121,11 +122,39 @@ void clean_quit(int signal){
|
|||
}
|
||||
if (Global::debug) Logger::debug("Quitting! Runtime: " + sec_to_dhms(time_s() - Global::start_time));
|
||||
Global::quitting = true;
|
||||
if (signal != -1) exit(signal);
|
||||
Config::write();
|
||||
if (sig != -1) exit(sig);
|
||||
}
|
||||
|
||||
void sleep_now(){
|
||||
if (Term::initialized) {
|
||||
Term::restore();
|
||||
if (!Global::debuginit) cout << Term::normal_screen << Term::show_cursor << flush;
|
||||
}
|
||||
std::raise(SIGSTOP);
|
||||
}
|
||||
|
||||
void resume_now(){
|
||||
Term::init();
|
||||
if (!Global::debuginit) cout << Term::alt_screen << Term::hide_cursor << flush;
|
||||
}
|
||||
|
||||
void _exit_handler() { clean_quit(-1); }
|
||||
|
||||
void _signal_handler(int sig) {
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
clean_quit(0);
|
||||
break;
|
||||
case SIGTSTP:
|
||||
sleep_now();
|
||||
break;
|
||||
case SIGCONT:
|
||||
resume_now();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//? Generate the btop++ banner
|
||||
void banner_gen() {
|
||||
size_t z = 0;
|
||||
|
@ -178,11 +207,16 @@ int main(int argc, char **argv){
|
|||
if (argc > 1) argumentParser(argc, argv);
|
||||
|
||||
std::atexit(_exit_handler);
|
||||
std::at_quick_exit(_exit_handler);
|
||||
std::signal(SIGINT, _signal_handler);
|
||||
std::signal(SIGTSTP, _signal_handler);
|
||||
std::signal(SIGCONT, _signal_handler);
|
||||
|
||||
//? Linux init
|
||||
#if defined(LINUX)
|
||||
Global::coreCount = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (Global::coreCount < 1) Global::coreCount = 1;
|
||||
|
||||
{
|
||||
std::error_code ec;
|
||||
Global::self_path = fs::read_symlink("/proc/self/exe", ec).remove_filename();
|
||||
|
@ -261,7 +295,7 @@ int main(int argc, char **argv){
|
|||
//* ------------------------------------------------ TESTING ------------------------------------------------------
|
||||
|
||||
|
||||
Global::debuginit = false;
|
||||
Global::debuginit = true;
|
||||
|
||||
// cout << Theme("main_bg") << Term::clear << flush;
|
||||
// bool thread_test = false;
|
||||
|
@ -453,8 +487,8 @@ int main(int argc, char **argv){
|
|||
greyscale.push_back(Theme::dec_to_color(xc, xc, xc));
|
||||
}
|
||||
|
||||
string pbox = Draw::createBox({.x = 0, .y = 10, .width = Term::width, .height = Term::height - 16, .line_color = Theme::c("proc_box"), .title = "testbox", .title2 = "below", .fill = false, .num = 7});
|
||||
pbox += rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 69) + " Threads: " +
|
||||
string pbox = Draw::createBox({.x = 1, .y = 10, .width = Term::width, .height = Term::height - 16, .line_color = Theme::c("proc_box"), .title = "testbox", .title2 = "below", .fill = false, .num = 7});
|
||||
pbox += Mv::r(1) + rjust("Pid:", 8) + " " + ljust("Program:", 16) + " " + ljust("Command:", Term::width - 70) + " Threads: " +
|
||||
ljust("User:", 10) + " " + rjust("MemB", 5) + " " + rjust("Cpu%", 14) + "\n" + Mv::save;
|
||||
|
||||
while (key != "q") {
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Config {
|
|||
|
||||
atomic<bool> locked (false);
|
||||
atomic<bool> writelock (false);
|
||||
bool changed = false;
|
||||
unordered_flat_map<string, bool> changed;
|
||||
|
||||
unordered_flat_map<string, string> strings = {
|
||||
{"color_theme", "Default"},
|
||||
|
@ -104,23 +104,22 @@ namespace Config {
|
|||
|
||||
bool _locked(){
|
||||
atomic_wait(writelock);
|
||||
if (!changed) changed = true;
|
||||
return locked.load();
|
||||
}
|
||||
}
|
||||
|
||||
//* Return config value <name> as a bool
|
||||
bool& getB(string name){
|
||||
//* Return bool config value <name>
|
||||
const bool& getB(string name){
|
||||
return bools.at(name);
|
||||
}
|
||||
|
||||
//* Return config value <name> as a int
|
||||
int& getI(string name){
|
||||
//* Return integer config value <name>
|
||||
const int& getI(string name){
|
||||
return ints.at(name);
|
||||
}
|
||||
|
||||
//* Return config value <name> as a string
|
||||
string& getS(string name){
|
||||
//* Return string config value <name>
|
||||
const string& getS(string name){
|
||||
return strings.at(name);
|
||||
}
|
||||
|
||||
|
@ -128,18 +127,21 @@ namespace Config {
|
|||
void set(string name, bool value){
|
||||
if (_locked()) boolsTmp.insert_or_assign(name, value);
|
||||
else bools.at(name) = value;
|
||||
changed.insert_or_assign(name, true);
|
||||
}
|
||||
|
||||
//* Set config value <name> to int <value>
|
||||
void set(string name, int value){
|
||||
if (_locked()) intsTmp.insert_or_assign(name, value);
|
||||
ints.at(name) = value;
|
||||
changed.insert_or_assign(name, true);
|
||||
}
|
||||
|
||||
//* Set config value <name> to string <value>
|
||||
void set(string name, string value){
|
||||
if (_locked()) stringsTmp.insert_or_assign(name, value);
|
||||
else strings.at(name) = value;
|
||||
changed.insert_or_assign(name, true);
|
||||
}
|
||||
|
||||
//* Flip config bool <name>
|
||||
|
@ -149,6 +151,7 @@ namespace Config {
|
|||
else boolsTmp.insert_or_assign(name, (!bools.at(name)));
|
||||
}
|
||||
else bools.at(name) = !bools.at(name);
|
||||
changed.insert_or_assign(name, true);
|
||||
}
|
||||
|
||||
//* Wait if locked then lock config and cache changes until unlock
|
||||
|
@ -184,6 +187,19 @@ namespace Config {
|
|||
void load(){
|
||||
if (conf_file.empty()) return;
|
||||
}
|
||||
|
||||
void write(){
|
||||
if (conf_file.empty() || changed.empty()) return;
|
||||
|
||||
if (Logger::loglevel > 3) {
|
||||
string items;
|
||||
for (auto item : Config::changed) {
|
||||
items += item.first + ", ";
|
||||
}
|
||||
items.pop_back(); items.pop_back();
|
||||
Logger::debug("Writing out new config values for: " + items);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -91,21 +91,21 @@ namespace Draw {
|
|||
|
||||
//* Draw horizontal lines
|
||||
for (uint hpos : {c.y, c.y + c.height - 1}){
|
||||
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width);
|
||||
out += Mv::to(hpos, c.x) + Symbols::h_line * (c.width - 1);
|
||||
}
|
||||
|
||||
//* Draw vertical lines and fill if enabled
|
||||
for (uint hpos : iota(c.y + 1, c.y + c.height - 1)){
|
||||
out += Mv::to(hpos, c.x) + Symbols::v_line +
|
||||
((c.fill) ? string(c.width - 1, ' ') : Mv::r(c.width - 1)) +
|
||||
((c.fill) ? string(c.width - 2, ' ') : Mv::r(c.width - 2)) +
|
||||
Symbols::v_line;
|
||||
}
|
||||
|
||||
//* Draw corners
|
||||
out += Mv::to(c.y, c.x) + Symbols::left_up +
|
||||
Mv::to(c.y, c.x + c.width) + Symbols::right_up +
|
||||
Mv::to(c.y, c.x + c.width - 1) + Symbols::right_up +
|
||||
Mv::to(c.y + c.height - 1, c.x) + Symbols::left_down +
|
||||
Mv::to(c.y + c.height - 1, c.x + c.width) + Symbols::right_down;
|
||||
Mv::to(c.y + c.height - 1, c.x + c.width - 1) + Symbols::right_down;
|
||||
|
||||
//* Draw titles if defined
|
||||
if (!c.title.empty()){
|
||||
|
@ -117,7 +117,7 @@ namespace Draw {
|
|||
Fx::ub + lcolor + Symbols::title_right;
|
||||
}
|
||||
|
||||
return out + Fx::reset + Mv::to(c.y + 1, c.x + 2);
|
||||
return out + Fx::reset + Mv::to(c.y + 1, c.x + 1);
|
||||
}
|
||||
|
||||
//* Class holding a percentage meter
|
||||
|
|
|
@ -155,8 +155,8 @@ namespace Proc {
|
|||
return current_procs;
|
||||
}
|
||||
|
||||
string pid_str = d.path().filename();
|
||||
bool new_cache = false;
|
||||
string pid_str = d.path().filename();
|
||||
if (d.is_directory() && isdigit(pid_str[0])) {
|
||||
npids++;
|
||||
proc_info new_proc (stoul(pid_str));
|
||||
|
@ -314,7 +314,7 @@ namespace Proc {
|
|||
);
|
||||
|
||||
//* When using "cpu lazy" sorting push processes with high cpu usage to the front regardless of cumulative usage
|
||||
if (sort_map.at(sorting) == 7 && !reverse) {
|
||||
if (sorting == "cpu lazy" && !reverse) {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, offset = 0; i < procs.size(); i++) {
|
||||
if (i <= 5 && procs[i].cpu_p > max) max = procs[i].cpu_p;
|
||||
|
|
|
@ -257,7 +257,7 @@ namespace Theme {
|
|||
//? If only _start was defined fill array with _start color
|
||||
c_gradient.fill(colors[name]);
|
||||
}
|
||||
gradients[wname] = c_gradient;
|
||||
gradients[wname].swap(c_gradient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,8 +267,8 @@ namespace Tools {
|
|||
return (str == "true") || (str == "false") || (str == "True") || (str == "False");
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value
|
||||
bool isint(string& str){
|
||||
//* Check if a string is a valid positive integer value
|
||||
bool isuint(string& str){
|
||||
return all_of(str.begin(), str.end(), ::isdigit);
|
||||
}
|
||||
|
||||
|
@ -428,13 +428,13 @@ namespace Tools {
|
|||
}
|
||||
|
||||
|
||||
#if __GNUC__ > 10
|
||||
#if (__GNUC__ > 10)
|
||||
//* Redirects to atomic wait
|
||||
void atomic_wait(atomic<bool>& atom, bool val=true){
|
||||
atom.wait(val);
|
||||
}
|
||||
#else
|
||||
//* Crude implementation of atomic wait for GCC < 11
|
||||
//* Crude implementation of atomic wait for GCC 10
|
||||
void atomic_wait(atomic<bool>& atom, bool val=true){
|
||||
while (atom.load() == val) sleep_ms(1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue