4
4
#![ feature( sync_unsafe_cell) ]
5
5
6
6
use std:: cell:: SyncUnsafeCell ;
7
- use std:: thread ;
8
- use std:: { mem, ptr} ;
7
+ use std:: mem :: MaybeUninit ;
8
+ use std:: { mem, ptr, thread } ;
9
9
10
10
fn main ( ) {
11
11
test_mutex_libc_init_recursive ( ) ;
@@ -15,9 +15,10 @@ fn main() {
15
15
#[ cfg( target_os = "linux" ) ]
16
16
test_mutex_libc_static_initializer_recursive ( ) ;
17
17
18
- test_mutex ( ) ;
18
+ check_mutex ( ) ;
19
19
check_rwlock_write ( ) ;
20
20
check_rwlock_read_no_deadlock ( ) ;
21
+ check_cond ( ) ;
21
22
}
22
23
23
24
fn test_mutex_libc_init_recursive ( ) {
@@ -119,7 +120,7 @@ impl<T> Clone for SendPtr<T> {
119
120
}
120
121
}
121
122
122
- fn test_mutex ( ) {
123
+ fn check_mutex ( ) {
123
124
// Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex.
124
125
unsafe {
125
126
let data = SyncUnsafeCell :: new ( ( libc:: PTHREAD_MUTEX_INITIALIZER , 0 ) ) ;
@@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() {
213
214
}
214
215
}
215
216
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
+
216
264
// std::sync::RwLock does not even used pthread_rwlock any more.
217
265
// Do some smoke testing of the API surface.
218
266
fn test_rwlock_libc_static_initializer ( ) {
0 commit comments