From f48bd5ee9a0ee0634db132f4ab8ed3a6e19bbb64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Feb 2024 14:41:15 +0100 Subject: [PATCH] add direct test of pthread_cond --- ...cond.rs => libc_pthread_cond_timedwait.rs} | 0 ...> libc_pthread_cond_timedwait_isolated.rs} | 0 tests/pass-dep/shims/pthread-sync.rs | 56 +++++++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) rename tests/pass-dep/concurrency/{libc_pthread_cond.rs => libc_pthread_cond_timedwait.rs} (100%) rename tests/pass-dep/concurrency/{libc_pthread_cond_isolated.rs => libc_pthread_cond_timedwait_isolated.rs} (100%) diff --git a/tests/pass-dep/concurrency/libc_pthread_cond.rs b/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs similarity index 100% rename from tests/pass-dep/concurrency/libc_pthread_cond.rs rename to tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs diff --git a/tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs b/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs similarity index 100% rename from tests/pass-dep/concurrency/libc_pthread_cond_isolated.rs rename to tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs diff --git a/tests/pass-dep/shims/pthread-sync.rs b/tests/pass-dep/shims/pthread-sync.rs index 077bbfff16..c9d10cb83d 100644 --- a/tests/pass-dep/shims/pthread-sync.rs +++ b/tests/pass-dep/shims/pthread-sync.rs @@ -4,8 +4,8 @@ #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; -use std::thread; -use std::{mem, ptr}; +use std::mem::MaybeUninit; +use std::{mem, ptr, thread}; fn main() { test_mutex_libc_init_recursive(); @@ -15,9 +15,10 @@ fn main() { #[cfg(target_os = "linux")] test_mutex_libc_static_initializer_recursive(); - test_mutex(); + check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); + check_cond(); } fn test_mutex_libc_init_recursive() { @@ -119,7 +120,7 @@ impl Clone for SendPtr { } } -fn test_mutex() { +fn check_mutex() { // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex. unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0)); @@ -213,6 +214,53 @@ fn check_rwlock_read_no_deadlock() { } } +fn check_cond() { + unsafe { + let mut cond: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0); + let cond = SendPtr { ptr: cond.as_mut_ptr() }; + + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + let mutex = SendPtr { ptr: &mut mutex }; + + let mut data = 0; + let data = SendPtr { ptr: &mut data }; + + let t = thread::spawn(move || { + let mutex = mutex; // circumvent per-field closure capture + let cond = cond; + let data = data; + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 0); + data.ptr.write(1); + libc::pthread_cond_wait(cond.ptr, mutex.ptr); + assert!(data.ptr.read() == 3); + data.ptr.write(4); + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + }); + + thread::yield_now(); + + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 1); + data.ptr.write(2); + assert_eq!(libc::pthread_cond_signal(cond.ptr), 0); + thread::yield_now(); // the other thread wakes up but can't get the lock yet + assert!(data.ptr.read() == 2); + data.ptr.write(3); + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + + thread::yield_now(); // now the other thread gets the lock back + + assert_eq!(libc::pthread_mutex_lock(mutex.ptr), 0); + assert!(data.ptr.read() == 4); + assert_eq!(libc::pthread_cond_broadcast(cond.ptr), 0); // just a smoke test + assert_eq!(libc::pthread_mutex_unlock(mutex.ptr), 0); + + t.join().unwrap(); + } +} + // std::sync::RwLock does not even used pthread_rwlock any more. // Do some smoke testing of the API surface. fn test_rwlock_libc_static_initializer() {