44#![ feature( sync_unsafe_cell) ]
55
66use std:: cell:: SyncUnsafeCell ;
7- use std:: thread ;
8- use std:: { mem, ptr} ;
7+ use std:: mem :: MaybeUninit ;
8+ use std:: { mem, ptr, thread } ;
99
1010fn main ( ) {
1111 test_mutex_libc_init_recursive ( ) ;
@@ -15,9 +15,10 @@ fn main() {
1515 #[ cfg( target_os = "linux" ) ]
1616 test_mutex_libc_static_initializer_recursive ( ) ;
1717
18- test_mutex ( ) ;
18+ check_mutex ( ) ;
1919 check_rwlock_write ( ) ;
2020 check_rwlock_read_no_deadlock ( ) ;
21+ check_cond ( ) ;
2122}
2223
2324fn test_mutex_libc_init_recursive ( ) {
@@ -119,7 +120,7 @@ impl<T> Clone for SendPtr<T> {
119120 }
120121}
121122
122- fn test_mutex ( ) {
123+ fn check_mutex ( ) {
123124 // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex.
124125 unsafe {
125126 let data = SyncUnsafeCell :: new ( ( libc:: PTHREAD_MUTEX_INITIALIZER , 0 ) ) ;
@@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() {
213214 }
214215}
215216
217+ fn check_cond ( ) {
218+ unsafe {
219+ let mut cond: MaybeUninit < libc:: pthread_cond_t > = MaybeUninit :: uninit ( ) ;
220+ assert_eq ! ( libc:: pthread_cond_init( cond. as_mut_ptr( ) , ptr:: null( ) ) , 0 ) ;
221+ let cond = SendPtr { ptr : cond. as_mut_ptr ( ) } ;
222+
223+ let mut mutex: libc:: pthread_mutex_t = libc:: PTHREAD_MUTEX_INITIALIZER ;
224+ let mutex = SendPtr { ptr : & mut mutex } ;
225+
226+ let mut data = 0 ;
227+ let data = SendPtr { ptr : & mut data } ;
228+
229+ let t = thread:: spawn ( move || {
230+ let mutex = mutex; // circumvent per-field closure capture
231+ let cond = cond;
232+ let data = data;
233+ assert_eq ! ( libc:: pthread_mutex_lock( mutex. ptr) , 0 ) ;
234+ assert ! ( data. ptr. read( ) == 0 ) ;
235+ data. ptr . write ( 1 ) ;
236+ libc:: pthread_cond_wait ( cond. ptr , mutex. ptr ) ;
237+ assert ! ( data. ptr. read( ) == 3 ) ;
238+ data. ptr . write ( 4 ) ;
239+ assert_eq ! ( libc:: pthread_mutex_unlock( mutex. ptr) , 0 ) ;
240+ } ) ;
241+
242+ thread:: yield_now ( ) ;
243+
244+ assert_eq ! ( libc:: pthread_mutex_lock( mutex. ptr) , 0 ) ;
245+ assert ! ( data. ptr. read( ) == 1 ) ;
246+ data. ptr . write ( 2 ) ;
247+ assert_eq ! ( libc:: pthread_cond_signal( cond. ptr) , 0 ) ;
248+ thread:: yield_now ( ) ; // the other thread wakes up but can't get the lock yet
249+ assert ! ( data. ptr. read( ) == 2 ) ;
250+ data. ptr . write ( 3 ) ;
251+ assert_eq ! ( libc:: pthread_mutex_unlock( mutex. ptr) , 0 ) ;
252+
253+ thread:: yield_now ( ) ; // now the other thread gets the lock back
254+
255+ assert_eq ! ( libc:: pthread_mutex_lock( mutex. ptr) , 0 ) ;
256+ assert ! ( data. ptr. read( ) == 4 ) ;
257+ assert_eq ! ( libc:: pthread_cond_broadcast( cond. ptr) , 0 ) ; // just a smoke test
258+ assert_eq ! ( libc:: pthread_mutex_unlock( mutex. ptr) , 0 ) ;
259+
260+ t. join ( ) . unwrap ( ) ;
261+ }
262+ }
263+
216264// std::sync::RwLock does not even used pthread_rwlock any more.
217265// Do some smoke testing of the API surface.
218266fn test_rwlock_libc_static_initializer ( ) {
0 commit comments