Skip to content

Commit 52fb8ae

Browse files
committed
Add function
1 parent 151e733 commit 52fb8ae

File tree

8 files changed

+90
-12
lines changed

8 files changed

+90
-12
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ fn main() -> std::io::Result<()> {
4242
}
4343
```
4444

45+
Need to detect Ctrl-C more than once? See [`examples/multi_ctrlc.rs`](https://github.com/malt03/ctrlc-tiny/blob/main/examples/multi_ctrlc.rs).
46+
4547
## 🔍 Why not use `ctrlc`?
4648

4749
[`ctrlc`](https://crates.io/crates/ctrlc) provides a flexible way to handle signals using closures and shared state.
@@ -55,6 +57,7 @@ No threads, no handlers, no extra logic.
5557

5658
- Internally uses a `volatile sig_atomic_t` flag — safe in POSIX signal handlers.
5759
- No heap, no threads — fully signal-safe by design.
60+
- The flag can be reset via `reset_ctrlc_received()`, but may race with the signal handler if SIGINT is received at the same time.
5861

5962
## 🛠️ Platform Support
6063

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fn main() -> Result<(), Error> {
3131
.header("c_src/sigint.h")
3232
.allowlist_function("init_sigint_handler")
3333
.allowlist_function("get_is_sigint_received")
34+
.allowlist_function("reset_is_sigint_received")
3435
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
3536
.generate()?;
3637

c_src/sigint.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ sig_atomic_t get_is_sigint_received()
2323
{
2424
return is_sigint_received;
2525
}
26+
27+
void reset_is_sigint_received()
28+
{
29+
is_sigint_received = 0;
30+
}

c_src/sigint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55

66
int init_sigint_handler(void);
77
sig_atomic_t get_is_sigint_received(void);
8+
void reset_is_sigint_received(void);
89

910
#endif

examples/ctrlc_probe.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ use std::io::{stdout, Write};
22
use std::{thread, time::Duration};
33

44
fn main() -> std::io::Result<()> {
5+
ctrlc_tiny::init_ctrlc()?;
6+
57
println!("probe started");
68
stdout().flush()?;
79

8-
// Initialize the Ctrl-C handler
9-
ctrlc_tiny::init_ctrlc()?;
10-
11-
// Poll until SIGINT is received
10+
let mut count = 0;
1211
loop {
1312
if ctrlc_tiny::is_ctrlc_received() {
14-
println!("Ctrl-C detected");
13+
count += 1;
14+
println!("Ctrl-C detected: {}", count);
1515
stdout().flush()?;
16-
break;
16+
if count == 2 {
17+
break;
18+
}
19+
ctrlc_tiny::reset_ctrlc_received();
1720
}
1821
thread::sleep(Duration::from_millis(50));
1922
}

examples/multi_ctrlc.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Example: detecting multiple Ctrl-C presses
2+
//!
3+
//! This example demonstrates how to detect Ctrl-C multiple times
4+
//! by resetting the internal flag after each detection.
5+
6+
fn main() -> std::io::Result<()> {
7+
ctrlc_tiny::init_ctrlc()?;
8+
9+
let mut count = 0;
10+
loop {
11+
if ctrlc_tiny::is_ctrlc_received() {
12+
ctrlc_tiny::reset_ctrlc_received();
13+
14+
count += 1;
15+
println!("SIGINT received {} time(s)", count);
16+
17+
if count == 10 {
18+
break;
19+
}
20+
}
21+
22+
std::thread::sleep(std::time::Duration::from_millis(100));
23+
}
24+
25+
Ok(())
26+
}

src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,39 @@ pub fn is_ctrlc_received() -> bool {
6868
unsafe { bindings::get_is_sigint_received() != 0 }
6969
}
7070

71+
/// Resets the internal Ctrl-C received flag to `false`.
72+
///
73+
/// This can be useful if you want to detect multiple Ctrl-C presses
74+
/// independently (e.g. "exit on second Ctrl-C").
75+
///
76+
/// # Safety
77+
///
78+
/// Internally, this clears a `sig_atomic_t` flag that may be concurrently
79+
/// modified by the signal handler. This is safe but may cause a signal
80+
/// received during the reset to be missed.
81+
///
82+
/// # Examples
83+
///
84+
/// ```rust,no_run
85+
/// ctrlc_tiny::init_ctrlc()?;
86+
/// let mut count = 0;
87+
/// loop {
88+
/// if ctrlc_tiny::is_ctrlc_received() {
89+
/// ctrlc_tiny::reset_ctrlc_received();
90+
/// count += 1;
91+
/// if count == 2 {
92+
/// break;
93+
/// }
94+
/// }
95+
/// }
96+
/// # Ok::<_, std::io::Error>(())
97+
/// ```
98+
pub fn reset_ctrlc_received() {
99+
unsafe {
100+
bindings::reset_is_sigint_received();
101+
}
102+
}
103+
71104
#[cfg(test)]
72105
mod tests {
73106
use super::*;
@@ -81,5 +114,7 @@ mod tests {
81114
#[test]
82115
fn is_ctrlc_received_initially_false() {
83116
assert!(!is_ctrlc_received());
117+
reset_ctrlc_received();
118+
assert!(!is_ctrlc_received());
84119
}
85120
}

tests/e2e.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ fn e2e_test() {
1111
let child_id = child.id();
1212
let stdout = child.stdout.expect("failed to capture stdout");
1313
let mut reader = std::io::BufReader::new(stdout);
14-
let mut last_line: String = String::new();
14+
let mut lines = Vec::new();
15+
let mut started = false;
1516

1617
loop {
1718
let mut line = String::new();
1819
if reader.read_line(&mut line).expect("failed to read line") == 0 {
1920
break;
2021
}
2122
let line = line.trim();
22-
last_line = line.to_string();
23-
if line == "probe started" {
24-
thread::sleep(Duration::from_millis(50));
23+
if started {
24+
lines.push(line.to_string());
25+
} else if line == "probe started" {
26+
started = true;
27+
}
28+
if started {
2529
unsafe {
2630
libc::kill(child_id as i32, libc::SIGINT);
2731
}
@@ -30,8 +34,8 @@ fn e2e_test() {
3034
}
3135

3236
assert_eq!(
33-
last_line.trim(),
34-
"Ctrl-C detected",
37+
lines,
38+
vec!["Ctrl-C detected: 1", "Ctrl-C detected: 2",],
3539
"Expected Ctrl-C detection in child output"
3640
);
3741
}

0 commit comments

Comments
 (0)