Skip to content

Commit 4bc85e4

Browse files
authored
Add sigsuspend (#2279)
* add sigsuspend * add cfg for sigsuspend * add fuchsia to target_os * Ok is unreachable > Since sigsuspend() suspends thread execution indefinitely, there is no > successful completion return value. If a return occurs, -1 shall be > returned and errno set to indicate the error. https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html * add test_sigsuspend * clippy * fix bug of test * add changelog * update doc * remove unnnessesary sleep * Revert "remove unnnessesary sleep" This reverts commit c174bd2. * move to SigSet::suspend * reorder doc * update test * update test * change memory order * Revert "change memory order" This reverts commit f63e656. * rename added.md * add unreachable reason * use alias * remove nto * Update libc I updated libc to use below commit which add sigsuspend to more targets. rust-lang/libc@11f7c7b * Add target bsd, solarish and haiku to sigsuspend
1 parent 833828e commit 4bc85e4

File tree

4 files changed

+82
-1
lines changed

4 files changed

+82
-1
lines changed

2279.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added a new API sigsuspend.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ targets = [
2828
]
2929

3030
[dependencies]
31-
libc = { git = "https://github.com/rust-lang/libc", rev = "cb18b837963c37a8d21732f3ca2c2096f04e6830", features = ["extra_traits"] }
31+
libc = { git = "https://github.com/rust-lang/libc", rev = "2f93bfb7678e18a9fc5373dec49384bd23f601c3", features = ["extra_traits"] }
3232
bitflags = "2.3.1"
3333
cfg-if = "1.0"
3434
pin-utils = { version = "0.1.0", optional = true }

src/sys/signal.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,35 @@ impl SigSet {
582582
})
583583
}
584584

585+
/// Wait for a signal
586+
///
587+
/// # Return value
588+
/// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`.
589+
/// If `sigsuspend(2)` set other error, this function returns `Err`.
590+
///
591+
/// For more information see the
592+
/// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html).
593+
#[cfg(any(
594+
bsd,
595+
linux_android,
596+
solarish,
597+
target_os = "haiku",
598+
target_os = "hurd",
599+
target_os = "aix",
600+
target_os = "fushsia"
601+
))]
602+
#[doc(alias("sigsuspend"))]
603+
pub fn suspend(&self) -> Result<()> {
604+
let res = unsafe {
605+
libc::sigsuspend(&self.sigset as *const libc::sigset_t)
606+
};
607+
match Errno::result(res).map(drop) {
608+
Err(Errno::EINTR) => Ok(()),
609+
Err(e) => Err(e),
610+
Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
611+
}
612+
}
613+
585614
/// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the
586615
/// `libc::sigset_t` is already initialized.
587616
///

test/sys/test_signal.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,57 @@ fn test_sigwait() {
343343
.unwrap();
344344
}
345345

346+
#[cfg(any(
347+
bsd,
348+
linux_android,
349+
solarish,
350+
target_os = "haiku",
351+
target_os = "hurd",
352+
target_os = "aix",
353+
target_os = "fushsia"
354+
))]
355+
#[test]
356+
fn test_sigsuspend() {
357+
// This test change signal handler
358+
let _m = crate::SIGNAL_MTX.lock();
359+
static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false);
360+
extern "C" fn test_sigsuspend_handler(_: libc::c_int) {
361+
assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst));
362+
}
363+
thread::spawn(|| {
364+
const SIGNAL: Signal = Signal::SIGUSR1;
365+
366+
// Add signal mask to this thread
367+
let mut signal_set = SigSet::empty();
368+
signal_set.add(SIGNAL);
369+
signal_set.thread_block().unwrap();
370+
371+
// Set signal handler and save old one.
372+
let act = SigAction::new(
373+
SigHandler::Handler(test_sigsuspend_handler),
374+
SaFlags::empty(),
375+
SigSet::empty(),
376+
);
377+
let old_act = unsafe { sigaction(SIGNAL, &act) }
378+
.expect("expect to be able to set new action and get old action");
379+
380+
raise(SIGNAL).expect("expect be able to send signal");
381+
// Now `SIGNAL` was sended but it is blocked.
382+
let mut not_wait_set = SigSet::all();
383+
not_wait_set.remove(SIGNAL);
384+
// signal handler must run in SigSet::suspend()
385+
assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst));
386+
not_wait_set.suspend().unwrap();
387+
assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst));
388+
389+
// Restore the signal handler.
390+
unsafe { sigaction(SIGNAL, &old_act) }
391+
.expect("expect to be able to restore old action ");
392+
})
393+
.join()
394+
.unwrap();
395+
}
396+
346397
#[test]
347398
fn test_from_sigset_t_unchecked() {
348399
let src_set = SigSet::empty();

0 commit comments

Comments
 (0)