Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
25
vendor/signal-hook/tests/default.rs
vendored
Normal file
25
vendor/signal-hook/tests/default.rs
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//! Check the hack of SIG_DFL for windows.
|
||||
//!
|
||||
//! Libc doesn't export SIG_DFL on windows. It seems to be 0 on all platforms, though, but just to
|
||||
//! make sure, we observe it is so. We try to read the previous signal on startup and it must be
|
||||
//! the default.
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use libc::{sighandler_t, signal, SIGTERM};
|
||||
|
||||
const SIG_DFL: sighandler_t = 0;
|
||||
|
||||
#[test]
|
||||
fn sig_dfl() {
|
||||
unsafe {
|
||||
let prev = signal(SIGTERM, SIG_DFL);
|
||||
assert_eq!(SIG_DFL, prev);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[test]
|
||||
fn sig_dfl_static() {
|
||||
assert_eq!(::libc::SIG_DFL, SIG_DFL);
|
||||
}
|
||||
260
vendor/signal-hook/tests/iterator.rs
vendored
Normal file
260
vendor/signal-hook/tests/iterator.rs
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
#![cfg(not(windows))]
|
||||
|
||||
extern crate signal_hook;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{self, RecvTimeoutError};
|
||||
use std::sync::Arc;
|
||||
use std::thread::{self, JoinHandle};
|
||||
use std::time::Duration;
|
||||
|
||||
use signal_hook::consts::{SIGUSR1, SIGUSR2};
|
||||
use signal_hook::iterator::{Handle, Signals};
|
||||
use signal_hook::low_level::raise;
|
||||
|
||||
use serial_test::serial;
|
||||
|
||||
fn send_sigusr1() {
|
||||
raise(SIGUSR1).unwrap();
|
||||
}
|
||||
|
||||
fn send_sigusr2() {
|
||||
raise(SIGUSR2).unwrap();
|
||||
}
|
||||
|
||||
fn setup_without_any_signals() -> (Signals, Handle) {
|
||||
let signals = Signals::new(&[]).unwrap();
|
||||
let controller = signals.handle();
|
||||
(signals, controller)
|
||||
}
|
||||
|
||||
fn setup_for_sigusr2() -> (Signals, Handle) {
|
||||
let signals = Signals::new(&[SIGUSR2]).unwrap();
|
||||
let controller = signals.handle();
|
||||
(signals, controller)
|
||||
}
|
||||
|
||||
macro_rules! assert_signals {
|
||||
($actual:expr, $($expected:expr),+ $(,)?) => {
|
||||
let actual = $actual.collect::<HashSet<libc::c_int>>();
|
||||
let expected = vec!($($expected),+).into_iter().collect::<HashSet<libc::c_int>>();
|
||||
assert_eq!(actual, expected);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_no_signals {
|
||||
($signals:expr) => {
|
||||
assert_eq!($signals.next(), None);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn forever_terminates_when_closed() {
|
||||
let (mut signals, controller) = setup_for_sigusr2();
|
||||
|
||||
// Detect early terminations.
|
||||
let stopped = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let stopped_bg = Arc::clone(&stopped);
|
||||
let thread = thread::spawn(move || {
|
||||
// Eat all the signals there are (might come from a concurrent test, in theory).
|
||||
// Would wait forever, but it should be terminated by the close below.
|
||||
for _sig in &mut signals {}
|
||||
|
||||
stopped_bg.store(true, Ordering::SeqCst);
|
||||
});
|
||||
|
||||
// Wait a bit to see if the thread terminates by itself.
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
assert!(!stopped.load(Ordering::SeqCst));
|
||||
|
||||
controller.close();
|
||||
|
||||
thread.join().unwrap();
|
||||
}
|
||||
|
||||
// A reproducer for #16: if we had the mio-support enabled (which is enabled also by the
|
||||
// tokio-support feature), blocking no longer works. The .wait() would return immediately (an empty
|
||||
// iterator, possibly), .forever() would do a busy loop.
|
||||
// flag)
|
||||
#[test]
|
||||
#[serial]
|
||||
fn signals_block_wait() {
|
||||
let mut signals = Signals::new(&[SIGUSR2]).unwrap();
|
||||
let (s, r) = mpsc::channel();
|
||||
let finish = Arc::new(AtomicBool::new(false));
|
||||
let thread_id = thread::spawn({
|
||||
let finish = Arc::clone(&finish);
|
||||
move || {
|
||||
// Technically, it may spuriously return early. But it shouldn't be doing it too much,
|
||||
// so we just try to wait multiple times ‒ if they *all* return right away, it is
|
||||
// broken.
|
||||
for _ in 0..10 {
|
||||
for _ in signals.wait() {
|
||||
if finish.load(Ordering::SeqCst) {
|
||||
// Asked to terminate at the end of the thread. Do so (but without
|
||||
// signalling the receipt).
|
||||
return;
|
||||
} else {
|
||||
panic!("Someone really did send us SIGUSR2, which breaks the test");
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = s.send(());
|
||||
}
|
||||
});
|
||||
|
||||
// A RAII guard to make sure we shut down the thread even if the test fails.
|
||||
struct ThreadGuard {
|
||||
thread: Option<JoinHandle<()>>,
|
||||
finish: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl ThreadGuard {
|
||||
fn shutdown(&mut self) {
|
||||
// Tell it to shut down
|
||||
self.finish.store(true, Ordering::SeqCst);
|
||||
// Wake it up
|
||||
send_sigusr2();
|
||||
// Wait for it to actually terminate.
|
||||
if let Some(thread) = self.thread.take() {
|
||||
thread.join().unwrap(); // Propagate panics
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ThreadGuard {
|
||||
fn drop(&mut self) {
|
||||
self.shutdown(); // OK if done twice, won't have the thread any more.
|
||||
}
|
||||
}
|
||||
|
||||
let mut bg_thread = ThreadGuard {
|
||||
thread: Some(thread_id),
|
||||
finish,
|
||||
};
|
||||
|
||||
let err = r
|
||||
.recv_timeout(Duration::from_millis(100))
|
||||
.expect_err("Wait didn't wait properly");
|
||||
assert_eq!(err, RecvTimeoutError::Timeout);
|
||||
|
||||
bg_thread.shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pending_doesnt_block() {
|
||||
let (mut signals, _) = setup_for_sigusr2();
|
||||
|
||||
let mut recieved_signals = signals.pending();
|
||||
|
||||
assert_no_signals!(recieved_signals);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn wait_returns_recieved_signals() {
|
||||
let (mut signals, _) = setup_for_sigusr2();
|
||||
send_sigusr2();
|
||||
|
||||
let recieved_signals = signals.wait();
|
||||
|
||||
assert_signals!(recieved_signals, SIGUSR2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn forever_returns_recieved_signals() {
|
||||
let (mut signals, _) = setup_for_sigusr2();
|
||||
send_sigusr2();
|
||||
|
||||
let signal = signals.forever().take(1);
|
||||
|
||||
assert_signals!(signal, SIGUSR2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn wait_doesnt_block_when_closed() {
|
||||
let (mut signals, controller) = setup_for_sigusr2();
|
||||
controller.close();
|
||||
|
||||
let mut recieved_signals = signals.wait();
|
||||
|
||||
assert_no_signals!(recieved_signals);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn wait_unblocks_when_closed() {
|
||||
let (mut signals, controller) = setup_without_any_signals();
|
||||
|
||||
let thread = thread::spawn(move || {
|
||||
signals.wait();
|
||||
});
|
||||
|
||||
controller.close();
|
||||
|
||||
thread.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn forever_doesnt_block_when_closed() {
|
||||
let (mut signals, controller) = setup_for_sigusr2();
|
||||
controller.close();
|
||||
|
||||
let mut signal = signals.forever();
|
||||
|
||||
assert_no_signals!(signal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn add_signal_after_creation() {
|
||||
let (mut signals, _) = setup_without_any_signals();
|
||||
signals.add_signal(SIGUSR1).unwrap();
|
||||
|
||||
send_sigusr1();
|
||||
|
||||
assert_signals!(signals.pending(), SIGUSR1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn delayed_signal_consumed() {
|
||||
let (mut signals, _) = setup_for_sigusr2();
|
||||
signals.add_signal(SIGUSR1).unwrap();
|
||||
|
||||
send_sigusr1();
|
||||
let mut recieved_signals = signals.wait();
|
||||
send_sigusr2();
|
||||
|
||||
assert_signals!(recieved_signals, SIGUSR1, SIGUSR2);
|
||||
|
||||
// The pipe still contains the byte from the second
|
||||
// signal and so wait won't block but won't return
|
||||
// a signal.
|
||||
recieved_signals = signals.wait();
|
||||
assert_no_signals!(recieved_signals);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn is_closed_initially_returns_false() {
|
||||
let (_, controller) = setup_for_sigusr2();
|
||||
|
||||
assert!(!controller.is_closed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn is_closed_returns_true_when_closed() {
|
||||
let (_, controller) = setup_for_sigusr2();
|
||||
controller.close();
|
||||
|
||||
assert!(controller.is_closed());
|
||||
}
|
||||
81
vendor/signal-hook/tests/shutdown.rs
vendored
Normal file
81
vendor/signal-hook/tests/shutdown.rs
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//! Tests for the shutdown.
|
||||
//!
|
||||
//! The tests work like this:
|
||||
//!
|
||||
//! * The register an alarm, to fail if anything takes too long (which is very much possible here).
|
||||
//! * A fork is done, with the child registering a signal with a NOP and cleanup operation (one or
|
||||
//! the other).
|
||||
//! * The child puts some kind of infinite loop or sleep inside itself, so it never actually
|
||||
//! terminates on the first, but would terminate after the signal.
|
||||
|
||||
#![cfg(not(windows))] // Forks don't work on Windows, but windows has the same implementation.
|
||||
|
||||
use std::io::Error;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use signal_hook::consts::signal::*;
|
||||
use signal_hook::flag;
|
||||
use signal_hook::low_level;
|
||||
|
||||
fn do_test<C: FnOnce()>(child: C) {
|
||||
unsafe {
|
||||
libc::alarm(10); // Time out the test after 10 seconds and get it killed.
|
||||
match libc::fork() {
|
||||
-1 => panic!("Fork failed: {}", Error::last_os_error()),
|
||||
0 => {
|
||||
child();
|
||||
loop {
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
pid => {
|
||||
// Give the child some time to register signals and stuff
|
||||
// We could actually signal that the child is ready by it eg. closing STDOUT, but
|
||||
// this is just a test so we don't really bother.
|
||||
thread::sleep(Duration::from_millis(250));
|
||||
libc::kill(pid, libc::SIGTERM);
|
||||
// Wait a small bit to make sure the signal got delivered.
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
// The child is still running, because the first signal got "handled" by being
|
||||
// ignored.
|
||||
let terminated = libc::waitpid(pid, ptr::null_mut(), libc::WNOHANG);
|
||||
assert_eq!(0, terminated, "Process {} terminated prematurely", pid);
|
||||
// But it terminates on the second attempt (we do block on wait here).
|
||||
libc::kill(pid, libc::SIGTERM);
|
||||
let terminated = libc::waitpid(pid, ptr::null_mut(), 0);
|
||||
assert_eq!(pid, terminated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use automatic cleanup inside the signal handler to get rid of old signals, the aggressive way.
|
||||
#[test]
|
||||
fn cleanup_inside_signal() {
|
||||
fn hook() {
|
||||
// Make sure we have some signal handler, not the default.
|
||||
unsafe { low_level::register(SIGTERM, || ()).unwrap() };
|
||||
let shutdown_cond = Arc::new(AtomicBool::new(false));
|
||||
// „disarmed“ shutdown
|
||||
flag::register_conditional_shutdown(SIGTERM, 0, Arc::clone(&shutdown_cond)).unwrap();
|
||||
// But arm at the first SIGTERM
|
||||
flag::register(SIGTERM, shutdown_cond).unwrap();
|
||||
}
|
||||
do_test(hook);
|
||||
}
|
||||
|
||||
/// Manually remove the signal handler just after receiving the signal but before going into an
|
||||
/// infinite loop.
|
||||
#[test]
|
||||
fn cleanup_after_signal() {
|
||||
fn hook() {
|
||||
let mut signals = signal_hook::iterator::Signals::new(&[libc::SIGTERM]).unwrap();
|
||||
assert_eq!(Some(SIGTERM), signals.into_iter().next());
|
||||
flag::register_conditional_shutdown(SIGTERM, 0, Arc::new(AtomicBool::new(true))).unwrap();
|
||||
}
|
||||
do_test(hook);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue