mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 01:18:21 +00:00
use condvar/mutex to not busywait when suspending input polling (closes #153)
This commit is contained in:
parent
a4de701415
commit
923bed9abf
3 changed files with 77 additions and 30 deletions
64
src/input.rs
64
src/input.rs
|
|
@ -1,3 +1,4 @@
|
|||
use crate::notify_mutex::NotifyableMutex;
|
||||
use crossbeam_channel::{unbounded, Receiver};
|
||||
use crossterm::event::{self, Event};
|
||||
use std::{
|
||||
|
|
@ -27,7 +28,7 @@ pub enum InputEvent {
|
|||
|
||||
///
|
||||
pub struct Input {
|
||||
desired_state: Arc<AtomicBool>,
|
||||
desired_state: Arc<NotifyableMutex<bool>>,
|
||||
current_state: Arc<AtomicBool>,
|
||||
receiver: Receiver<InputEvent>,
|
||||
}
|
||||
|
|
@ -37,40 +38,39 @@ impl Input {
|
|||
pub fn new() -> Self {
|
||||
let (tx, rx) = unbounded();
|
||||
|
||||
let desired_state = Arc::new(AtomicBool::new(true));
|
||||
let desired_state = Arc::new(NotifyableMutex::new(true));
|
||||
let current_state = Arc::new(AtomicBool::new(true));
|
||||
|
||||
let arc_desired = Arc::clone(&desired_state);
|
||||
let arc_current = Arc::clone(¤t_state);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
//TODO: use condvar to not busy wait
|
||||
if arc_desired.load(Ordering::Relaxed) {
|
||||
if !arc_current.load(Ordering::Relaxed) {
|
||||
tx.send(InputEvent::State(
|
||||
InputState::Polling,
|
||||
))
|
||||
.expect("send failed");
|
||||
}
|
||||
arc_current.store(true, Ordering::Relaxed);
|
||||
thread::spawn(move || loop {
|
||||
if arc_desired.get() {
|
||||
if !arc_current.load(Ordering::Relaxed) {
|
||||
log::info!("input polling resumed");
|
||||
|
||||
if let Some(e) = Self::poll(POLL_DURATION)
|
||||
.expect("failed to pull events.")
|
||||
{
|
||||
tx.send(InputEvent::Input(e))
|
||||
.expect("send input event failed");
|
||||
}
|
||||
} else {
|
||||
if arc_current.load(Ordering::Relaxed) {
|
||||
tx.send(InputEvent::State(
|
||||
InputState::Paused,
|
||||
))
|
||||
.expect("send failed");
|
||||
}
|
||||
|
||||
arc_current.store(false, Ordering::Relaxed);
|
||||
tx.send(InputEvent::State(InputState::Polling))
|
||||
.expect("send state failed");
|
||||
}
|
||||
arc_current.store(true, Ordering::Relaxed);
|
||||
|
||||
if let Some(e) = Self::poll(POLL_DURATION)
|
||||
.expect("failed to pull events.")
|
||||
{
|
||||
tx.send(InputEvent::Input(e))
|
||||
.expect("send input failed");
|
||||
}
|
||||
} else {
|
||||
if arc_current.load(Ordering::Relaxed) {
|
||||
log::info!("input polling suspended");
|
||||
|
||||
tx.send(InputEvent::State(InputState::Paused))
|
||||
.expect("send state failed");
|
||||
}
|
||||
|
||||
arc_current.store(false, Ordering::Relaxed);
|
||||
|
||||
arc_desired.wait(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -88,12 +88,16 @@ impl Input {
|
|||
|
||||
///
|
||||
pub fn set_polling(&mut self, enabled: bool) {
|
||||
self.desired_state.store(enabled, Ordering::Relaxed);
|
||||
self.desired_state.set_and_notify(enabled)
|
||||
}
|
||||
|
||||
fn shall_poll(&self) -> bool {
|
||||
self.desired_state.get()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn is_state_changing(&self) -> bool {
|
||||
self.desired_state.load(Ordering::Relaxed)
|
||||
self.shall_poll()
|
||||
!= self.current_state.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ mod cmdbar;
|
|||
mod components;
|
||||
mod input;
|
||||
mod keys;
|
||||
mod notify_mutex;
|
||||
mod queue;
|
||||
mod spinner;
|
||||
mod strings;
|
||||
|
|
|
|||
42
src/notify_mutex.rs
Normal file
42
src/notify_mutex.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
///
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NotifyableMutex<T> {
|
||||
data: Arc<(Mutex<T>, Condvar)>,
|
||||
}
|
||||
|
||||
impl<T> NotifyableMutex<T> {
|
||||
///
|
||||
pub fn new(start_value: T) -> Self {
|
||||
Self {
|
||||
data: Arc::new((Mutex::new(start_value), Condvar::new())),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn wait(&self, condition: T)
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
let mut data = self.data.0.lock().expect("lock err");
|
||||
while *data != condition {
|
||||
data = self.data.1.wait(data).expect("wait err");
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn set_and_notify(&self, value: T) {
|
||||
*self.data.0.lock().expect("set err") = value;
|
||||
self.data.1.notify_one();
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get(&self) -> T
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
*self.data.0.lock().expect("get err")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue