Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add return handle #110

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.vscode/
.VSCodeCounter/
target
Cargo.lock
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# CtrlC

[![Version](https://img.shields.io/crates/v/ctrlc.svg?style=flat)](https://crates.io/crates/ctrlc)
[![Documentation](https://img.shields.io/badge/docs-release-brightgreen.svg?style=flat)](https://docs.rs/ctrlc)
[![Download](https://img.shields.io/crates/d/ctrlc.svg)](https://crates.io/crates/ctrlc)
[![License](https://img.shields.io/crates/l/ctrlc.svg?style=flat)](https://github.com/Detegr/rust-ctrlc/blob/master/LICENSE-MIT)
[![Build Status](https://travis-ci.org/Detegr/rust-ctrlc.svg?branch=master)](https://travis-ci.org/Detegr/rust-ctrlc)
[![Build status](https://ci.appveyor.com/api/projects/status/kwg1uu2w2aqn9ta9/branch/master?svg=true)](https://ci.appveyor.com/project/Detegr/rust-ctrlc/branch/master)

Expand All @@ -24,12 +29,13 @@ use ctrlc;
fn main() {
let (tx, rx) = channel();

ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel."))
let handle = ctrlc::set_handler(move || {tx.send(()).expect("Could not send signal on channel."); true})
.expect("Error setting Ctrl-C handler");

println!("Waiting for Ctrl-C...");
rx.recv().expect("Could not receive from channel.");
println!("Got it! Exiting...");
handle.join().unwarp();
}
```

Expand Down
7 changes: 4 additions & 3 deletions examples/issue_46_example.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
Expand All @@ -7,12 +6,13 @@ use std::time::Duration;
fn main() {
let running = Arc::new(AtomicUsize::new(0));
let r = running.clone();
ctrlc::set_handler(move || {
let handle = ctrlc::set_handler(move || {
let prev = r.fetch_add(1, Ordering::SeqCst);
if prev == 0 {
println!("Exiting...");
false
} else {
process::exit(0);
true
}
})
.expect("Error setting Ctrl-C handler");
Expand All @@ -23,4 +23,5 @@ fn main() {
break;
}
}
handle.join().unwrap();
}
8 changes: 6 additions & 2 deletions examples/readme_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ use std::sync::mpsc::channel;
fn main() {
let (tx, rx) = channel();

ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel."))
.expect("Error setting Ctrl-C handler");
let handle = ctrlc::set_handler(move || {
tx.send(()).expect("Could not send signal on channel.");
true
})
.expect("Error setting Ctrl-C handler");

println!("Waiting for Ctrl-C...");
rx.recv().expect("Could not receive from channel.");
println!("Got it! Exiting...");
handle.join().unwrap();
}
36 changes: 20 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
//! let running = Arc::new(AtomicBool::new(true));
//! let r = running.clone();
//!
//! ctrlc::set_handler(move || {
//! let handle = ctrlc::set_handler(move || {
//! r.store(false, Ordering::SeqCst);
//! true
//! }).expect("Error setting Ctrl-C handler");
//!
//! println!("Waiting for Ctrl-C...");
//! while running.load(Ordering::SeqCst) {}
//! println!("Got it! Exiting...");
//! handle.join().unwrap();
//! }
//! ```
//!
Expand All @@ -57,7 +59,7 @@ pub use signal::*;
pub use error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use std::thread;
use std::thread::{self, JoinHandle};

static INIT: AtomicBool = AtomicBool::new(false);
static INIT_LOCK: Mutex<()> = Mutex::new(());
Expand All @@ -69,7 +71,7 @@ static INIT_LOCK: Mutex<()> = Mutex::new(());
///
/// # Example
/// ```no_run
/// ctrlc::set_handler(|| println!("Hello world!")).expect("Error setting Ctrl-C handler");
/// ctrlc::set_handler(|| {println!("Hello world!"); true}).expect("Error setting Ctrl-C handler");
/// ```
///
/// # Warning
Expand All @@ -90,9 +92,9 @@ static INIT_LOCK: Mutex<()> = Mutex::new(());
///
/// # Panics
/// Any panic in the handler will not be caught and will cause the signal handler thread to stop.
pub fn set_handler<F>(user_handler: F) -> Result<(), Error>
pub fn set_handler<F>(user_handler: F) -> Result<JoinHandle<()>, Error>
where
F: FnMut() + 'static + Send,
F: FnMut() -> bool + 'static + Send,
{
init_and_set_handler(user_handler, true)
}
Expand All @@ -102,33 +104,33 @@ where
/// # Errors
/// Will return an error if another handler exists or if a system error occurred while setting the
/// handler.
pub fn try_set_handler<F>(user_handler: F) -> Result<(), Error>
pub fn try_set_handler<F>(user_handler: F) -> Result<JoinHandle<()>, Error>
where
F: FnMut() + 'static + Send,
F: FnMut() -> bool + 'static + Send,
{
init_and_set_handler(user_handler, false)
}

fn init_and_set_handler<F>(user_handler: F, overwrite: bool) -> Result<(), Error>
fn init_and_set_handler<F>(user_handler: F, overwrite: bool) -> Result<JoinHandle<()>, Error>
where
F: FnMut() + 'static + Send,
F: FnMut() -> bool + 'static + Send,
{
if !INIT.load(Ordering::Acquire) {
let _guard = INIT_LOCK.lock().unwrap();

if !INIT.load(Ordering::Relaxed) {
set_handler_inner(user_handler, overwrite)?;
let handle = set_handler_inner(user_handler, overwrite)?;
INIT.store(true, Ordering::Release);
return Ok(());
return Ok(handle);
}
}

Err(Error::MultipleHandlers)
}

fn set_handler_inner<F>(mut user_handler: F, overwrite: bool) -> Result<(), Error>
fn set_handler_inner<F>(mut user_handler: F, overwrite: bool) -> Result<JoinHandle<()>, Error>
where
F: FnMut() + 'static + Send,
F: FnMut() -> bool + 'static + Send,
{
unsafe {
match platform::init_os_handler(overwrite) {
Expand All @@ -139,15 +141,17 @@ where
}
}

thread::Builder::new()
let builder = thread::Builder::new()
.name("ctrl-c".into())
.spawn(move || loop {
unsafe {
platform::block_ctrl_c().expect("Critical system error while waiting for Ctrl-C");
}
user_handler();
if user_handler() {
break;
}
})
.expect("failed to spawn thread");

Ok(())
Ok(builder)
}
2 changes: 1 addition & 1 deletion tests/main/issue_97.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use test_signal_hook::run_signal_hook;

fn expect_multiple_handlers() {
#[cfg(not(windows))]
match ctrlc::try_set_handler(|| {}) {
match ctrlc::try_set_handler(|| true) {
Err(ctrlc::Error::MultipleHandlers) => {}
_ => panic!("Expected Error::MultipleHandlers"),
}
Expand Down
3 changes: 2 additions & 1 deletion tests/main/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn test_set_handler() {
let flag_handler = Arc::clone(&flag);
ctrlc::set_handler(move || {
flag_handler.store(true, Ordering::SeqCst);
true
})
.unwrap();

Expand All @@ -31,7 +32,7 @@ fn test_set_handler() {
std::thread::sleep(std::time::Duration::from_millis(100));
assert!(flag.load(Ordering::SeqCst));

match ctrlc::set_handler(|| {}) {
match ctrlc::set_handler(|| true) {
Err(ctrlc::Error::MultipleHandlers) => {}
ret => panic!("{:?}", ret),
}
Expand Down