]> git.proxmox.com Git - rustc.git/blame - library/std/src/io/stdio/tests.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / library / std / src / io / stdio / tests.rs
CommitLineData
1b1a35ee
XL
1use super::*;
2use crate::panic::{RefUnwindSafe, UnwindSafe};
136023e0 3use crate::sync::mpsc::sync_channel;
1b1a35ee
XL
4use crate::thread;
5
6#[test]
7fn stdout_unwind_safe() {
8 assert_unwind_safe::<Stdout>();
9}
10#[test]
11fn stdoutlock_unwind_safe() {
12 assert_unwind_safe::<StdoutLock<'_>>();
13 assert_unwind_safe::<StdoutLock<'static>>();
14}
15#[test]
16fn stderr_unwind_safe() {
17 assert_unwind_safe::<Stderr>();
18}
19#[test]
20fn stderrlock_unwind_safe() {
21 assert_unwind_safe::<StderrLock<'_>>();
22 assert_unwind_safe::<StderrLock<'static>>();
23}
24
25fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
26
27#[test]
28#[cfg_attr(target_os = "emscripten", ignore)]
29fn panic_doesnt_poison() {
30 thread::spawn(|| {
31 let _a = stdin();
32 let _a = _a.lock();
33 let _a = stdout();
34 let _a = _a.lock();
35 let _a = stderr();
36 let _a = _a.lock();
37 panic!();
38 })
39 .join()
40 .unwrap_err();
41
42 let _a = stdin();
43 let _a = _a.lock();
44 let _a = stdout();
45 let _a = _a.lock();
46 let _a = stderr();
47 let _a = _a.lock();
48}
136023e0
XL
49
50#[test]
51#[cfg_attr(target_os = "emscripten", ignore)]
52fn test_lock_stderr() {
53 test_lock(stderr, stderr_locked);
54}
55#[test]
56#[cfg_attr(target_os = "emscripten", ignore)]
57fn test_lock_stdin() {
58 test_lock(stdin, stdin_locked);
59}
60#[test]
61#[cfg_attr(target_os = "emscripten", ignore)]
62fn test_lock_stdout() {
63 test_lock(stdout, stdout_locked);
64}
65
66// Helper trait to make lock testing function generic.
67trait Stdio<'a>: 'static
68where
69 Self::Lock: 'a,
70{
71 type Lock;
72 fn lock(&'a self) -> Self::Lock;
73}
74impl<'a> Stdio<'a> for Stderr {
75 type Lock = StderrLock<'a>;
76 fn lock(&'a self) -> StderrLock<'a> {
77 self.lock()
78 }
79}
80impl<'a> Stdio<'a> for Stdin {
81 type Lock = StdinLock<'a>;
82 fn lock(&'a self) -> StdinLock<'a> {
83 self.lock()
84 }
85}
86impl<'a> Stdio<'a> for Stdout {
87 type Lock = StdoutLock<'a>;
88 fn lock(&'a self) -> StdoutLock<'a> {
89 self.lock()
90 }
91}
92
93// Helper trait to make lock testing function generic.
94trait StdioOwnedLock: 'static {}
95impl StdioOwnedLock for StderrLock<'static> {}
96impl StdioOwnedLock for StdinLock<'static> {}
97impl StdioOwnedLock for StdoutLock<'static> {}
98
99// Tests locking on stdio handles by starting two threads and checking that
100// they block each other appropriately.
101fn test_lock<T, U>(get_handle: fn() -> T, get_locked: fn() -> U)
102where
103 T: for<'a> Stdio<'a>,
104 U: StdioOwnedLock,
105{
106 // State enum to track different phases of the test, primarily when
107 // each lock is acquired and released.
108 #[derive(Debug, PartialEq)]
109 enum State {
110 Start1,
111 Acquire1,
112 Start2,
113 Release1,
114 Acquire2,
115 Release2,
116 }
117 use State::*;
118 // Logging vector to be checked to make sure lock acquisitions and
119 // releases happened in the correct order.
120 let log = Arc::new(Mutex::new(Vec::new()));
121 let ((tx1, rx1), (tx2, rx2)) = (sync_channel(0), sync_channel(0));
122 let th1 = {
123 let (log, tx) = (Arc::clone(&log), tx1);
124 thread::spawn(move || {
125 log.lock().unwrap().push(Start1);
126 let handle = get_handle();
127 {
128 let locked = handle.lock();
129 log.lock().unwrap().push(Acquire1);
130 tx.send(Acquire1).unwrap(); // notify of acquisition
131 tx.send(Release1).unwrap(); // wait for release command
132 log.lock().unwrap().push(Release1);
133 }
134 tx.send(Acquire1).unwrap(); // wait for th2 acquire
135 {
136 let locked = handle.lock();
137 log.lock().unwrap().push(Acquire1);
138 }
139 log.lock().unwrap().push(Release1);
140 })
141 };
142 let th2 = {
143 let (log, tx) = (Arc::clone(&log), tx2);
144 thread::spawn(move || {
145 tx.send(Start2).unwrap(); // wait for start command
146 let locked = get_locked();
147 log.lock().unwrap().push(Acquire2);
148 tx.send(Acquire2).unwrap(); // notify of acquisition
149 tx.send(Release2).unwrap(); // wait for release command
150 log.lock().unwrap().push(Release2);
151 })
152 };
153 assert_eq!(rx1.recv().unwrap(), Acquire1); // wait for th1 acquire
154 log.lock().unwrap().push(Start2);
155 assert_eq!(rx2.recv().unwrap(), Start2); // block th2
156 assert_eq!(rx1.recv().unwrap(), Release1); // release th1
157 assert_eq!(rx2.recv().unwrap(), Acquire2); // wait for th2 acquire
158 assert_eq!(rx1.recv().unwrap(), Acquire1); // block th1
159 assert_eq!(rx2.recv().unwrap(), Release2); // release th2
160 th2.join().unwrap();
161 th1.join().unwrap();
162 assert_eq!(
163 *log.lock().unwrap(),
164 [Start1, Acquire1, Start2, Release1, Acquire2, Release2, Acquire1, Release1]
165 );
166}