1 //@ignore-target-windows: No libc on Windows
2 #![feature(cstr_from_bytes_until_nul)]
3 use std::ffi::{CStr, CString};
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();
13 #[cfg(target_os = "linux")]
14 test_mutex_libc_static_initializer_recursive();
17 fn test_mutex_libc_init_recursive() {
19 let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
20 assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0);
22 libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE),
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);
41 fn test_mutex_libc_init_normal() {
43 let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
45 libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678),
49 libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL),
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);
63 fn test_mutex_libc_init_errorcheck() {
65 let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed();
67 libc::pthread_mutexattr_settype(
68 &mut mutexattr as *mut _,
69 libc::PTHREAD_MUTEX_ERRORCHECK,
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);
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);
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);
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);
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);
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);
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);
129 assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0);
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>();
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()) };
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()));
149 // But the system is limited -- make sure we successfully set a truncation.
150 let mut buf = vec![0u8; long_name.len() + 1];
152 libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
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()));
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);
163 result.unwrap().join().unwrap();