From 6392904047919a8f6f4a3bbae3d371037f840300 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 29 Oct 2020 13:09:31 +0200 Subject: [PATCH] Replace PosixTimer with async timers --- src/bin.rs | 18 +- src/components/mail/compose/gpg.rs | 493 ++++++++++++++-------------- src/components/mail/listing.rs | 2 +- src/components/notifications.rs | 4 +- src/components/utilities.rs | 2 +- src/components/utilities/widgets.rs | 26 +- src/jobs.rs | 141 +++++++- src/managesieve.rs | 3 - src/state.rs | 5 +- src/types.rs | 20 +- src/unix.rs | 184 ----------- 11 files changed, 406 insertions(+), 492 deletions(-) delete mode 100644 src/unix.rs diff --git a/src/bin.rs b/src/bin.rs index b6fc61bc9..bb22acb03 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -49,9 +49,6 @@ static GLOBAL: System = System; extern crate melib; use melib::*; -mod unix; -use unix::*; - #[macro_use] pub mod types; use crate::types::*; @@ -104,7 +101,6 @@ fn notify( nix::fcntl::FcntlArg::F_SETFL(nix::fcntl::OFlag::O_NONBLOCK), ); std::thread::spawn(move || { - let mut buf = [0; 1]; let mut ctr = 0; loop { ctr %= 3; @@ -117,16 +113,6 @@ fn notify( for signal in signals.pending() { let _ = s.send_timeout(signal, Duration::from_millis(500)).ok(); } - while nix::unistd::read(alarm_pipe_r, buf.as_mut()) - .map(|s| s > 0) - .unwrap_or(false) - { - let value = buf[0]; - let _ = sender.send_timeout( - ThreadEvent::UIEvent(UIEvent::Timer(value)), - Duration::from_millis(2000), - ); - } std::thread::sleep(std::time::Duration::from_millis(100)); ctr += 1; @@ -377,7 +363,9 @@ fn run_app(opt: Opt) -> Result<()> { #[cfg(all(target_os = "linux", feature = "dbus-notifications"))] { - let dbus_notifications = Box::new(components::notifications::DbusNotifications::new()); + let dbus_notifications = Box::new(components::notifications::DbusNotifications::new( + &state.context, + )); state.register_component(dbus_notifications); } state.register_component(Box::new( diff --git a/src/components/mail/compose/gpg.rs b/src/components/mail/compose/gpg.rs index f51fa40e2..7aa64cfac 100644 --- a/src/components/mail/compose/gpg.rs +++ b/src/components/mail/compose/gpg.rs @@ -19,273 +19,270 @@ * along with meli. If not, see . */ - use super::*; +use super::*; - #[derive(Debug)] - pub enum KeySelection { - LoadingKeys { - handle: JoinHandle>>, - progress_spinner: ProgressSpinner, - secret: bool, - local: bool, - pattern: String, - allow_remote_lookup: ToggleFlag, - }, - Error { - id: ComponentId, - err: MeliError, - }, - Loaded { - widget: UIDialog, - keys: Vec, - }, +#[derive(Debug)] +pub enum KeySelection { + LoadingKeys { + handle: JoinHandle>>, + progress_spinner: ProgressSpinner, + secret: bool, + local: bool, + pattern: String, + allow_remote_lookup: ToggleFlag, + }, + Error { + id: ComponentId, + err: MeliError, + }, + Loaded { + widget: UIDialog, + keys: Vec, + }, +} + +impl std::fmt::Display for KeySelection { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "select pgp keys") } +} - impl std::fmt::Display for KeySelection { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "select pgp keys") +impl KeySelection { + pub fn new( + secret: bool, + local: bool, + pattern: String, + allow_remote_lookup: ToggleFlag, + context: &mut Context, + ) -> Result { + use melib::gpgme::*; + debug!("KeySelection::new"); + debug!(&secret); + debug!(&local); + debug!(&pattern); + debug!(&allow_remote_lookup); + let mut ctx = Context::new()?; + if local { + ctx.set_auto_key_locate(LocateKey::LOCAL)?; + } else { + ctx.set_auto_key_locate(LocateKey::WKD | LocateKey::LOCAL)?; + } + let job = ctx.keylist(secret, Some(pattern.clone()))?; + let handle = context.job_executor.spawn_specialized(job); + let mut progress_spinner = ProgressSpinner::new(8, context); + progress_spinner.start(); + Ok(KeySelection::LoadingKeys { + handle, + secret, + local, + pattern, + allow_remote_lookup, + progress_spinner, + }) + } +} + +impl Component for KeySelection { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + match self { + KeySelection::LoadingKeys { + ref mut progress_spinner, + .. + } => progress_spinner.draw(grid, center_area(area, (2, 2)), context), + KeySelection::Error { ref err, .. } => { + let theme_default = crate::conf::value(context, "theme_default"); + write_string_to_grid( + &err.to_string(), + grid, + theme_default.fg, + theme_default.bg, + theme_default.attrs, + center_area(area, (15, 2)), + Some(0), + ); + } + KeySelection::Loaded { ref mut widget, .. } => { + widget.draw(grid, center_area(area, widget.content.size()), context) + } } } - impl KeySelection { - pub fn new( - secret: bool, - local: bool, - pattern: String, - allow_remote_lookup: ToggleFlag, - context: &mut Context, - ) -> Result { - use melib::gpgme::*; - debug!("KeySelection::new"); - debug!(&secret); - debug!(&local); - debug!(&pattern); - debug!(&allow_remote_lookup); - let mut ctx = Context::new()?; - if local { - ctx.set_auto_key_locate(LocateKey::LOCAL)?; - } else { - ctx.set_auto_key_locate(LocateKey::WKD | LocateKey::LOCAL)?; - } - let job = ctx.keylist(secret, Some(pattern.clone()))?; - let handle = context.job_executor.spawn_specialized(job); - let mut progress_spinner = ProgressSpinner::new(8); - progress_spinner.start(); - Ok(KeySelection::LoadingKeys { - handle, + fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { + debug!(&self); + debug!(&event); + match self { + KeySelection::LoadingKeys { + ref mut progress_spinner, + ref mut handle, secret, local, - pattern, + ref mut pattern, allow_remote_lookup, - progress_spinner, - }) - } - } - - impl Component for KeySelection { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - match self { - KeySelection::LoadingKeys { - ref mut progress_spinner, - .. - } => progress_spinner.draw(grid, center_area(area, (2, 2)), context), - KeySelection::Error { ref err, .. } => { - let theme_default = crate::conf::value(context, "theme_default"); - write_string_to_grid( - &err.to_string(), - grid, - theme_default.fg, - theme_default.bg, - theme_default.attrs, - center_area(area, (15, 2)), - Some(0), - ); - } - KeySelection::Loaded { ref mut widget, .. } => { - widget.draw(grid, center_area(area, widget.content.size()), context) - } - } - } - - fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { - debug!(&self); - debug!(&event); - match self { - KeySelection::LoadingKeys { - ref mut progress_spinner, - ref mut handle, - secret, - local, - ref mut pattern, - allow_remote_lookup, - .. - } => match event { - UIEvent::StatusEvent(StatusEvent::JobFinished(ref id)) - if *id == handle.job_id => - { - match handle.chan.try_recv().unwrap().unwrap() { - Ok(keys) => { - if keys.is_empty() { - let id = progress_spinner.id(); - if allow_remote_lookup.is_true() { - match Self::new( - *secret, - *local, - std::mem::replace(pattern, String::new()), - *allow_remote_lookup, - context, - ) { - Ok(w) => { - *self = w; - } - Err(err) => *self = KeySelection::Error { err, id }, - } - } else if !*local && allow_remote_lookup.is_ask() { - *self = KeySelection::Error { - err: MeliError::new(format!( - "No keys found for {}, perform remote lookup?", - pattern - )), - id, - } - } else { - *self = KeySelection::Error { - err: MeliError::new(format!( - "No keys found for {}.", - pattern - )), - id, + .. + } => match event { + UIEvent::StatusEvent(StatusEvent::JobFinished(ref id)) if *id == handle.job_id => { + match handle.chan.try_recv().unwrap().unwrap() { + Ok(keys) => { + if keys.is_empty() { + let id = progress_spinner.id(); + if allow_remote_lookup.is_true() { + match Self::new( + *secret, + *local, + std::mem::replace(pattern, String::new()), + *allow_remote_lookup, + context, + ) { + Ok(w) => { + *self = w; } + Err(err) => *self = KeySelection::Error { err, id }, } - if let KeySelection::Error { ref err, .. } = self { - context.replies.push_back(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(err.to_string()), - )); - let res: Option = None; - context.replies.push_back(UIEvent::FinishedUIDialog( - id, - Box::new(res), - )); + } else if !*local && allow_remote_lookup.is_ask() { + *self = KeySelection::Error { + err: MeliError::new(format!( + "No keys found for {}, perform remote lookup?", + pattern + )), + id, + } + } else { + *self = KeySelection::Error { + err: MeliError::new(format!( + "No keys found for {}.", + pattern + )), + id, } - return true; } - let mut widget = UIDialog::new( - "select key", - keys.iter() - .map(|k| { - ( - k.clone(), - if let Some(primary_uid) = k.primary_uid() { - format!("{} {}", k.fingerprint(), primary_uid) - } else { - k.fingerprint().to_string() - }, - ) - }) - .collect::>(), - true, - Some(Box::new( - move |id: ComponentId, results: &[melib::gpgme::Key]| { - Some(UIEvent::FinishedUIDialog( - id, - Box::new(results.get(0).map(|k| k.clone())), - )) - }, - )), - context, - ); - widget.set_dirty(true); - *self = KeySelection::Loaded { widget, keys }; - } - Err(err) => { - *self = KeySelection::Error { - err, - id: ComponentId::new_v4(), - }; + if let KeySelection::Error { ref err, .. } = self { + context.replies.push_back(UIEvent::StatusEvent( + StatusEvent::DisplayMessage(err.to_string()), + )); + let res: Option = None; + context + .replies + .push_back(UIEvent::FinishedUIDialog(id, Box::new(res))); + } + return true; } + let mut widget = UIDialog::new( + "select key", + keys.iter() + .map(|k| { + ( + k.clone(), + if let Some(primary_uid) = k.primary_uid() { + format!("{} {}", k.fingerprint(), primary_uid) + } else { + k.fingerprint().to_string() + }, + ) + }) + .collect::>(), + true, + Some(Box::new( + move |id: ComponentId, results: &[melib::gpgme::Key]| { + Some(UIEvent::FinishedUIDialog( + id, + Box::new(results.get(0).map(|k| k.clone())), + )) + }, + )), + context, + ); + widget.set_dirty(true); + *self = KeySelection::Loaded { widget, keys }; + } + Err(err) => { + *self = KeySelection::Error { + err, + id: ComponentId::new_v4(), + }; } - true } - _ => progress_spinner.process_event(event, context), - }, - KeySelection::Error { .. } => false, - KeySelection::Loaded { ref mut widget, .. } => widget.process_event(event, context), - } - } - - fn is_dirty(&self) -> bool { - match self { - KeySelection::LoadingKeys { - ref progress_spinner, - .. - } => progress_spinner.is_dirty(), - KeySelection::Error { .. } => true, - KeySelection::Loaded { ref widget, .. } => widget.is_dirty(), - } - } - - fn set_dirty(&mut self, value: bool) { - match self { - KeySelection::LoadingKeys { - ref mut progress_spinner, - .. - } => progress_spinner.set_dirty(value), - KeySelection::Error { .. } => {} - KeySelection::Loaded { ref mut widget, .. } => widget.set_dirty(value), - } - } - - fn kill(&mut self, _uuid: Uuid, _context: &mut Context) {} - - fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { - match self { - KeySelection::LoadingKeys { .. } | KeySelection::Error { .. } => { - ShortcutMaps::default() + true } - KeySelection::Loaded { ref widget, .. } => widget.get_shortcuts(context), - } - } - - fn id(&self) -> ComponentId { - match self { - KeySelection::LoadingKeys { - ref progress_spinner, - .. - } => progress_spinner.id(), - KeySelection::Error { ref id, .. } => *id, - KeySelection::Loaded { ref widget, .. } => widget.id(), - } - } - - fn set_id(&mut self, new_id: ComponentId) { - match self { - KeySelection::LoadingKeys { - ref mut progress_spinner, - .. - } => progress_spinner.set_id(new_id), - KeySelection::Error { ref mut id, .. } => *id = new_id, - KeySelection::Loaded { ref mut widget, .. } => widget.set_id(new_id), - } + _ => progress_spinner.process_event(event, context), + }, + KeySelection::Error { .. } => false, + KeySelection::Loaded { ref mut widget, .. } => widget.process_event(event, context), } } - #[derive(Debug, Clone)] - pub struct GpgComposeState { - pub sign_mail: ToggleFlag, - pub encrypt_mail: ToggleFlag, - pub encrypt_keys: Vec, - pub encrypt_for_self: bool, - pub sign_keys: Vec, - } - - impl GpgComposeState { - pub fn new() -> Self { - GpgComposeState { - sign_mail: ToggleFlag::Unset, - encrypt_mail: ToggleFlag::Unset, - encrypt_keys: vec![], - encrypt_for_self: true, - sign_keys: vec![], - } + fn is_dirty(&self) -> bool { + match self { + KeySelection::LoadingKeys { + ref progress_spinner, + .. + } => progress_spinner.is_dirty(), + KeySelection::Error { .. } => true, + KeySelection::Loaded { ref widget, .. } => widget.is_dirty(), } } + + fn set_dirty(&mut self, value: bool) { + match self { + KeySelection::LoadingKeys { + ref mut progress_spinner, + .. + } => progress_spinner.set_dirty(value), + KeySelection::Error { .. } => {} + KeySelection::Loaded { ref mut widget, .. } => widget.set_dirty(value), + } + } + + fn kill(&mut self, _uuid: Uuid, _context: &mut Context) {} + + fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { + match self { + KeySelection::LoadingKeys { .. } | KeySelection::Error { .. } => { + ShortcutMaps::default() + } + KeySelection::Loaded { ref widget, .. } => widget.get_shortcuts(context), + } + } + + fn id(&self) -> ComponentId { + match self { + KeySelection::LoadingKeys { + ref progress_spinner, + .. + } => progress_spinner.id(), + KeySelection::Error { ref id, .. } => *id, + KeySelection::Loaded { ref widget, .. } => widget.id(), + } + } + + fn set_id(&mut self, new_id: ComponentId) { + match self { + KeySelection::LoadingKeys { + ref mut progress_spinner, + .. + } => progress_spinner.set_id(new_id), + KeySelection::Error { ref mut id, .. } => *id = new_id, + KeySelection::Loaded { ref mut widget, .. } => widget.set_id(new_id), + } + } +} + +#[derive(Debug, Clone)] +pub struct GpgComposeState { + pub sign_mail: ToggleFlag, + pub encrypt_mail: ToggleFlag, + pub encrypt_keys: Vec, + pub encrypt_for_self: bool, + pub sign_keys: Vec, +} + +impl GpgComposeState { + pub fn new() -> Self { + GpgComposeState { + sign_mail: ToggleFlag::Unset, + encrypt_mail: ToggleFlag::Unset, + encrypt_keys: vec![], + encrypt_for_self: true, + sign_keys: vec![], + } + } +} diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index cd30fc49f..15d122235 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -1391,7 +1391,7 @@ impl Listing { dirty: true, cursor_pos: (0, 0), menu_cursor_pos: (0, 0), - startup_checks_rate: RateLimit::new(2, 1000), + startup_checks_rate: RateLimit::new(2, 1000, context.job_executor.clone()), theme_default: conf::value(context, "theme_default"), id: ComponentId::new_v4(), show_divider: false, diff --git a/src/components/notifications.rs b/src/components/notifications.rs index 7c6185231..c3a828b0b 100644 --- a/src/components/notifications.rs +++ b/src/components/notifications.rs @@ -47,9 +47,9 @@ mod dbus { } impl DbusNotifications { - pub fn new() -> Self { + pub fn new(context: &Context) -> Self { DbusNotifications { - rate_limit: RateLimit::new(1000, 1000), + rate_limit: RateLimit::new(1000, 1000, context.job_executor.clone()), } } } diff --git a/src/components/utilities.rs b/src/components/utilities.rs index 990641e74..4346a6346 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -74,7 +74,7 @@ impl fmt::Display for StatusBar { impl StatusBar { pub fn new(context: &Context, container: Box) -> Self { - let mut progress_spinner = ProgressSpinner::new(19); + let mut progress_spinner = ProgressSpinner::new(19, context); match context.settings.terminal.progress_spinner_sequence.as_ref() { Some(conf::terminal::ProgressSpinnerSequence::Integer(k)) => { progress_spinner.set_kind(*k); diff --git a/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs index 132f19fdc..cd7d90300 100644 --- a/src/components/utilities/widgets.rs +++ b/src/components/utilities/widgets.rs @@ -1154,7 +1154,7 @@ impl ScrollBar { #[derive(Debug)] pub struct ProgressSpinner { - timer: crate::timer::PosixTimer, + timer: crate::jobs::Timer, stage: usize, pub kind: std::result::Result>, pub width: usize, @@ -1201,13 +1201,11 @@ impl ProgressSpinner { const INTERVAL: std::time::Duration = std::time::Duration::from_millis(50); - pub fn new(kind: usize) -> Self { - let timer = crate::timer::PosixTimer::new_with_signal( - std::time::Duration::from_millis(0), - std::time::Duration::from_millis(0), - nix::sys::signal::Signal::SIGALRM, - ) - .unwrap(); + pub fn new(kind: usize, context: &Context) -> Self { + let timer = context + .job_executor + .clone() + .create_timer(Self::INTERVAL, Self::INTERVAL); let kind = kind % Self::KINDS.len(); let width = Self::KINDS[kind] .iter() @@ -1255,19 +1253,13 @@ impl ProgressSpinner { return; } self.active = true; - self.timer - .set_interval(Self::INTERVAL) - .set_value(Self::INTERVAL) - .rearm() + self.timer.rearm(); } pub fn stop(&mut self) { self.active = false; self.stage = 0; - self.timer - .set_interval(std::time::Duration::from_millis(0)) - .set_value(std::time::Duration::from_millis(0)) - .rearm() + self.timer.disable(); } } @@ -1309,7 +1301,7 @@ impl Component for ProgressSpinner { fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { match event { - UIEvent::Timer(id) if *id == self.timer.si_value => { + UIEvent::Timer(id) if *id == self.timer.id() => { match self.kind.as_ref() { Ok(kind) => { self.stage = (self.stage + 1).wrapping_rem(Self::KINDS[*kind].len()); diff --git a/src/jobs.rs b/src/jobs.rs index 63e0fcb4a..2ded0da4d 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -28,14 +28,15 @@ use melib::error::Result; use melib::smol; +use std::collections::HashMap; use std::future::Future; use std::panic::catch_unwind; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; use uuid::Uuid; -use crate::types::ThreadEvent; +use crate::types::{ThreadEvent, UIEvent}; use crossbeam::deque::{Injector, Stealer, Worker}; use crossbeam::sync::{Parker, Unparker}; use crossbeam::Sender; @@ -97,6 +98,7 @@ uuid_hash_type!(JobId); pub struct MeliTask { task: AsyncTask, id: JobId, + timer: bool, } #[derive(Debug)] @@ -105,6 +107,37 @@ pub struct JobExecutor { workers: Vec>, sender: Sender, parkers: Vec, + timers: Arc>>, +} + +#[derive(Debug, Default)] +struct TimerPrivate { + /// Interval for periodic timer. + interval: Duration, + /// Time until next expiration. + value: Duration, + active: bool, + handle: Option>, +} + +#[derive(Debug)] +pub struct Timer { + id: Uuid, + job_executor: Arc, +} + +impl Timer { + pub fn id(&self) -> Uuid { + self.id + } + + pub fn rearm(&self) { + self.job_executor.rearm(self.id); + } + + pub fn disable(&self) { + self.job_executor.disable_timer(self.id); + } } impl JobExecutor { @@ -116,6 +149,7 @@ impl JobExecutor { workers: vec![], parkers: vec![], sender, + timers: Arc::new(Mutex::new(HashMap::default())), }; let mut workers = vec![]; for _ in 0..num_cpus::get().max(1) { @@ -146,10 +180,14 @@ impl JobExecutor { parker.park_timeout(Duration::from_millis(100)); let task = find_task(&local, &global, stealers.as_slice()); if let Some(meli_task) = task { - let MeliTask { task, id } = meli_task; - debug!("Worker {} got task {:?}", i, id); + let MeliTask { task, id, timer } = meli_task; + if !timer { + debug!("Worker {} got task {:?}", i, id); + } let _ = catch_unwind(|| task.run()); - debug!("Worker {} returned after {:?}", i, id); + if !timer { + debug!("Worker {} returned after {:?}", i, id); + } } }) .unwrap(); @@ -177,7 +215,13 @@ impl JobExecutor { .unwrap(); Ok(()) }, - move |task| injector.push(MeliTask { task, id: job_id }), + move |task| { + injector.push(MeliTask { + task, + id: job_id, + timer: false, + }) + }, (), ); task.schedule(); @@ -200,6 +244,91 @@ impl JobExecutor { { self.spawn_specialized(smol::unblock(move || futures::executor::block_on(future))) } + + pub fn create_timer(self: Arc, interval: Duration, value: Duration) -> Timer { + let id = Uuid::new_v4(); + let timer = TimerPrivate { + interval, + value, + active: true, + handle: None, + }; + self.timers.lock().unwrap().insert(id, timer); + self.arm_timer(id, value); + Timer { + id, + job_executor: self, + } + } + + pub fn rearm(&self, timer_id: Uuid) { + let mut timers_lck = self.timers.lock().unwrap(); + if let Some(timer) = timers_lck.get_mut(&timer_id) { + if let Some(handle) = timer.handle.take() { + handle.cancel(); + } + let value = timer.value; + drop(timers_lck); + self.arm_timer(timer_id, value); + } + } + + fn arm_timer(&self, id: Uuid, value: Duration) { + let job_id = JobId::new(); + let sender = self.sender.clone(); + let injector = self.global_queue.clone(); + let timers = self.timers.clone(); + let (task, handle) = async_task::spawn( + async move { + let mut value = value; + loop { + smol::Timer::after(value).await; + sender + .send(ThreadEvent::UIEvent(UIEvent::Timer(id))) + .unwrap(); + if let Some(interval) = timers.lock().unwrap().get(&id).and_then(|timer| { + if timer.interval.as_millis() == 0 && timer.interval.as_secs() == 0 { + None + } else if timer.active { + Some(timer.interval) + } else { + None + } + }) { + value = interval; + } else { + break; + } + } + }, + move |task| { + injector.push(MeliTask { + task, + id: job_id, + timer: true, + }) + }, + (), + ); + self.timers.lock().unwrap().entry(id).and_modify(|timer| { + timer.handle = Some(handle); + timer.active = true; + }); + task.schedule(); + for unparker in self.parkers.iter() { + unparker.unpark(); + } + } + + fn disable_timer(&self, id: Uuid) { + let mut timers_lck = self.timers.lock().unwrap(); + if let Some(timer) = timers_lck.get_mut(&id) { + if let Some(handle) = timer.handle.take() { + handle.cancel(); + } + timer.active = false; + } + } } pub type JobChannel = oneshot::Receiver; diff --git a/src/managesieve.rs b/src/managesieve.rs index 60c647206..f26353ee9 100644 --- a/src/managesieve.rs +++ b/src/managesieve.rs @@ -37,9 +37,6 @@ extern crate termion; use melib::backends::imap::managesieve::new_managesieve_connection; use melib::Result; -mod unix; -use unix::*; - #[macro_use] pub mod types; use crate::types::*; diff --git a/src/state.rs b/src/state.rs index ce2396d2f..2cd18b0af 100644 --- a/src/state.rs +++ b/src/state.rs @@ -327,7 +327,7 @@ impl State { components: Vec::with_capacity(8), overlay: Vec::new(), timer, - draw_rate_limit: RateLimit::new(1, 3), + draw_rate_limit: RateLimit::new(1, 3, job_executor.clone()), draw_horizontal_segment_fn: if settings.terminal.use_color() { State::draw_horizontal_segment } else { @@ -361,9 +361,6 @@ impl State { receiver, }, }; - s.draw_rate_limit - .timer - .set_value(std::time::Duration::from_millis(3)); if s.context.settings.terminal.ascii_drawing { s.grid.set_ascii_drawing(true); s.overlay_grid.set_ascii_drawing(true); diff --git a/src/types.rs b/src/types.rs index 5c690c579..0de210021 100644 --- a/src/types.rs +++ b/src/types.rs @@ -36,9 +36,10 @@ mod helpers; pub use self::helpers::*; use super::command::Action; -use super::jobs::JobId; +use super::jobs::{JobExecutor, JobId}; use super::terminal::*; use crate::components::{Component, ComponentId}; +use std::sync::Arc; use melib::backends::{AccountHash, BackendEvent, MailboxHash}; use melib::{EnvelopeHash, RefreshEvent, ThreadHash}; @@ -144,7 +145,7 @@ pub enum UIEvent { FinishedUIDialog(ComponentId, UIMessage), Callback(CallbackFn), GlobalUIDialog(Box), - Timer(u8), + Timer(Uuid), } pub struct CallbackFn(pub Box () + Send + 'static>); @@ -313,7 +314,7 @@ pub mod segment_tree { #[derive(Debug)] pub struct RateLimit { last_tick: std::time::Instant, - pub timer: crate::timer::PosixTimer, + pub timer: crate::jobs::Timer, rate: std::time::Duration, reqs: u64, millis: std::time::Duration, @@ -322,16 +323,13 @@ pub struct RateLimit { //FIXME: tests. impl RateLimit { - pub fn new(reqs: u64, millis: u64) -> Self { + pub fn new(reqs: u64, millis: u64, job_executor: Arc) -> Self { RateLimit { last_tick: std::time::Instant::now(), - timer: crate::timer::PosixTimer::new_with_signal( + timer: job_executor.create_timer( std::time::Duration::from_secs(0), std::time::Duration::from_millis(millis), - nix::sys::signal::Signal::SIGALRM, - ) - .unwrap(), - + ), rate: std::time::Duration::from_millis(millis / reqs), reqs, millis: std::time::Duration::from_millis(millis), @@ -357,8 +355,8 @@ impl RateLimit { } #[inline(always)] - pub fn id(&self) -> u8 { - self.timer.si_value + pub fn id(&self) -> Uuid { + self.timer.id() } } #[test] diff --git a/src/unix.rs b/src/unix.rs deleted file mode 100644 index b473fbb1d..000000000 --- a/src/unix.rs +++ /dev/null @@ -1,184 +0,0 @@ -/* - * meli - * - * Copyright 2017-2018 Manos Pitsidianakis - * - * This file is part of meli. - * - * meli is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * meli is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with meli. If not, see . - */ - -/*! UNIX and POSIX interfaces. - */ - -pub mod timer { - //! POSIX timers - //! - //! # Example usage - //! ```no_run - //! let timer = crate::timer::PosixTimer::new_with_signal( - //! std::time::Duration::from_secs(0), - //! std::time::Duration::from_secs(1), - //! nix::sys::signal::Signal::SIGALRM, - //! ) - //! .unwrap(); - //! - //! // some time passes, we should receive and handle the SIGALRM - //! // The timer remains unarmed since the interval given was zero, until we rearm it explicitly. - //! timer.rearm(); - //! ``` - use libc::clockid_t; - use libc::sigevent; - use libc::{itimerspec, timespec}; - use melib::{MeliError, Result}; - use nix::sys::signal::{SigEvent, SigevNotify}; - use std::cell::RefCell; - use std::convert::TryInto; - use std::time::Duration; - - thread_local!(static TIMER_IDS: RefCell = RefCell::new(0)); - - #[allow(non_camel_case_types)] - pub type timer_t = libc::intptr_t; - - #[link(name = "rt")] - extern "C" { - fn timer_create(clockid: clockid_t, sevp: *const sigevent, timerid: *mut timer_t) -> i32; - fn timer_settime( - timerid: timer_t, - flags: i32, - new_value: *const itimerspec, - old_value: *const itimerspec, - ) -> i32; - - fn timer_delete(timerid: timer_t) -> i32; - } - - #[derive(Debug)] - pub struct PosixTimer { - timer_id: timer_t, - /// Interval for periodic timer. - interval: Duration, - /// Time until next expiration. - value: Duration, - /// `si_value` is a byte accessible from the signal handler when it receives signals from this timer. - pub si_value: u8, - } - - impl Drop for PosixTimer { - fn drop(&mut self) { - unsafe { - timer_delete(self.timer_id); - } - } - } - - impl PosixTimer { - /// Arm without changing interval and value. - pub fn rearm(&self) { - let spec = itimerspec { - it_interval: timespec { - tv_sec: self.interval.as_secs().try_into().unwrap_or(0), - tv_nsec: self.interval.subsec_nanos().try_into().unwrap_or(0), - }, - it_value: timespec { - tv_sec: self.value.as_secs().try_into().unwrap_or(0), - tv_nsec: self.value.subsec_nanos().try_into().unwrap_or(0), - }, - }; - let ret = - unsafe { timer_settime(self.timer_id, 0, &spec as *const _, std::ptr::null_mut()) }; - if ret != 0 { - match ret { - libc::EFAULT => { - panic!( - "EFAULT: new_value, old_value, or curr_value is not a valid pointer." - ); - } - libc::EINVAL => { - panic!("EINVAL: timerid is invalid."); - } - _ => {} - } - } - } - - /// Sets value without arming timer - pub fn set_value(&mut self, value: Duration) -> &mut Self { - self.value = value; - self - } - - /// Sets interval without arming timer - pub fn set_interval(&mut self, interval: Duration) -> &mut Self { - self.interval = interval; - self - } - - pub fn new_with_signal( - interval: Duration, - value: Duration, - signal: nix::sys::signal::Signal, - ) -> Result { - let mut timer_id = Default::default(); - - let mut si_value = 0; - TIMER_IDS.with(|t| { - si_value = *t.borrow_mut(); - *t.borrow_mut() += 1; - }); - - let sigev_notify = SigevNotify::SigevSignal { - signal, - si_value: si_value as isize, - }; - let event = SigEvent::new(sigev_notify); - - let ret = unsafe { - timer_create( - libc::CLOCK_MONOTONIC, - &event.sigevent() as *const _, - &mut timer_id as *mut _, - ) - }; - - if ret != 0 { - match ret { - libc::EAGAIN => { - return Err(MeliError::new( - "Temporary error during kernel allocation of timer", - )); - } - libc::EINVAL => { - panic!("Clock ID, sigev_notify, sigev_signo, or sigev_notify_thread_id is invalid."); - } - libc::ENOMEM => { - return Err(MeliError::new("Could not allocate memory.")); - } - _ => {} - } - } - - let ret = PosixTimer { - timer_id, - interval, - value, - si_value, - }; - - ret.rearm(); - Ok(ret) - } - } -}