]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass-dep/shims/pthreads.rs
Auto merge of #106884 - clubby789:fieldless-enum-debug, r=michaelwoerister
[rust.git] / src / tools / miri / tests / pass-dep / shims / pthreads.rs
1 //@ignore-target-windows: No libc on Windows
2 #![feature(cstr_from_bytes_until_nul)]
3 use std::ffi::{CStr, CString};
4 use std::thread;
5
6 fn main() {
7     test_mutex_libc_init_recursive();
8     test_mutex_libc_init_normal();
9     test_mutex_libc_init_errorcheck();
10     test_rwlock_libc_static_initializer();
11     test_named_thread_truncation();
12
13     #[cfg(target_os = "linux")]
14     test_mutex_libc_static_initializer_recursive();
15 }
16
17 fn test_mutex_libc_init_recursive() {
18     unsafe {
19         let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
20         assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0);
21         assert_eq!(
22             libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE),
23             0,
24         );
25         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
26         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0);
27         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
28         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
29         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
30         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
31         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
32         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
33         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
34         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
35         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM);
36         assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
37         assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0);
38     }
39 }
40
41 fn test_mutex_libc_init_normal() {
42     unsafe {
43         let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
44         assert_eq!(
45             libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678),
46             libc::EINVAL,
47         );
48         assert_eq!(
49             libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL),
50             0,
51         );
52         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
53         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
54         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
55         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY);
56         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
57         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
58         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
59         assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
60     }
61 }
62
63 fn test_mutex_libc_init_errorcheck() {
64     unsafe {
65         let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
66         assert_eq!(
67             libc::pthread_mutexattr_settype(
68                 &mut mutexattr as *mut _,
69                 libc::PTHREAD_MUTEX_ERRORCHECK,
70             ),
71             0,
72         );
73         let mut mutex: libc::pthread_mutex_t = std::mem::zeroed();
74         assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0);
75         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
76         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY);
77         assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK);
78         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
79         assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0);
80         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
81         assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM);
82         assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
83     }
84 }
85
86 // Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
87 // libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER.
88 #[cfg(target_os = "linux")]
89 fn test_mutex_libc_static_initializer_recursive() {
90     let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
91     unsafe {
92         assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
93         assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
94         assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
95         assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
96         assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0);
97         assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0);
98         assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
99         assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0);
100         assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM);
101         assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0);
102     }
103 }
104
105 // Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we
106 // need to go a layer deeper and test the behavior of the libc functions, because
107 // std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers.
108 fn test_rwlock_libc_static_initializer() {
109     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
110     unsafe {
111         assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
112         assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0);
113         assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
114         assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0);
115         assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
116         assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
117         assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
118
119         assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0);
120         assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY);
121         assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
122         assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
123
124         assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0);
125         assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY);
126         assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY);
127         assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0);
128
129         assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0);
130     }
131 }
132
133 fn test_named_thread_truncation() {
134     let long_name = std::iter::once("test_named_thread_truncation")
135         .chain(std::iter::repeat(" yada").take(100))
136         .collect::<String>();
137
138     fn set_thread_name(name: &CStr) -> i32 {
139         #[cfg(target_os = "linux")]
140         return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) };
141         #[cfg(target_os = "macos")]
142         return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) };
143     }
144
145     let result = thread::Builder::new().name(long_name.clone()).spawn(move || {
146         // Rust remembers the full thread name itself.
147         assert_eq!(thread::current().name(), Some(long_name.as_str()));
148
149         // But the system is limited -- make sure we successfully set a truncation.
150         let mut buf = vec![0u8; long_name.len() + 1];
151         unsafe {
152             libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
153         };
154         let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
155         assert!(cstr.to_bytes().len() >= 15); // POSIX seems to promise at least 15 chars
156         assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
157
158         // Also test directly calling pthread_setname to check its return value.
159         assert_eq!(set_thread_name(&cstr), 0);
160         // But with a too long name it should fail.
161         assert_ne!(set_thread_name(&CString::new(long_name).unwrap()), 0);
162     });
163     result.unwrap().join().unwrap();
164 }