2 use crate::panic
::{RefUnwindSafe, UnwindSafe}
;
3 use crate::sync
::mpsc
::sync_channel
;
7 fn stdout_unwind_safe() {
8 assert_unwind_safe
::<Stdout
>();
11 fn stdoutlock_unwind_safe() {
12 assert_unwind_safe
::<StdoutLock
<'_
>>();
13 assert_unwind_safe
::<StdoutLock
<'
static>>();
16 fn stderr_unwind_safe() {
17 assert_unwind_safe
::<Stderr
>();
20 fn stderrlock_unwind_safe() {
21 assert_unwind_safe
::<StderrLock
<'_
>>();
22 assert_unwind_safe
::<StderrLock
<'
static>>();
25 fn assert_unwind_safe
<T
: UnwindSafe
+ RefUnwindSafe
>() {}
28 #[cfg_attr(target_os = "emscripten", ignore)]
29 fn panic_doesnt_poison() {
51 #[cfg_attr(target_os = "emscripten", ignore)]
52 fn test_lock_stderr() {
53 test_lock(stderr
, stderr_locked
);
56 #[cfg_attr(target_os = "emscripten", ignore)]
57 fn test_lock_stdin() {
58 test_lock(stdin
, stdin_locked
);
61 #[cfg_attr(target_os = "emscripten", ignore)]
62 fn test_lock_stdout() {
63 test_lock(stdout
, stdout_locked
);
66 // Helper trait to make lock testing function generic.
67 trait Stdio
<'a
>: '
static
72 fn lock(&'a
self) -> Self::Lock
;
74 impl<'a
> Stdio
<'a
> for Stderr
{
75 type Lock
= StderrLock
<'a
>;
76 fn lock(&'a
self) -> StderrLock
<'a
> {
80 impl<'a
> Stdio
<'a
> for Stdin
{
81 type Lock
= StdinLock
<'a
>;
82 fn lock(&'a
self) -> StdinLock
<'a
> {
86 impl<'a
> Stdio
<'a
> for Stdout
{
87 type Lock
= StdoutLock
<'a
>;
88 fn lock(&'a
self) -> StdoutLock
<'a
> {
93 // Helper trait to make lock testing function generic.
94 trait StdioOwnedLock
: '
static {}
95 impl StdioOwnedLock
for StderrLock
<'
static> {}
96 impl StdioOwnedLock
for StdinLock
<'
static> {}
97 impl StdioOwnedLock
for StdoutLock
<'
static> {}
99 // Tests locking on stdio handles by starting two threads and checking that
100 // they block each other appropriately.
101 fn test_lock
<T
, U
>(get_handle
: fn() -> T
, get_locked
: fn() -> U
)
103 T
: for<'a
> Stdio
<'a
>,
106 // State enum to track different phases of the test, primarily when
107 // each lock is acquired and released.
108 #[derive(Debug, PartialEq)]
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));
123 let (log
, tx
) = (Arc
::clone(&log
), tx1
);
124 thread
::spawn(move || {
125 log
.lock().unwrap().push(Start1
);
126 let handle
= get_handle();
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
);
134 tx
.send(Acquire1
).unwrap(); // wait for th2 acquire
136 let locked
= handle
.lock();
137 log
.lock().unwrap().push(Acquire1
);
139 log
.lock().unwrap().push(Release1
);
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
);
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
163 *log
.lock().unwrap(),
164 [Start1
, Acquire1
, Start2
, Release1
, Acquire2
, Release2
, Acquire1
, Release1
]