Skip to content

Commit

Permalink
Add sigsuspend (nix-rust#2279)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Toru3 authored Jan 7, 2024
1 parent 833828e commit 4bc85e4
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 1 deletion.
1 change: 1 addition & 0 deletions 2279.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a new API sigsuspend.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ targets = [
]

[dependencies]
libc = { git = "https://github.com/rust-lang/libc", rev = "cb18b837963c37a8d21732f3ca2c2096f04e6830", features = ["extra_traits"] }
libc = { git = "https://github.com/rust-lang/libc", rev = "2f93bfb7678e18a9fc5373dec49384bd23f601c3", features = ["extra_traits"] }
bitflags = "2.3.1"
cfg-if = "1.0"
pin-utils = { version = "0.1.0", optional = true }
Expand Down
29 changes: 29 additions & 0 deletions src/sys/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,35 @@ impl SigSet {
})
}

/// Wait for a signal
///
/// # Return value
/// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`.
/// If `sigsuspend(2)` set other error, this function returns `Err`.
///
/// For more information see the
/// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html).
#[cfg(any(
bsd,
linux_android,
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "aix",
target_os = "fushsia"
))]
#[doc(alias("sigsuspend"))]
pub fn suspend(&self) -> Result<()> {
let res = unsafe {
libc::sigsuspend(&self.sigset as *const libc::sigset_t)
};
match Errno::result(res).map(drop) {
Err(Errno::EINTR) => Ok(()),
Err(e) => Err(e),
Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
}
}

/// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the
/// `libc::sigset_t` is already initialized.
///
Expand Down
51 changes: 51 additions & 0 deletions test/sys/test_signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,57 @@ fn test_sigwait() {
.unwrap();
}

#[cfg(any(
bsd,
linux_android,
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "aix",
target_os = "fushsia"
))]
#[test]
fn test_sigsuspend() {
// This test change signal handler
let _m = crate::SIGNAL_MTX.lock();
static SIGNAL_RECIEVED: AtomicBool = AtomicBool::new(false);
extern "C" fn test_sigsuspend_handler(_: libc::c_int) {
assert!(!SIGNAL_RECIEVED.swap(true, Ordering::SeqCst));
}
thread::spawn(|| {
const SIGNAL: Signal = Signal::SIGUSR1;

// Add signal mask to this thread
let mut signal_set = SigSet::empty();
signal_set.add(SIGNAL);
signal_set.thread_block().unwrap();

// Set signal handler and save old one.
let act = SigAction::new(
SigHandler::Handler(test_sigsuspend_handler),
SaFlags::empty(),
SigSet::empty(),
);
let old_act = unsafe { sigaction(SIGNAL, &act) }
.expect("expect to be able to set new action and get old action");

raise(SIGNAL).expect("expect be able to send signal");
// Now `SIGNAL` was sended but it is blocked.
let mut not_wait_set = SigSet::all();
not_wait_set.remove(SIGNAL);
// signal handler must run in SigSet::suspend()
assert!(!SIGNAL_RECIEVED.load(Ordering::SeqCst));
not_wait_set.suspend().unwrap();
assert!(SIGNAL_RECIEVED.load(Ordering::SeqCst));

// Restore the signal handler.
unsafe { sigaction(SIGNAL, &old_act) }
.expect("expect to be able to restore old action ");
})
.join()
.unwrap();
}

#[test]
fn test_from_sigset_t_unchecked() {
let src_set = SigSet::empty();
Expand Down

0 comments on commit 4bc85e4

Please sign in to comment.