forked from apache/incubator-teaclave-sgx-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_signal.rs
128 lines (110 loc) · 3.9 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
128
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use sgx_libc::{siginfo_t, c_int, pid_t, SIGUSR1, SIGUSR2, SIGILL, SIGTERM,SIGINT};
use sgx_libc::ocall::getpid;
use sgx_signal::signal::{register, register_sigaction, unregister, unregister_signal, raise_signal};
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));
}