Skip to content

Commit 280f9b4

Browse files
committed
rust-ctrlc -> rust-simple-signal
1 parent 2ab74b5 commit 280f9b4

File tree

6 files changed

+112
-65
lines changed

6 files changed

+112
-65
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
target
22
Cargo.lock
3+
*~

Cargo.toml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
[package]
22

3-
name = "ctrlc"
3+
name = "simple-signal"
44
version = "1.0.0"
5-
authors = ["Antti Keränen <detegr@gmail.com>"]
5+
authors = ["Antti Keränen <detegr@gmail.com>", "Alexey Voznyuk <me@swizard.info"]
66
license = "MIT"
7-
keywords = ["ctrlc", "signal", "SIGINT"]
8-
description = "Easy Ctrl-C handler for Rust projects"
9-
homepage = "https://github.com/Detegr/rust-ctrlc"
10-
repository = "https://github.com/Detegr/rust-ctrlc.git"
7+
keywords = ["signal", "SIGINT", "SIGTERM", "SIGQUIT"]
8+
description = "Easy unix signals handler for Rust projects"
9+
homepage = "https://github.com/swizard0/rust-simple-signal"
10+
repository = "https://github.com/swizard0/rust-simple-signal.git"
11+
12+
[lib]
13+
name = "simple_signal"
1114

1215
[dependencies]
13-
libc = "0.1"
14-
winapi = "0.2"
15-
kernel32-sys = "0.1"
16+
libc = "*"
1617

1718
[dependencies.lazy_static]
1819
version = "0.1"

