-
Notifications
You must be signed in to change notification settings - Fork 265
/
test_signal.rs
127 lines (109 loc) · 4.02 KB
/
test_signal.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use sgx_libc::ocall::getpid;
use sgx_libc::{c_int, pid_t, siginfo_t, SIGILL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2};
use sgx_signal::signal::{
raise_signal, register, register_sigaction, unregister, unregister_signal,
};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
pub fn test_signal_forbidden() {
let ret = register(SIGILL, || ());
assert_eq!(ret.is_ok(), false);
}
pub fn test_signal_without_pid() {
let status = Arc::new(AtomicUsize::new(0));
let action = {
let status = Arc::clone(&status);
move || {
status.store(1, Ordering::Relaxed);
}
};
register(SIGUSR2, action).unwrap();
raise_signal(SIGUSR2);
for _ in 0..10 {
thread::sleep(Duration::from_millis(100));
let current = status.load(Ordering::Relaxed);
match current {
// Not yet
0 => continue,
// Good, we are done with the correct result
_ if current == 1 => return,
_ => panic!("Wrong result value {}", current),
}
}
panic!("Timed out waiting for the signal");
}
pub fn test_signal_with_pid() {
let status = Arc::new(AtomicUsize::new(0));
let action = {
let status = Arc::clone(&status);
move |siginfo: &siginfo_t| {
// Hack: currently, libc exposes only the first 3 fields of siginfo_t. The pid
// comes somewhat later on. Therefore, we do a Really Ugly Hack and define our
// own structure (and hope it is correct on all platforms). But hey, this is
// only the tests, so we are going to get away with this.
#[repr(C)]
struct SigInfo {
_fields: [c_int; 3],
#[cfg(all(target_pointer_width = "64", target_os = "linux"))]
_pad: c_int,
pid: pid_t,
}
let info: &SigInfo =
unsafe { (siginfo as *const _ as *const SigInfo).as_ref().unwrap() };
status.store(info.pid as usize, Ordering::Relaxed);
}
};
let pid = unsafe { getpid() };
register_sigaction(SIGUSR2, action).unwrap();
raise_signal(SIGUSR2);
for _ in 0..10 {
thread::sleep(Duration::from_millis(100));
let current = status.load(Ordering::Relaxed);
match current {
// Not yet (PID == 0 doesn't happen)
0 => continue,
// Good, we are done with the correct result
_ if current == pid as usize => return,
_ => panic!("Wrong status value {}", current),
}
}
panic!("Timed out waiting for the signal");
}
// Check that registration works as expected and that unregister tells if it did or not.
pub fn test_signal_register_unregister() {
let signal = register(SIGUSR1, || ()).unwrap();
// It was there now, so we can unregister
assert!(unregister(signal));
// The next time unregistering does nothing and tells us so.
assert!(!unregister(signal));
}
pub fn test_signal_register_unregister1() {
let called = Arc::new(AtomicUsize::new(0));
let action = {
let called = Arc::clone(&called);
move || {
called.fetch_add(1, Ordering::Relaxed);
}
};
register(SIGTERM, action.clone()).unwrap();
register(SIGTERM, action.clone()).unwrap();
register(SIGINT, action.clone()).unwrap();
raise_signal(SIGTERM);
// The closure is run twice.
assert_eq!(2, called.load(Ordering::Relaxed));
assert!(unregister_signal(SIGTERM));
raise_signal(SIGTERM);
// Second one unregisters nothing.
assert!(!unregister_signal(SIGTERM));
// After unregistering (both), it is no longer run at all.
assert_eq!(2, called.load(Ordering::Relaxed));
// The SIGINT one is not disturbed.
raise_signal(SIGINT);
assert_eq!(3, called.load(Ordering::Relaxed));
// But it's possible to register it again just fine.
register(SIGTERM, action).unwrap();
raise_signal(SIGTERM);
assert_eq!(4, called.load(Ordering::Relaxed));
}