feat: fix deadlocks

This commit is contained in:
Cyrix126 2024-10-10 19:45:41 +02:00
parent 5230d46d93
commit 387f386573
10 changed files with 538 additions and 540 deletions

View file

@ -27,6 +27,12 @@ impl eframe::App for App {
// These values are checked multiple times so // These values are checked multiple times so
// might as well check only once here to save // might as well check only once here to save
// on a bunch of [.lock().unwrap()]s. // on a bunch of [.lock().unwrap()]s.
debug!("App | Locking and collecting Node state...");
let node = self.node.lock().unwrap();
let node_is_alive = node.is_alive();
let node_is_waiting = node.is_waiting();
let node_state = node.state;
drop(node);
debug!("App | Locking and collecting P2Pool state..."); debug!("App | Locking and collecting P2Pool state...");
let p2pool = self.p2pool.lock().unwrap(); let p2pool = self.p2pool.lock().unwrap();
let p2pool_is_alive = p2pool.is_alive(); let p2pool_is_alive = p2pool.is_alive();
@ -49,14 +55,9 @@ impl eframe::App for App {
let xvb = self.xvb.lock().unwrap(); let xvb = self.xvb.lock().unwrap();
let xvb_is_alive = xvb.is_alive(); let xvb_is_alive = xvb.is_alive();
let xvb_is_waiting = xvb.is_waiting(); let xvb_is_waiting = xvb.is_waiting();
let xvb_is_running = xvb.state == ProcessState::Alive;
let xvb_state = xvb.state; let xvb_state = xvb.state;
drop(xvb); drop(xvb);
debug!("App | Locking and collecting Node state...");
let node = self.node.lock().unwrap();
let node_is_alive = node.is_alive();
let node_is_waiting = node.is_waiting();
let node_state = node.state;
drop(node);
// This sets the top level Ui dimensions. // This sets the top level Ui dimensions.
// Used as a reference for other uis. // Used as a reference for other uis.
@ -139,6 +140,7 @@ impl eframe::App for App {
xmrig_is_alive, xmrig_is_alive,
xmrig_proxy_is_alive, xmrig_proxy_is_alive,
xvb_is_alive, xvb_is_alive,
xvb_is_running,
); );
} }
} }

View file

@ -1,6 +1,5 @@
use crate::app::keys::KeyPressed; use crate::app::keys::KeyPressed;
use crate::app::Tab; use crate::app::Tab;
use crate::helper::ProcessState;
use crate::utils::constants::*; use crate::utils::constants::*;
use crate::utils::errors::{ErrorButtons, ErrorFerris}; use crate::utils::errors::{ErrorButtons, ErrorFerris};
use egui::*; use egui::*;
@ -25,6 +24,7 @@ impl crate::app::App {
xmrig_is_alive: bool, xmrig_is_alive: bool,
xmrig_proxy_is_alive: bool, xmrig_proxy_is_alive: bool,
xvb_is_alive: bool, xvb_is_alive: bool,
xvb_is_running: bool,
) { ) {
// Middle panel, contents of the [Tab] // Middle panel, contents of the [Tab]
debug!("App | Rendering CENTRAL_PANEL (tab contents)"); debug!("App | Rendering CENTRAL_PANEL (tab contents)");
@ -43,12 +43,14 @@ impl crate::app::App {
let distro = true; let distro = true;
#[cfg(not(feature = "distro"))] #[cfg(not(feature = "distro"))]
let distro = false; let distro = false;
let node_gui_len = self.node_api.lock().unwrap().output.len();
let p2pool_gui_len = self.p2pool_api.lock().unwrap().output.len(); let p2pool_gui_len = self.p2pool_api.lock().unwrap().output.len();
let xmrig_gui_len = self.xmrig_api.lock().unwrap().output.len(); let xmrig_gui_len = self.xmrig_api.lock().unwrap().output.len();
let xmrig_proxy_gui_len = self.xmrig_proxy_api.lock().unwrap().output.len(); let xmrig_proxy_gui_len = self.xmrig_proxy_api.lock().unwrap().output.len();
let gupax_p2pool_api = self.gupax_p2pool_api.lock().unwrap(); let gupax_p2pool_api = self.gupax_p2pool_api.lock().unwrap();
let debug_info = format!( let debug_info = format!(
"Gupax version: {}\n "Gupax version: {}\n
Bundled Node version: {}\n
Bundled P2Pool version: {}\n Bundled P2Pool version: {}\n
Bundled XMRig version: {}\n Bundled XMRig version: {}\n
Bundled XMRig-Proxy version: {}\n Bundled XMRig-Proxy version: {}\n
@ -114,6 +116,7 @@ path_xmr: {:#?}\n
self.state.gupax.absolute_p2pool_path.display(), self.state.gupax.absolute_p2pool_path.display(),
self.state.gupax.absolute_xmrig_path.display(), self.state.gupax.absolute_xmrig_path.display(),
self.state.gupax.absolute_xp_path.display(), self.state.gupax.absolute_xp_path.display(),
node_gui_len,
p2pool_gui_len, p2pool_gui_len,
xmrig_gui_len, xmrig_gui_len,
xmrig_proxy_gui_len, xmrig_proxy_gui_len,
@ -181,7 +184,7 @@ path_xmr: {:#?}\n
} }
Tab::Xvb => { Tab::Xvb => {
debug!("App | Entering [XvB] Tab"); debug!("App | Entering [XvB] Tab");
crate::disk::state::Xvb::show(&mut self.state.xvb, self.size, &self.state.p2pool.address, ctx, ui, &self.xvb_api, &self.xmrig_api, self.xvb.lock().unwrap().state == ProcessState::Alive); crate::disk::state::Xvb::show(&mut self.state.xvb, self.size, &self.state.p2pool.address, ctx, ui, &self.xvb_api, &self.xmrig_api, xvb_is_running);
} }
} }
}); });

View file

@ -369,8 +369,12 @@ impl Update {
info!("Update | Saving state..."); info!("Update | Saving state...");
let original_version = og.lock().unwrap().version.clone(); let original_version = og.lock().unwrap().version.clone();
og.lock().unwrap().version = state_ver; og.lock().unwrap().version = state_ver;
match State::save(&mut og.lock().unwrap(), &state_path) { let mut state = og.lock().unwrap().to_owned();
Ok(_) => info!("Update ... OK"), match State::save(&mut state, &state_path) {
Ok(_) => {
info!("Update ... OK");
*og.lock().unwrap() = state;
}
Err(e) => { Err(e) => {
warn!("Update | Saving state ... FAIL: {}", e); warn!("Update | Saving state ... FAIL: {}", e);
og.lock().unwrap().version = original_version; og.lock().unwrap().version = original_version;

View file

@ -466,39 +466,39 @@ impl Helper {
// 2. Lock... EVERYTHING! // 2. Lock... EVERYTHING!
let mut lock = helper.lock().unwrap(); let mut lock = helper.lock().unwrap();
debug!("Helper | Locking (1/15) ... [helper]"); debug!("Helper | Locked (1/17) ... [helper]");
let node = node.lock().unwrap(); let node = node.lock().unwrap();
debug!("Helper | Locking (2/15) ... [helper]"); debug!("Helper | Locked (2/17) ... [node]");
let p2pool = p2pool.lock().unwrap(); let p2pool = p2pool.lock().unwrap();
debug!("Helper | Locking (3/15) ... [p2pool]"); debug!("Helper | Locked (3/17) ... [p2pool]");
let xmrig = xmrig.lock().unwrap(); let xmrig = xmrig.lock().unwrap();
debug!("Helper | Locking (4/15) ... [xmrig]"); debug!("Helper | Locked (4/17) ... [xmrig]");
let xmrig_proxy = xmrig_proxy.lock().unwrap(); let xmrig_proxy = xmrig_proxy.lock().unwrap();
debug!("Helper | Locking (5/15) ... [xmrig_proxy]"); debug!("Helper | Locked (5/17) ... [xmrig_proxy]");
let xvb = xvb.lock().unwrap(); let xvb = xvb.lock().unwrap();
debug!("Helper | Locking (6/15) ... [xvb]"); debug!("Helper | Locked (6/17) ... [xvb]");
let mut lock_pub_sys = pub_sys.lock().unwrap(); let mut lock_pub_sys = pub_sys.lock().unwrap();
debug!("Helper | Locking (8/15) ... [gui_api_node]"); debug!("Helper | Locked (8/17) ... [pub_sys]");
let mut gui_api_node = gui_api_node.lock().unwrap(); let mut gui_api_node = gui_api_node.lock().unwrap();
debug!("Helper | Locking (7/15) ... [pub_sys]"); debug!("Helper | Locked (7/17) ... [gui_api_node]");
let mut gui_api_p2pool = gui_api_p2pool.lock().unwrap(); let mut gui_api_p2pool = gui_api_p2pool.lock().unwrap();
debug!("Helper | Locking (8/15) ... [gui_api_p2pool]"); debug!("Helper | Locked (9/17) ... [gui_api_p2pool]");
let mut gui_api_xmrig = gui_api_xmrig.lock().unwrap(); let mut gui_api_xmrig = gui_api_xmrig.lock().unwrap();
debug!("Helper | Locking (9/15) ... [gui_api_xmrig]"); debug!("Helper | Locked (10/17) ... [gui_api_xmrig]");
let mut gui_api_xp = gui_api_xp.lock().unwrap(); let mut gui_api_xp = gui_api_xp.lock().unwrap();
debug!("Helper | Locking (10/15) ... [gui_api_xp]"); debug!("Helper | Locked (11/17) ... [gui_api_xp]");
let mut gui_api_xvb = gui_api_xvb.lock().unwrap(); let mut gui_api_xvb = gui_api_xvb.lock().unwrap();
debug!("Helper | Locking (11/15) ... [gui_api_xvb]"); debug!("Helper | Locked (12/17) ... [gui_api_xvb]");
let mut pub_api_node = pub_api_node.lock().unwrap(); let mut pub_api_node = pub_api_node.lock().unwrap();
debug!("Helper | Locking (14/15) ... [pub_api_node]"); debug!("Helper | Locked (13/17) ... [pub_api_node]");
let mut pub_api_p2pool = pub_api_p2pool.lock().unwrap(); let mut pub_api_p2pool = pub_api_p2pool.lock().unwrap();
debug!("Helper | Locking (14/15) ... [pub_api_p2pool]"); debug!("Helper | Locked (14/17) ... [pub_api_p2pool]");
let mut pub_api_xmrig = pub_api_xmrig.lock().unwrap(); let mut pub_api_xmrig = pub_api_xmrig.lock().unwrap();
debug!("Helper | Locking (13/15) ... [pub_api_xmrig]"); debug!("Helper | Locked (15/17) ... [pub_api_xmrig]");
let mut pub_api_xp = pub_api_xp.lock().unwrap(); let mut pub_api_xp = pub_api_xp.lock().unwrap();
debug!("Helper | Locking (14/15) ... [pub_api_xp]"); debug!("Helper | Locked (16/17) ... [pub_api_xp]");
let mut pub_api_xvb = pub_api_xvb.lock().unwrap(); let mut pub_api_xvb = pub_api_xvb.lock().unwrap();
debug!("Helper | Locking (15/15) ... [pub_api_xvb]"); debug!("Helper | Locked (17/17) ... [pub_api_xvb]");
// Calculate Gupax's uptime always. // Calculate Gupax's uptime always.
lock.uptime = HumanTime::into_human(lock.instant.elapsed()); lock.uptime = HumanTime::into_human(lock.instant.elapsed());
// If [Node] is alive... // If [Node] is alive...
@ -558,39 +558,39 @@ impl Helper {
// 3. Drop... (almost) EVERYTHING... IN REVERSE! // 3. Drop... (almost) EVERYTHING... IN REVERSE!
drop(lock_pub_sys); drop(lock_pub_sys);
debug!("Helper | Unlocking (1/12) ... [pub_sys]"); debug!("Helper | Unlocking (1/17) ... [pub_sys]");
drop(xvb); drop(xvb);
debug!("Helper | Unlocking (2/12) ... [xvb]"); debug!("Helper | Unlocking (2/17) ... [xvb]");
drop(xmrig_proxy); drop(xmrig_proxy);
debug!("Helper | Unlocking (3/12) ... [xmrig_proxy]"); debug!("Helper | Unlocking (3/17) ... [xmrig_proxy]");
drop(xmrig); drop(xmrig);
debug!("Helper | Unlocking (3/12) ... [xmrig]"); debug!("Helper | Unlocking (4/17) ... [xmrig]");
drop(p2pool); drop(p2pool);
debug!("Helper | Unlocking (4/12) ... [p2pool]"); debug!("Helper | Unlocking (5/17) ... [p2pool]");
drop(node); drop(node);
debug!("Helper | Unlocking (4/12) ... [node]"); debug!("Helper | Unlocking (6/17) ... [node]");
drop(pub_api_xvb); drop(pub_api_xvb);
debug!("Helper | Unlocking (5/12) ... [pub_api_xvb]"); debug!("Helper | Unlocking (7/17) ... [pub_api_xvb]");
drop(pub_api_xp); drop(pub_api_xp);
debug!("Helper | Unlocking (6/12) ... [pub_api_xp]"); debug!("Helper | Unlocking (8/17) ... [pub_api_xp]");
drop(pub_api_xmrig); drop(pub_api_xmrig);
debug!("Helper | Unlocking (6/12) ... [pub_api_xmrig]"); debug!("Helper | Unlocking (9/17) ... [pub_api_xmrig]");
drop(pub_api_p2pool); drop(pub_api_p2pool);
debug!("Helper | Unlocking (7/12) ... [pub_api_p2pool]"); debug!("Helper | Unlocking (10/17) ... [pub_api_p2pool]");
drop(pub_api_node); drop(pub_api_node);
debug!("Helper | Unlocking (7/12) ... [node]"); debug!("Helper | Unlocking (11/17) ... [pub_api_node]");
drop(gui_api_xvb); drop(gui_api_xvb);
debug!("Helper | Unlocking (8/12) ... [gui_api_xvb]"); debug!("Helper | Unlocking (12/17) ... [gui_api_xvb]");
drop(gui_api_xp); drop(gui_api_xp);
debug!("Helper | Unlocking (9/12) ... [gui_api_xp]"); debug!("Helper | Unlocking (13/17) ... [gui_api_xp]");
drop(gui_api_xmrig); drop(gui_api_xmrig);
debug!("Helper | Unlocking (10/12) ... [gui_api_xmrig]"); debug!("Helper | Unlocking (14/17) ... [gui_api_xmrig]");
drop(gui_api_p2pool); drop(gui_api_p2pool);
debug!("Helper | Unlocking (11/12) ... [gui_api_p2pool]"); debug!("Helper | Unlocking (15/17) ... [gui_api_p2pool]");
drop(gui_api_node); drop(gui_api_node);
debug!("Helper | Unlocking (11/12) ... [node]"); debug!("Helper | Unlocking (16/17) ... [gui_api_node]");
drop(lock); drop(lock);
debug!("Helper | Unlocking (12/12) ... [helper]"); debug!("Helper | Unlocking (17/17) ... [helper]");
// 4. Calculate if we should sleep or not. // 4. Calculate if we should sleep or not.
// If we should sleep, how long? // If we should sleep, how long?
@ -686,71 +686,63 @@ fn check_user_input(process: &Arc<Mutex<Process>>, stdin: &mut Box<dyn std::io::
} }
} }
fn signal_end( fn signal_end(
process: &Arc<Mutex<Process>>, process: &mut Process,
child_pty: &Arc<Mutex<Box<dyn Child + Sync + Send>>>, child_pty: &Arc<Mutex<Box<dyn Child + Sync + Send>>>,
start: &Instant, start: &Instant,
gui_api_output_raw: &mut String, gui_api_output_raw: &mut String,
) -> bool { ) -> bool {
if process.lock().unwrap().signal == ProcessSignal::Stop { let mut child_pty_lock = child_pty.lock().unwrap();
debug!("{} Watchdog | Stop SIGNAL caught", process.lock().unwrap().name); if process.signal == ProcessSignal::Stop {
debug!("{} Watchdog | Stop SIGNAL caught", process.name);
// This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool) // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
if let Err(e) = child_pty.lock().unwrap().kill() { if let Err(e) = child_pty_lock.kill() {
error!("{} Watchdog | Kill error: {}", process.lock().unwrap().name, e); error!("{} Watchdog | Kill error: {}", process.name, e);
} }
// Wait to get the exit status // Wait to get the exit status
let exit_status = match child_pty.lock().unwrap().wait() { let exit_status = match child_pty_lock.wait() {
Ok(e) => { Ok(e) => {
if e.success() { if e.success() {
process.lock().unwrap().state = ProcessState::Dead; process.state = ProcessState::Dead;
"Successful" "Successful"
} else { } else {
process.lock().unwrap().state = ProcessState::Failed; process.state = ProcessState::Failed;
"Failed" "Failed"
} }
} }
_ => { _ => {
process.lock().unwrap().state = ProcessState::Failed; process.state = ProcessState::Failed;
"Unknown Error" "Unknown Error"
} }
}; };
let uptime = HumanTime::into_human(start.elapsed()); let uptime = HumanTime::into_human(start.elapsed());
info!( info!(
"{} Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", "{} Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]",
process.lock().unwrap().name, process.name, uptime, exit_status
uptime,
exit_status
); );
// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it. // This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
let name = process.name.to_owned();
if let Err(e) = writeln!( if let Err(e) = writeln!(
gui_api_output_raw, gui_api_output_raw,
"{}\n{} stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", "{}\n{} stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
process.lock().unwrap().name, name, HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE
HORI_CONSOLE,
uptime,
exit_status,
HORI_CONSOLE
) { ) {
error!( error!(
"{} Watchdog | GUI Uptime/Exit status write failed: {}", "{} Watchdog | GUI Uptime/Exit status write failed: {}",
process.lock().unwrap().name, name, e
e
); );
} }
process.lock().unwrap().signal = ProcessSignal::None; process.signal = ProcessSignal::None;
debug!( debug!("{} Watchdog | Stop SIGNAL done, breaking", process.name,);
"{} Watchdog | Stop SIGNAL done, breaking",
process.lock().unwrap().name,
);
return true; return true;
// Check RESTART // Check RESTART
} else if process.lock().unwrap().signal == ProcessSignal::Restart { } else if process.signal == ProcessSignal::Restart {
debug!("{} Watchdog | Restart SIGNAL caught", process.lock().unwrap().name,); debug!("{} Watchdog | Restart SIGNAL caught", process.name,);
// This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool) // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
if let Err(e) = child_pty.lock().unwrap().kill() { if let Err(e) = child_pty_lock.kill() {
error!("{} Watchdog | Kill error: {}", process.lock().unwrap().name, e); error!("{} Watchdog | Kill error: {}", process.name, e);
} }
// Wait to get the exit status // Wait to get the exit status
let exit_status = match child_pty.lock().unwrap().wait() { let exit_status = match child_pty_lock.wait() {
Ok(e) => { Ok(e) => {
if e.success() { if e.success() {
"Successful" "Successful"
@ -763,31 +755,22 @@ fn signal_end(
let uptime = HumanTime::into_human(start.elapsed()); let uptime = HumanTime::into_human(start.elapsed());
info!( info!(
"{} Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]", "{} Watchdog | Stopped ... Uptime was: [{}], Exit status: [{}]",
process.lock().unwrap().name, process.name, uptime, exit_status
uptime,
exit_status
); );
// This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it. // This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it.
let name = process.name.to_owned();
if let Err(e) = writeln!( if let Err(e) = writeln!(
gui_api_output_raw, gui_api_output_raw,
"{}\n{} stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", "{}\n{} stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n",
process.lock().unwrap().name, name, HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE
HORI_CONSOLE,
uptime,
exit_status,
HORI_CONSOLE
) { ) {
error!( error!(
"{} Watchdog | GUI Uptime/Exit status write failed: {}", "{} Watchdog | GUI Uptime/Exit status write failed: {}",
process.lock().unwrap().name, name, e
e
); );
} }
process.lock().unwrap().state = ProcessState::Waiting; process.state = ProcessState::Waiting;
debug!( debug!("{} Watchdog | Restart SIGNAL done, breaking", process.name,);
"{} Watchdog | Restart SIGNAL done, breaking",
process.lock().unwrap().name,
);
return true; return true;
} }
false false
@ -796,8 +779,8 @@ async fn sleep_end_loop(now: Instant, name: ProcessName) {
// Sleep (only if 999ms hasn't passed) // Sleep (only if 999ms hasn't passed)
let elapsed = now.elapsed().as_millis(); let elapsed = now.elapsed().as_millis();
// Since logic goes off if less than 1000, casting should be safe // Since logic goes off if less than 1000, casting should be safe
if elapsed < 999 { if elapsed < 1000 {
let sleep = (999 - elapsed) as u64; let sleep = (1000 - elapsed) as u64;
debug!( debug!(
"{} Watchdog | END OF LOOP - Sleeping for [{}]ms...", "{} Watchdog | END OF LOOP - Sleeping for [{}]ms...",
name, sleep name, sleep

View file

@ -227,7 +227,8 @@ impl Helper {
loop { loop {
let now = Instant::now(); let now = Instant::now();
debug!("Node Watchdog | ----------- Start of loop -----------"); debug!("Node Watchdog | ----------- Start of loop -----------");
{
// scope to drop locked mutex before the sleep
// check state // check state
if check_died( if check_died(
&child_pty, &child_pty,
@ -239,7 +240,7 @@ impl Helper {
} }
// check signal // check signal
if signal_end( if signal_end(
process, &mut process.lock().unwrap(),
&child_pty, &child_pty,
&start, &start,
&mut gui_api.lock().unwrap().output, &mut gui_api.lock().unwrap().output,
@ -253,8 +254,10 @@ impl Helper {
// Check if logs need resetting // Check if logs need resetting
debug!("Node Watchdog | Attempting GUI log reset check"); debug!("Node Watchdog | Attempting GUI log reset check");
{ {
let mut lock = gui_api.lock().unwrap(); Self::check_reset_gui_output(
Self::check_reset_gui_output(&mut lock.output, ProcessName::Node); &mut gui_api.lock().unwrap().output,
ProcessName::Node,
);
} }
// No need to check output since monerod has a sufficient API // No need to check output since monerod has a sufficient API
// Always update from output // Always update from output
@ -264,7 +267,9 @@ impl Helper {
debug!("Node Watchdog | Attempting HTTP API request..."); debug!("Node Watchdog | Attempting HTTP API request...");
match PrivNodeApi::request_api(&client, &state).await { match PrivNodeApi::request_api(&client, &state).await {
Ok(priv_api) => { Ok(priv_api) => {
debug!("Node Watchdog | HTTP API request OK, attempting [update_from_priv()]"); debug!(
"Node Watchdog | HTTP API request OK, attempting [update_from_priv()]"
);
if priv_api.result.synchronized && priv_api.result.status == "OK" { if priv_api.result.synchronized && priv_api.result.status == "OK" {
process.lock().unwrap().state = ProcessState::Alive process.lock().unwrap().state = ProcessState::Alive
} }
@ -280,6 +285,7 @@ impl Helper {
} }
} }
} }
}
// do not use more than 1 second for the loop // do not use more than 1 second for the loop
sleep_end_loop(now, ProcessName::Node).await; sleep_end_loop(now, ProcessName::Node).await;
} }

View file

@ -527,8 +527,8 @@ impl Helper {
// Set timer // Set timer
let now = Instant::now(); let now = Instant::now();
debug!("P2Pool Watchdog | ----------- Start of loop -----------"); debug!("P2Pool Watchdog | ----------- Start of loop -----------");
{
gui_api.lock().unwrap().tick = (last_p2pool_request.elapsed().as_secs() % 60) as u8; gui_api.lock().unwrap().tick = (last_p2pool_request.elapsed().as_secs() % 60) as u8;
// Check if the process is secretly died without us knowing :) // Check if the process is secretly died without us knowing :)
if check_died( if check_died(
&child_pty, &child_pty,
@ -541,7 +541,7 @@ impl Helper {
// Check SIGNAL // Check SIGNAL
if signal_end( if signal_end(
&process, &mut process.lock().unwrap(),
&child_pty, &child_pty,
&start, &start,
&mut gui_api.lock().unwrap().output, &mut gui_api.lock().unwrap().output,
@ -558,12 +558,14 @@ impl Helper {
// Always update from output // Always update from output
debug!("P2Pool Watchdog | Starting [update_from_output()]"); debug!("P2Pool Watchdog | Starting [update_from_output()]");
let mut process_lock = process.lock().unwrap();
let mut pub_api_lock = pub_api.lock().unwrap();
PubP2poolApi::update_from_output( PubP2poolApi::update_from_output(
&pub_api, &mut pub_api_lock,
&output_parse, &output_parse,
&output_pub, &output_pub,
start.elapsed(), start.elapsed(),
&process, &mut process_lock,
); );
// Read [local] API // Read [local] API
@ -572,7 +574,7 @@ impl Helper {
// Deserialize // Deserialize
if let Ok(local_api) = PrivP2poolLocalApi::from_str(&string) { if let Ok(local_api) = PrivP2poolLocalApi::from_str(&string) {
// Update the structs. // Update the structs.
PubP2poolApi::update_from_local(&pub_api, local_api); PubP2poolApi::update_from_local(&mut pub_api_lock, local_api);
} }
} }
// If more than 1 minute has passed, read the other API files. // If more than 1 minute has passed, read the other API files.
@ -582,7 +584,7 @@ impl Helper {
// check if value is 100k or under and request immediately if that's the case. fixed in release of p2pool including commit https://github.com/SChernykh/p2pool/commit/64a199be6dec7924b41f857a401086f25e1ec9be // check if value is 100k or under and request immediately if that's the case. fixed in release of p2pool including commit https://github.com/SChernykh/p2pool/commit/64a199be6dec7924b41f857a401086f25e1ec9be
if (last_p2pool_request_expired if (last_p2pool_request_expired
|| pub_api.lock().unwrap().p2pool_difficulty_u64 <= 100000) || pub_api.lock().unwrap().p2pool_difficulty_u64 <= 100000)
&& process.lock().unwrap().state == ProcessState::Alive && process_lock.state == ProcessState::Alive
{ {
debug!("P2Pool Watchdog | Attempting [network] & [pool] API file read"); debug!("P2Pool Watchdog | Attempting [network] & [pool] API file read");
if let (Ok(network_api), Ok(pool_api)) = ( if let (Ok(network_api), Ok(pool_api)) = (
@ -593,7 +595,11 @@ impl Helper {
PrivP2poolNetworkApi::from_str(&network_api), PrivP2poolNetworkApi::from_str(&network_api),
PrivP2poolPoolApi::from_str(&pool_api), PrivP2poolPoolApi::from_str(&pool_api),
) { ) {
PubP2poolApi::update_from_network_pool(&pub_api, network_api, pool_api); PubP2poolApi::update_from_network_pool(
&mut pub_api_lock,
network_api,
pool_api,
);
last_p2pool_request = tokio::time::Instant::now(); last_p2pool_request = tokio::time::Instant::now();
} }
} }
@ -601,9 +607,8 @@ impl Helper {
let last_status_request_expired = let last_status_request_expired =
last_status_request.elapsed() >= Duration::from_secs(60); last_status_request.elapsed() >= Duration::from_secs(60);
if (last_status_request_expired || first_loop) if (last_status_request_expired || first_loop)
&& process.lock().unwrap().state == ProcessState::Alive && process_lock.state == ProcessState::Alive
{ {
debug!("P2Pool Watchdog | Reading status output of p2pool node"); debug!("P2Pool Watchdog | Reading status output of p2pool node");
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -625,11 +630,8 @@ impl Helper {
if first_loop { if first_loop {
first_loop = false; first_loop = false;
} }
} // end of scope to drop lock
sleep_end_loop(now, ProcessName::P2pool).await; sleep_end_loop(now, ProcessName::P2pool).await;
debug!(
"P2Pool Watchdog | END OF LOOP - Tick: [{}/60]",
gui_api.lock().unwrap().tick,
);
} }
// 5. If loop broke, we must be done here. // 5. If loop broke, we must be done here.
@ -826,46 +828,39 @@ impl PubP2poolApi {
// Mutate "watchdog"'s [PubP2poolApi] with data the process output. // Mutate "watchdog"'s [PubP2poolApi] with data the process output.
pub(super) fn update_from_output( pub(super) fn update_from_output(
public: &Arc<Mutex<Self>>, public: &mut Self,
output_parse: &Arc<Mutex<String>>, output_parse: &Arc<Mutex<String>>,
output_pub: &Arc<Mutex<String>>, output_pub: &Arc<Mutex<String>>,
elapsed: std::time::Duration, elapsed: std::time::Duration,
process: &Arc<Mutex<Process>>, process: &mut Process,
) { ) {
// 1. Take the process's current output buffer and combine it with Pub (if not empty) // 1. Take the process's current output buffer and combine it with Pub (if not empty)
let mut output_pub = output_pub.lock().unwrap(); let mut output_pub = output_pub.lock().unwrap();
if !output_pub.is_empty() { if !output_pub.is_empty() {
public public.output.push_str(&std::mem::take(&mut *output_pub));
.lock()
.unwrap()
.output
.push_str(&std::mem::take(&mut *output_pub));
} }
// 2. Parse the full STDOUT // 2. Parse the full STDOUT
let mut output_parse = output_parse.lock().unwrap(); let mut output_parse = output_parse.lock().unwrap();
let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse); let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse);
// Check for "SYNCHRONIZED" only if we aren't already. // Check for "SYNCHRONIZED" only if we aren't already.
if process.lock().unwrap().state == ProcessState::Syncing { if process.state == ProcessState::Syncing {
// look for depth 0 // look for depth 0
if P2POOL_REGEX.depth_0.is_match(&output_parse) { if P2POOL_REGEX.depth_0.is_match(&output_parse) {
process.lock().unwrap().state = ProcessState::Alive; process.state = ProcessState::Alive;
} }
} }
// check if zmq server still alive // check if zmq server still alive
if process.lock().unwrap().state == ProcessState::Alive if process.state == ProcessState::Alive && contains_zmq_connection_lost(&output_parse) {
&& contains_zmq_connection_lost(&output_parse)
{
// node zmq is not responding, p2pool is not ready // node zmq is not responding, p2pool is not ready
process.lock().unwrap().state = ProcessState::Syncing; process.state = ProcessState::Syncing;
} }
// 3. Throw away [output_parse] // 3. Throw away [output_parse]
output_parse.clear(); output_parse.clear();
drop(output_parse); drop(output_parse);
// 4. Add to current values // 4. Add to current values
let mut public = public.lock().unwrap();
let (payouts, xmr) = (public.payouts + payouts_new, public.xmr + xmr_new); let (payouts, xmr) = (public.payouts + payouts_new, public.xmr + xmr_new);
// 5. Calculate hour/day/month given elapsed time // 5. Calculate hour/day/month given elapsed time
@ -912,13 +907,12 @@ impl PubP2poolApi {
xmr_hour, xmr_hour,
xmr_day, xmr_day,
xmr_month, xmr_month,
..std::mem::take(&mut *public) ..std::mem::take(public)
}; };
} }
// Mutate [PubP2poolApi] with data from a [PrivP2poolLocalApi] and the process output. // Mutate [PubP2poolApi] with data from a [PrivP2poolLocalApi] and the process output.
pub(super) fn update_from_local(public: &Arc<Mutex<Self>>, local: PrivP2poolLocalApi) { pub(super) fn update_from_local(public: &mut Self, local: PrivP2poolLocalApi) {
let mut public = public.lock().unwrap();
*public = Self { *public = Self {
hashrate_15m: HumanNumber::from_u64(local.hashrate_15m), hashrate_15m: HumanNumber::from_u64(local.hashrate_15m),
hashrate_1h: HumanNumber::from_u64(local.hashrate_1h), hashrate_1h: HumanNumber::from_u64(local.hashrate_1h),
@ -934,11 +928,11 @@ impl PubP2poolApi {
// Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api]. // Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api].
pub(super) fn update_from_network_pool( pub(super) fn update_from_network_pool(
public: &Arc<Mutex<Self>>, public: &mut Self,
net: PrivP2poolNetworkApi, net: PrivP2poolNetworkApi,
pool: PrivP2poolPoolApi, pool: PrivP2poolPoolApi,
) { ) {
let user_hashrate = public.lock().unwrap().user_p2pool_hashrate_u64; // The user's total P2Pool hashrate let user_hashrate = public.user_p2pool_hashrate_u64; // The user's total P2Pool hashrate
let monero_difficulty = net.difficulty; let monero_difficulty = net.difficulty;
let monero_hashrate = monero_difficulty / MONERO_BLOCK_TIME_IN_SECONDS; let monero_hashrate = monero_difficulty / MONERO_BLOCK_TIME_IN_SECONDS;
let p2pool_hashrate = pool.pool_statistics.hashRate; let p2pool_hashrate = pool.pool_statistics.hashRate;
@ -980,7 +974,6 @@ impl PubP2poolApi {
p2pool_difficulty / user_hashrate, p2pool_difficulty / user_hashrate,
)); ));
} }
let mut public = public.lock().unwrap();
*public = Self { *public = Self {
p2pool_difficulty_u64: p2pool_difficulty, p2pool_difficulty_u64: p2pool_difficulty,
monero_difficulty_u64: monero_difficulty, monero_difficulty_u64: monero_difficulty,

View file

@ -116,8 +116,14 @@ Uptime = 0h 2m 4s
"".to_string(), "".to_string(),
PathBuf::new(), PathBuf::new(),
))); )));
PubP2poolApi::update_from_output(&public, &output_parse, &output_pub, elapsed, &process); let mut public = public.lock().unwrap();
let public = public.lock().unwrap(); PubP2poolApi::update_from_output(
&mut public,
&output_parse,
&output_pub,
elapsed,
&mut process.lock().unwrap(),
);
println!("{:#?}", public); println!("{:#?}", public);
assert_eq!(public.payouts, 3); assert_eq!(public.payouts, 3);
assert_eq!(public.payouts_hour, 180.0); assert_eq!(public.payouts_hour, 180.0);
@ -161,8 +167,8 @@ Uptime = 0h 2m 4s
}, },
}; };
// Update Local // Update Local
PubP2poolApi::update_from_local(&public, local); let mut p = public.lock().unwrap();
let p = public.lock().unwrap(); PubP2poolApi::update_from_local(&mut p, local);
println!("AFTER LOCAL: {:#?}", p); println!("AFTER LOCAL: {:#?}", p);
assert_eq!(p.hashrate_15m.to_string(), "10,000"); assert_eq!(p.hashrate_15m.to_string(), "10,000");
assert_eq!(p.hashrate_1h.to_string(), "20,000"); assert_eq!(p.hashrate_1h.to_string(), "20,000");
@ -175,10 +181,8 @@ Uptime = 0h 2m 4s
assert_eq!(p.current_effort.to_string(), "200.00%"); assert_eq!(p.current_effort.to_string(), "200.00%");
assert_eq!(p.connections.to_string(), "1,234"); assert_eq!(p.connections.to_string(), "1,234");
assert_eq!(p.user_p2pool_hashrate_u64, 20000); assert_eq!(p.user_p2pool_hashrate_u64, 20000);
drop(p);
// Update Network + Pool // Update Network + Pool
PubP2poolApi::update_from_network_pool(&public, network, pool); PubP2poolApi::update_from_network_pool(&mut p, network, pool);
let p = public.lock().unwrap();
println!("AFTER NETWORK+POOL: {:#?}", p); println!("AFTER NETWORK+POOL: {:#?}", p);
assert_eq!(p.monero_difficulty.to_string(), "300,000,000,000"); assert_eq!(p.monero_difficulty.to_string(), "300,000,000,000");
assert_eq!(p.monero_hashrate.to_string(), "2.500 GH/s"); assert_eq!(p.monero_hashrate.to_string(), "2.500 GH/s");

View file

@ -1,12 +1,12 @@
use crate::constants::*;
use crate::helper::xrig::update_xmrig_config; use crate::helper::xrig::update_xmrig_config;
use crate::helper::{check_died, check_user_input, sleep_end_loop, Process}; use crate::helper::{arc_mut, check_died, check_user_input, sleep, sleep_end_loop, Process};
use crate::helper::{Helper, ProcessName, ProcessSignal, ProcessState}; use crate::helper::{Helper, ProcessName, ProcessSignal, ProcessState};
use crate::helper::{PubXvbApi, XvbNode}; use crate::helper::{PubXvbApi, XvbNode};
use crate::miscs::output_console; use crate::miscs::output_console;
use crate::regex::{contains_error, contains_usepool, detect_new_node_xmrig, XMRIG_REGEX}; use crate::regex::{contains_error, contains_usepool, detect_new_node_xmrig, XMRIG_REGEX};
use crate::utils::human::HumanNumber; use crate::utils::human::HumanNumber;
use crate::utils::sudo::SudoState; use crate::utils::sudo::SudoState;
use crate::{constants::*, macros::*};
use enclose::enclose; use enclose::enclose;
use log::*; use log::*;
use portable_pty::Child; use portable_pty::Child;
@ -514,7 +514,7 @@ impl Helper {
} }
// Stop on [Stop/Restart] SIGNAL // Stop on [Stop/Restart] SIGNAL
if Self::xmrig_signal_end( if Self::xmrig_signal_end(
&process, &mut process.lock().unwrap(),
&child_pty, &child_pty,
&start, &start,
&mut gui_api.lock().unwrap().output, &mut gui_api.lock().unwrap().output,
@ -591,13 +591,13 @@ impl Helper {
info!("XMRig Watchdog | Watchdog thread exiting... Goodbye!"); info!("XMRig Watchdog | Watchdog thread exiting... Goodbye!");
} }
fn xmrig_signal_end( fn xmrig_signal_end(
process: &Arc<Mutex<Process>>, process: &mut Process,
child_pty: &Arc<Mutex<Box<dyn Child + Sync + Send>>>, child_pty: &Arc<Mutex<Box<dyn Child + Sync + Send>>>,
start: &Instant, start: &Instant,
gui_api_output_raw: &mut String, gui_api_output_raw: &mut String,
sudo: &Arc<Mutex<SudoState>>, sudo: &Arc<Mutex<SudoState>>,
) -> bool { ) -> bool {
let signal = process.lock().unwrap().signal; let signal = process.signal;
if signal == ProcessSignal::Stop || signal == ProcessSignal::Restart { if signal == ProcessSignal::Stop || signal == ProcessSignal::Restart {
debug!("XMRig Watchdog | Stop/Restart SIGNAL caught"); debug!("XMRig Watchdog | Stop/Restart SIGNAL caught");
// macOS requires [sudo] again to kill [XMRig] // macOS requires [sudo] again to kill [XMRig]
@ -616,7 +616,6 @@ impl Helper {
} }
let exit_status = match child_pty.lock().unwrap().wait() { let exit_status = match child_pty.lock().unwrap().wait() {
Ok(e) => { Ok(e) => {
let mut process = process.lock().unwrap();
if e.success() { if e.success() {
if process.signal == ProcessSignal::Stop { if process.signal == ProcessSignal::Stop {
process.state = ProcessState::Dead; process.state = ProcessState::Dead;
@ -630,7 +629,6 @@ impl Helper {
} }
} }
_ => { _ => {
let mut process = process.lock().unwrap();
if process.signal == ProcessSignal::Stop { if process.signal == ProcessSignal::Stop {
process.state = ProcessState::Failed; process.state = ProcessState::Failed;
} }
@ -652,7 +650,6 @@ impl Helper {
e e
); );
} }
let mut process = process.lock().unwrap();
match process.signal { match process.signal {
ProcessSignal::Stop => process.signal = ProcessSignal::None, ProcessSignal::Stop => process.signal = ProcessSignal::None,
ProcessSignal::Restart => process.state = ProcessState::Waiting, ProcessSignal::Restart => process.state = ProcessState::Waiting,

View file

@ -371,7 +371,7 @@ impl Helper {
loop { loop {
let now = Instant::now(); let now = Instant::now();
debug!("XMRig-Proxy Watchdog | ----------- Start of loop -----------"); debug!("XMRig-Proxy Watchdog | ----------- Start of loop -----------");
// check state {
if check_died( if check_died(
&child_pty, &child_pty,
&mut process.lock().unwrap(), &mut process.lock().unwrap(),
@ -382,7 +382,7 @@ impl Helper {
} }
// check signal // check signal
if signal_end( if signal_end(
process, &mut process.lock().unwrap(),
&child_pty, &child_pty,
&start, &start,
&mut gui_api.lock().unwrap().output, &mut gui_api.lock().unwrap().output,
@ -395,10 +395,10 @@ impl Helper {
// Check if logs need resetting // Check if logs need resetting
debug!("XMRig-Proxy Watchdog | Attempting GUI log reset check"); debug!("XMRig-Proxy Watchdog | Attempting GUI log reset check");
{ Self::check_reset_gui_output(
let mut lock = gui_api.lock().unwrap(); &mut gui_api.lock().unwrap().output,
Self::check_reset_gui_output(&mut lock.output, ProcessName::XmrigProxy); ProcessName::XmrigProxy,
} );
// Always update from output // Always update from output
// todo: check difference with xmrig // todo: check difference with xmrig
debug!("XMRig-Proxy Watchdog | Starting [update_from_output()]"); debug!("XMRig-Proxy Watchdog | Starting [update_from_output()]");
@ -411,7 +411,8 @@ impl Helper {
); );
// update data from api // update data from api
debug!("XMRig-Proxy Watchdog | Attempting HTTP API request..."); debug!("XMRig-Proxy Watchdog | Attempting HTTP API request...");
match PrivXmrigProxyApi::request_xp_api(&client, api_summary_xp, token_proxy).await { match PrivXmrigProxyApi::request_xp_api(&client, api_summary_xp, token_proxy).await
{
Ok(priv_api) => { Ok(priv_api) => {
debug!("XMRig-Proxy Watchdog | HTTP API request OK, attempting [update_from_priv()]"); debug!("XMRig-Proxy Watchdog | HTTP API request OK, attempting [update_from_priv()]");
PubXmrigProxyApi::update_from_priv(pub_api, priv_api); PubXmrigProxyApi::update_from_priv(pub_api, priv_api);
@ -455,6 +456,7 @@ impl Helper {
debug!("XMRig-Proxy Process | mining on Xmrig-Proxy pool"); debug!("XMRig-Proxy Process | mining on Xmrig-Proxy pool");
} }
} }
} // locked are dropped here
// do not use more than 1 second for the loop // do not use more than 1 second for the loop
sleep_end_loop(now, ProcessName::XmrigProxy).await; sleep_end_loop(now, ProcessName::XmrigProxy).await;
} }

View file

@ -208,6 +208,7 @@ impl Helper {
debug!("XvB Watchdog | ----------- Start of loop -----------"); debug!("XvB Watchdog | ----------- Start of loop -----------");
// Set timer of loop // Set timer of loop
let start_loop = std::time::Instant::now(); let start_loop = std::time::Instant::now();
{
// check if first loop the state of Xmrig-Proxy // check if first loop the state of Xmrig-Proxy
if first_loop { if first_loop {
xp_alive = process_xp.lock().unwrap().state == ProcessState::Alive; xp_alive = process_xp.lock().unwrap().state == ProcessState::Alive;
@ -279,7 +280,9 @@ impl Helper {
&& last_request.lock().unwrap().elapsed() >= Duration::from_secs(25); && last_request.lock().unwrap().elapsed() >= Duration::from_secs(25);
let process_alive = process.lock().unwrap().state == ProcessState::Alive; let process_alive = process.lock().unwrap().state == ProcessState::Alive;
if ((last_request_expired || first_loop) if ((last_request_expired || first_loop)
|| (*retry.lock().unwrap() || is_algo_finished || should_refresh_before_next_algo) || (*retry.lock().unwrap()
|| is_algo_finished
|| should_refresh_before_next_algo)
&& process_alive) && process_alive)
&& is_request_finished && is_request_finished
{ {
@ -405,6 +408,7 @@ impl Helper {
first_loop = false; first_loop = false;
} }
// Sleep (only if 900ms hasn't passed) // Sleep (only if 900ms hasn't passed)
}
sleep_end_loop(start_loop, ProcessName::Xvb).await; sleep_end_loop(start_loop, ProcessName::Xvb).await;
} }
} }