README.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
# CtrlC
2-
[![Build Status](https://travis-ci.org/Detegr/rust-ctrlc.svg?branch=master)](https://travis-ci.org/Detegr/rust-ctrlc)
3-
4-
A simple easy to use wrapper around Ctrl-C signal.
1+
# simple-signale
2+
A simple easy to use wrapper around unix signals.
53

64
## Example usage
75
```rust
8-
extern crate ctrlc;
9-
use ctrlc::CtrlC;
6+
extern crate simple_signal;
7+
use simple_signal::{Signals, Signal};
108
use std::sync::atomic::{AtomicBool, Ordering};
119
use std::sync::Arc;
1210

1311
fn main() {
1412
let running = Arc::new(AtomicBool::new(true));
1513
let r = running.clone();
16-
CtrlC::set_handler(move || {
14+
Signals::set_handler(&[Signal::Int, Signal::Term], move |_signals| {
1715
r.store(false, Ordering::SeqCst);
1816
});
19-
println!("Waiting for Ctrl-C...");
17+
println!("Waiting for a signal...");
2018
while running.load(Ordering::SeqCst) {}
2119
println!("Got it! Exiting...");
2220
}

examples/readme_example.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
extern crate ctrlc;
2-
use ctrlc::CtrlC;
1+
extern crate simple_signal;
2+
use simple_signal::{Signals, Signal};
33
use std::sync::atomic::{AtomicBool, Ordering};
44
use std::sync::Arc;
55

66
fn main() {
77
let running = Arc::new(AtomicBool::new(true));
88
let r = running.clone();
9-
CtrlC::set_handler(move || {
9+
Signals::set_handler(&[Signal::Int, Signal::Term], move |_signals| {
1010
r.store(false, Ordering::SeqCst);
1111
});
12-
println!("Waiting for Ctrl-C...");
12+
println!("Waiting for a signal...");
1313
while running.load(Ordering::SeqCst) {}
1414
println!("Got it! Exiting...");
1515
}

examples/simple.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
// 100% of CPU. This is because cargo seems to kill the process even
44
// though you have set up Ctrl-C handler of your own.
55

6-
extern crate ctrlc;
7-
use ctrlc::CtrlC;
6+
extern crate simple_signal;
7+
use simple_signal::{Signals, Signal};
88
fn main() {
9-
CtrlC::set_handler(|| println!("Hello world!"));
9+
Signals::set_handler(&[Signal::Int, Signal::Term], |signals| println!("Caught: {:?}", signals));
1010
loop {}
1111
}

src/lib.rs

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! A simple easy to use wrapper around Ctrl-C signal.
1+
//! A simple easy to use wrapper around unix signals.
22
33
#![cfg_attr(feature="nightly", feature(static_condvar))]
44
#![cfg_attr(feature="nightly", feature(static_mutex))]
@@ -9,84 +9,131 @@ extern crate lazy_static;
99

1010
use std::sync::atomic::Ordering;
1111

12+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
13+
pub enum Signal {
14+
Hup,
15+
Int,
16+
Quit,
17+
Ill,
18+
Abrt,
19+
Fpe,
20+
Kill,
21+
Segv,
22+
Pipe,
23+
Alrm,
24+
Term,
25+
}
26+
1227
#[cfg(feature="nightly")]
1328
mod features {
14-
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
29+
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
1530
use std::sync::{StaticCondvar, CONDVAR_INIT, StaticMutex, MUTEX_INIT};
1631
pub static CVAR: StaticCondvar = CONDVAR_INIT;
1732
pub static MUTEX: StaticMutex = MUTEX_INIT;
18-
pub static DONE: AtomicBool = ATOMIC_BOOL_INIT;
33+
pub static MASK: AtomicUsize = ATOMIC_USIZE_INIT;
1934
}
2035
#[cfg(not(feature="nightly"))]
2136
mod features {
22-
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
37+
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
2338
use std::sync::{Condvar, Mutex};
2439
lazy_static! {
2540
pub static ref CVAR: Condvar = Condvar::new();
2641
pub static ref MUTEX: Mutex<bool> = Mutex::new(false);
2742
}
28-
pub static DONE: AtomicBool = ATOMIC_BOOL_INIT;
43+
pub static MASK: AtomicUsize = ATOMIC_USIZE_INIT;
2944
}
3045
use self::features::*;
3146

3247
#[cfg(unix)]
3348
mod platform {
3449
extern crate libc;
35-
use self::libc::c_int;
36-
use self::libc::types::os::common::posix01::sighandler_t;
37-
use self::libc::consts::os::posix88::SIGINT;
38-
use self::libc::funcs::posix01::signal::signal;
50+
use self::libc::{c_int, signal, sighandler_t};
51+
use self::libc::{SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM};
3952
use std::sync::atomic::Ordering;
53+
use super::Signal;
4054

4155
#[repr(C)]
42-
pub fn handler(_: c_int) {
43-
super::features::DONE.store(true, Ordering::Relaxed);
44-
super::features::CVAR.notify_all();
45-
}
46-
#[inline]
47-
pub unsafe fn set_os_handler(handler: fn(c_int)) {
48-
signal(SIGINT, ::std::mem::transmute::<_, sighandler_t>(handler));
49-
}
50-
}
51-
#[cfg(windows)]
52-
mod platform {
53-
extern crate winapi;
54-
extern crate kernel32;
55-
use self::kernel32::SetConsoleCtrlHandler;
56-
use self::winapi::{BOOL, DWORD, TRUE};
57-
use std::sync::atomic::Ordering;
56+
pub fn handler(sig: c_int) {
57+
let mask = match sig {
58+
SIGHUP => 1,
59+
SIGINT => 2,
60+
SIGQUIT => 4,
61+
SIGILL => 8,
62+
SIGABRT => 16,
63+
SIGFPE => 32,
64+
SIGKILL => 64,
65+
SIGSEGV => 128,
66+
SIGPIPE => 256,
67+
SIGALRM => 512,
68+
SIGTERM => 1024,
69+
_ => return,
70+
};
5871

59-
pub unsafe extern "system" fn handler(_: DWORD) -> BOOL {
60-
super::features::DONE.store(true, Ordering::Relaxed);
72+
loop {
73+
let prev_mask = super::features::MASK.load(Ordering::Relaxed);
74+
let new_mask = prev_mask | mask;
75+
if super::features::MASK.compare_and_swap(prev_mask, new_mask, Ordering::Relaxed) == new_mask {
76+
break
77+
}
78+
}
6179
super::features::CVAR.notify_all();
62-
TRUE
6380
}
6481
#[inline]
65-
pub unsafe fn set_os_handler(handler: unsafe extern "system" fn(DWORD) -> BOOL) {
66-
SetConsoleCtrlHandler(Some(handler), TRUE);
82+
pub unsafe fn set_os_handler(sig: Signal) {
83+
let os_sig = match sig {
84+
Signal::Hup => SIGHUP,
85+
Signal::Int => SIGINT,
86+
Signal::Quit => SIGQUIT,
87+
Signal::Ill => SIGILL,
88+
Signal::Abrt => SIGABRT,
89+
Signal::Fpe => SIGFPE,
90+
Signal::Kill => SIGKILL,
91+
Signal::Segv => SIGSEGV,
92+
Signal::Pipe => SIGPIPE,
93+
Signal::Alrm => SIGALRM,
94+
Signal::Term => SIGTERM,
95+
};
96+
97+
signal(os_sig, ::std::mem::transmute::<_, sighandler_t>(handler));
6798
}
6899
}
100+
69101
use self::platform::*;
70102

71-
pub struct CtrlC;
72-
impl CtrlC {
73-
/// Sets up the signal handler for Ctrl-C
103+
pub struct Signals;
104+
impl Signals {
105+
/// Sets up some signals handler
74106
/// # Example
75107
/// ```
76-
/// use ctrlc::CtrlC;
77-
/// CtrlC::set_handler(|| println!("Hello world!"));
108+
/// use simple_signal::{Signals, Signal};
109+
/// Signals::set_handler(&[Signal::Int, Signal::Term], |signals| println!("Caught: {:?}", signals));
78110
/// ```
79-
pub fn set_handler<F: Fn() -> () + 'static + Send>(user_handler: F) -> () {
80-
unsafe {
81-
set_os_handler(handler);
111+
pub fn set_handler<F>(signals: &[Signal], user_handler: F) where F: Fn(&[Signal]) + 'static + Send {
112+
for &signal in signals.iter() {
113+
unsafe { set_os_handler(signal) }
82114
}
83115
::std::thread::spawn(move || {
116+
let mut signals = Vec::new();
84117
loop {
85-
if !DONE.load(Ordering::Relaxed) {
118+
let mask = MASK.load(Ordering::Relaxed);
119+
if mask == 0 {
86120
let _ = CVAR.wait(MUTEX.lock().unwrap());
87-
DONE.store(false, Ordering::Relaxed);
121+
continue
88122
}
89-
user_handler();
123+
signals.clear();
124+
if mask & 1 != 0 { signals.push(Signal::Hup) }
125+
if mask & 2 != 0 { signals.push(Signal::Int) }
126+
if mask & 4 != 0 { signals.push(Signal::Quit) }
127+
if mask & 8 != 0 { signals.push(Signal::Ill) }
128+
if mask & 16 != 0 { signals.push(Signal::Abrt) }
129+
if mask & 32 != 0 { signals.push(Signal::Fpe) }
130+
if mask & 64 != 0 { signals.push(Signal::Kill) }
131+
if mask & 128 != 0 { signals.push(Signal::Segv) }
132+
if mask & 256 != 0 { signals.push(Signal::Pipe) }
133+
if mask & 512 != 0 { signals.push(Signal::Alrm) }
134+
if mask & 1024 != 0 { signals.push(Signal::Term) }
135+
MASK.store(0, Ordering::Relaxed);
136+
user_handler(&signals);
90137
}
91138
});
92139
}

0 commit comments

Comments
 (0)