Implemented signal handling.
This commit is contained in:
parent
bde5bc9307
commit
b27667d5e2
3 changed files with 76 additions and 11 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -10,15 +10,15 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
name = "kt"
|
name = "kt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"signal-hook",
|
||||||
"termion",
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.91"
|
version = "0.2.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
|
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
|
@ -44,6 +44,25 @@ dependencies = [
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termion"
|
name = "termion"
|
||||||
version = "1.5.6"
|
version = "1.5.6"
|
||||||
|
|
|
@ -7,5 +7,5 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
termion = "1.5"
|
termion = "1.5.6"
|
||||||
libc = "0.2"
|
signal-hook = "0.3.8"
|
||||||
|
|
58
src/main.rs
58
src/main.rs
|
@ -1,5 +1,5 @@
|
||||||
extern crate termion;
|
extern crate termion;
|
||||||
extern crate libc;
|
extern crate signal_hook;
|
||||||
mod alarm;
|
mod alarm;
|
||||||
mod clock;
|
mod clock;
|
||||||
mod common;
|
mod common;
|
||||||
|
@ -7,6 +7,9 @@ mod layout;
|
||||||
|
|
||||||
use std::{time, thread, env};
|
use std::{time, thread, env};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use signal_hook::flag;
|
||||||
use termion::{clear, color, cursor, style};
|
use termion::{clear, color, cursor, style};
|
||||||
use termion::raw::{IntoRawMode, RawTerminal};
|
use termion::raw::{IntoRawMode, RawTerminal};
|
||||||
use termion::event::Key;
|
use termion::event::Key;
|
||||||
|
@ -24,11 +27,20 @@ const USAGE: &str =
|
||||||
-e, --exec [COMMAND] Execute \"COMMAND\" on alarm. Must be the last flag on
|
-e, --exec [COMMAND] Execute \"COMMAND\" on alarm. Must be the last flag on
|
||||||
the command line. Everything after it is passed as
|
the command line. Everything after it is passed as
|
||||||
argument to \"COMMAND\". Every \"%s\" will be replaced
|
argument to \"COMMAND\". Every \"%s\" will be replaced
|
||||||
with the elapsed time in [(HH:)MM:SS] format.";
|
with the elapsed time in [(HH:)MM:SS] format.
|
||||||
|
|
||||||
|
SIGNALS: <SIGUSR1> Reset clock.
|
||||||
|
<SIGUSR2> Pause or un-pause clock.";
|
||||||
const MENUBAR: &str =
|
const MENUBAR: &str =
|
||||||
"[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit";
|
"[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit";
|
||||||
const MENUBAR_SHORT: &str =
|
const MENUBAR_SHORT: &str =
|
||||||
"[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit";
|
"[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit";
|
||||||
|
// Needed for signal_hook.
|
||||||
|
const SIGTSTP: usize = signal_hook::consts::SIGTSTP as usize;
|
||||||
|
const SIGTERM: usize = signal_hook::consts::SIGTERM as usize;
|
||||||
|
const SIGINT: usize = signal_hook::consts::SIGINT as usize;
|
||||||
|
const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize;
|
||||||
|
const SIGUSR2: usize = signal_hook::consts::SIGUSR2 as usize;
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
plain: bool,
|
plain: bool,
|
||||||
|
@ -55,6 +67,10 @@ fn main() {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
let mut buffer_updated: bool = false;
|
let mut buffer_updated: bool = false;
|
||||||
let mut countdown = Countdown::new();
|
let mut countdown = Countdown::new();
|
||||||
|
|
||||||
|
// Register signal handlers.
|
||||||
|
let signal = Arc::new(AtomicUsize::new(0));
|
||||||
|
register_signal_handlers(&signal);
|
||||||
|
|
||||||
// Clear screen and hide cursor.
|
// Clear screen and hide cursor.
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
|
@ -67,6 +83,29 @@ fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// Process received signals.
|
||||||
|
match signal.swap(0, Ordering::Relaxed) {
|
||||||
|
// No signal received.
|
||||||
|
0 => (),
|
||||||
|
// Suspend execution on SIGTSTP.
|
||||||
|
SIGTSTP => {
|
||||||
|
suspend(&mut stdout);
|
||||||
|
layout.force_redraw = true;
|
||||||
|
},
|
||||||
|
// Exit main loop on SIGTERM and SIGINT.
|
||||||
|
SIGTERM | SIGINT => break,
|
||||||
|
// Reset clock on SIGUSR1.
|
||||||
|
SIGUSR1 => {
|
||||||
|
clock.reset();
|
||||||
|
alarm_roster.reset_all();
|
||||||
|
layout.force_redraw = true;
|
||||||
|
},
|
||||||
|
// (Un-)Pause clock on SIGUSR2.
|
||||||
|
SIGUSR2 => clock.toggle(),
|
||||||
|
// We didn't register anything else.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
// Process input.
|
// Process input.
|
||||||
if let Some(key) = input_keys.next() {
|
if let Some(key) = input_keys.next() {
|
||||||
match key.expect("Error reading input") {
|
match key.expect("Error reading input") {
|
||||||
|
@ -269,7 +308,15 @@ fn parse_args(config: &mut Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suspend execution by raising SIGTSTP.
|
fn register_signal_handlers(signal: &Arc<AtomicUsize>) {
|
||||||
|
flag::register_usize(SIGTSTP as i32, Arc::clone(&signal), SIGTSTP).unwrap();
|
||||||
|
flag::register_usize(SIGTERM as i32, Arc::clone(&signal), SIGTERM).unwrap();
|
||||||
|
flag::register_usize(SIGINT as i32, Arc::clone(&signal), SIGINT).unwrap();
|
||||||
|
flag::register_usize(SIGUSR1 as i32, Arc::clone(&signal), SIGUSR1).unwrap();
|
||||||
|
flag::register_usize(SIGUSR2 as i32, Arc::clone(&signal), SIGUSR2).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suspend execution on SIGTSTP.
|
||||||
fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
|
fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
"{}{}{}",
|
"{}{}{}",
|
||||||
|
@ -283,9 +330,8 @@ fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
|
||||||
eprintln!("Failed to leave raw terminal mode prior to suspend: {}", error);
|
eprintln!("Failed to leave raw terminal mode prior to suspend: {}", error);
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = unsafe { libc::raise(libc::SIGTSTP) };
|
if let Err(error) = signal_hook::low_level::emulate_default_handler(SIGTSTP as i32) {
|
||||||
if result != 0 {
|
eprintln!("Error raising SIGTSTP: {}", error);
|
||||||
panic!("{}", std::io::Error::last_os_error());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.activate_raw_mode()
|
stdout.activate_raw_mode()
|
||||||
|
|
Loading…
Reference in a new issue