diff --git a/src/btop.cpp b/src/btop.cpp index 55c1af2..eca96c4 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -30,6 +30,7 @@ tab-size = 4 #include #include #include +#include #include #include @@ -40,7 +41,7 @@ tab-size = 4 #include using std::string, std::string_view, std::vector, std::atomic, std::endl, std::cout, std::min, std::flush, std::endl; -using std::string_literals::operator""s, std::to_string, std::future, std::async, std::bitset, std::future_status; +using std::string_literals::operator""s, std::to_string, std::future, std::async, std::bitset, std::future_status, std::mutex, std::lock_guard; namespace fs = std::filesystem; namespace rng = std::ranges; using namespace Tools; @@ -79,7 +80,6 @@ namespace Global { uint64_t start_time; atomic resized (false); - atomic resizing (false); atomic quitting (false); atomic _runner_started (false); @@ -150,8 +150,8 @@ void argumentParser(const int& argc, char **argv) { //* Handler for SIGWINCH and general resizing events, does nothing if terminal hasn't been resized unless force=true void term_resize(bool force) { - if (Global::resizing) return; - atomic_lock lck(Global::resizing); + static mutex resizing; + lock_guard lock(resizing); if (auto refreshed = Term::refresh(true); refreshed or force) { if (force and refreshed) force = false; } @@ -271,6 +271,7 @@ namespace Runner { atomic stopping (false); atomic waiting (false); atomic redraw (false); + // mutex runner_mtx; //* Setup semaphore for triggering thread to do work #if __GNUC__ < 11 @@ -302,6 +303,7 @@ namespace Runner { sigset_t mask; pthread_t runner_id; pthread_mutex_t mtx; + pthread_mutex_t active_mtx; const unordered_flat_map box_bits = { {"proc", 0b0000'0001}, @@ -387,6 +389,7 @@ namespace Runner { //* ----------------------------------------------- THREAD LOOP ----------------------------------------------- while (not Global::quitting) { thread_wait(); + thread_lock lock(active_mtx); if (stopping or Global::resized) { continue; } @@ -589,34 +592,40 @@ namespace Runner { //* Runs collect and draw in a secondary thread, unlocks and locks config to update cached values void run(const string& box, const bool no_update, const bool force_redraw) { - if (active) atomic_wait(active); - if (stopping or Global::resized) return; + bool trigger = false; + { + thread_lock lock(active_mtx); + if (stopping or Global::resized) return; - if (box == "overlay") { - cout << Term::sync_start << Global::overlay << Term::sync_end << flush; - } - else if (box == "clock") { - cout << Term::sync_start << Global::clock << Term::sync_end << flush; - } - else { - Config::unlock(); - Config::lock(); - - //? Setup bitmask for selected boxes and pass to _runner thread - bitset<8> box_mask; - for (const auto& box : (box == "all" ? Config::current_boxes : vector{box})) { - box_mask |= box_bits.at(box); + if (box == "overlay") { + cout << Term::sync_start << Global::overlay << Term::sync_end << flush; } + else if (box == "clock") { + cout << Term::sync_start << Global::clock << Term::sync_end << flush; + } + else { + Config::unlock(); + Config::lock(); - current_conf = {box_mask, no_update, force_redraw, (not Config::getB("tty_mode") and Config::getB("background_update")), Global::overlay, Global::clock}; + //? Setup bitmask for selected boxes and pass to _runner thread + bitset<8> box_mask; + for (const auto& box : (box == "all" ? Config::current_boxes : vector{box})) { + box_mask |= box_bits.at(box); + } - if (Menu::active and not current_conf.background_update) Global::overlay.clear(); + current_conf = {box_mask, no_update, force_redraw, (not Config::getB("tty_mode") and Config::getB("background_update")), Global::overlay, Global::clock}; - thread_trigger(); + if (Menu::active and not current_conf.background_update) Global::overlay.clear(); - //? Wait for _runner thread to be active before returning - for (int i = 0; not active and i < 10; i++) sleep_ms(1); + trigger = true; + } } + //? Trigger thread start and wait for it to be active before returning + if (trigger) { + thread_trigger(); + atomic_wait_for(active, false, 10); + } + } //* Stops any work being done in runner thread and checks for thread errors @@ -629,9 +638,15 @@ namespace Runner { exit(1); } else if (ret == EBUSY) { - atomic_wait(active); + atomic_wait_for(active, true, 1000); + if (active) { + Global::exit_error_msg = "No response from Runner thread, quitting!"; + active = false; + exit(1); + } thread_trigger(); - sleep_ms(1); + atomic_wait_for(active, false, 100); + atomic_wait_for(active, true, 100); } stopping = false; } @@ -857,7 +872,7 @@ int main(int argc, char **argv) { Global::resized = false; if (Menu::active) Menu::process(); else Runner::run("all", true, true); - atomic_wait(Runner::active); + atomic_wait_for(Runner::active, true, 1000); } //? Update clock if needed diff --git a/src/btop_config.cpp b/src/btop_config.cpp index a26323f..4ca2ac1 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -21,12 +21,13 @@ tab-size = 4 #include #include #include +#include #include #include #include -using std::array, std::atomic, std::string_view, std::string_literals::operator""s; +using std::array, std::atomic, std::string_view, std::string_literals::operator""s, std::mutex, std::lock_guard; namespace fs = std::filesystem; namespace rng = std::ranges; using namespace Tools; @@ -35,7 +36,7 @@ using namespace Tools; namespace Config { atomic locked (false); - atomic writelock (false); + mutex writelock; bool write_new; const vector> descriptions = { @@ -256,7 +257,7 @@ namespace Config { unordered_flat_map intsTmp; bool _locked(const string& name) { - atomic_wait(writelock); + lock_guard lock(writelock); if (not write_new and rng::find_if(descriptions, [&name](const auto& a) { return a.at(0) == name; }) != descriptions.end()) write_new = true; return locked.load(); @@ -334,7 +335,7 @@ namespace Config { } void lock() { - atomic_wait(writelock); + lock_guard lock(writelock); locked = true; } @@ -448,7 +449,7 @@ namespace Config { void unlock() { if (not locked) return; atomic_wait(Runner::active); - atomic_lock lck(writelock); + lock_guard lock(writelock); try { if (Proc::shown) { ints.at("selected_pid") = Proc::selected_pid; diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index 4668169..72b7e90 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -24,6 +24,7 @@ tab-size = 4 #include #include #include +#include #include #include @@ -33,7 +34,8 @@ tab-size = 4 #include #include -using std::string_view, std::max, std::floor, std::to_string, std::cin, std::cout, std::flush, robin_hood::unordered_flat_map; +using std::string_view, std::max, std::floor, std::to_string, std::cin, std::cout, std::flush, robin_hood::unordered_flat_map, + std::mutex, std::lock_guard; namespace fs = std::filesystem; namespace rng = std::ranges; @@ -321,11 +323,18 @@ namespace Tools { return ss.str(); } + void atomic_wait(const atomic& atom, const bool old) noexcept { + while (atom.load(std::memory_order_relaxed) == old ) busy_wait(); + } + + void atomic_wait_for(const atomic& atom, const bool old, const uint64_t wait_ms) noexcept { + const uint64_t start_time = time_ms(); + while (atom.load(std::memory_order_relaxed) == old and (time_ms() - start_time < wait_ms)) sleep_ms(1); + } + atomic_lock::atomic_lock(atomic& atom) : atom(atom) { active_locks++; - while (not this->atom.compare_exchange_strong(this->not_true, true, std::memory_order_relaxed)) { - busy_wait(); - } + this->atom.store(true); } atomic_lock::~atomic_lock() { @@ -375,11 +384,10 @@ namespace Tools { namespace Logger { using namespace Tools; - namespace { - std::atomic busy (false); - bool first = true; - const string tdf = "%Y/%m/%d (%T) | "; - } + + mutex logger_mtx; + bool first = true; + const string tdf = "%Y/%m/%d (%T) | "; size_t loglevel; fs::path logfile; @@ -390,7 +398,7 @@ namespace Logger { void log_write(const size_t level, const string& msg) { if (loglevel < level or logfile.empty()) return; - atomic_lock lck(busy); + lock_guard lock(logger_mtx); std::error_code ec; try { if (fs::exists(logfile) and fs::file_size(logfile, ec) > 1024 << 10 and not ec) { diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index 4e705c7..0810adc 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -281,9 +281,9 @@ namespace Tools { #endif } - inline void atomic_wait(const atomic& atom, const bool old=true) noexcept { - while (atom.load(std::memory_order_relaxed) == old) busy_wait(); - } + void atomic_wait(const atomic& atom, const bool old=true) noexcept; + + void atomic_wait_for(const atomic& atom, const bool old=true, const uint64_t wait_ms=0) noexcept; //* Waits for atomic to be false and sets it to true on construct, sets to false on destruct class atomic_lock {