From 40b02f5ea2ab9833c7555bb0490d48d9f1d9e8cc Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Mon, 24 Jul 2023 22:29:40 +0200 Subject: [PATCH] Enforce call of `pthread_*_init` (#1725) Very old macOS has a wired behaviour that statically initalized and not used pthread primites returns EINVAL on attempt to be destroyed. calling `pthread_*_init` on not used objects fixes all such errors. Closes: https://github.com/capnproto/capnproto/issues/1715 --- c++/src/kj/mutex.c++ | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git c++/src/kj/mutex.c++ c++/src/kj/mutex.c++ index 1ddd4921..edccdf40 100644 --- src/kj/mutex.c++ +++ src/kj/mutex.c++ @@ -870,7 +870,13 @@ void Once::reset() { } \ } -Mutex::Mutex(): mutex(PTHREAD_RWLOCK_INITIALIZER) {} +Mutex::Mutex(): mutex(PTHREAD_RWLOCK_INITIALIZER) { +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 + // In older versions of MacOS, mutexes initialized statically cannot be destroyed, + // so we must call the init function. + KJ_PTHREAD_CALL(pthread_rwlock_init(&mutex, NULL)); +#endif +} Mutex::~Mutex() { KJ_PTHREAD_CLEANUP(pthread_rwlock_destroy(&mutex)); } @@ -950,6 +956,14 @@ void Mutex::wait(Predicate& predicate, Maybe timeout, NoopSourceLocati nullptr, waitersTail, predicate, nullptr, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; + +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 + // In older versions of MacOS, mutexes initialized statically cannot be destroyed, + // so we must call the init function. + KJ_PTHREAD_CALL(pthread_cond_init(&waiter.condvar, NULL)); + KJ_PTHREAD_CALL(pthread_mutex_init(&waiter.stupidMutex, NULL)); +#endif + addWaiter(waiter); // To guarantee that we've re-locked the mutex before scope exit, keep track of whether it is @@ -1059,7 +1073,13 @@ void Mutex::induceSpuriousWakeupForTest() { Once::Once(bool startInitialized) : state(startInitialized ? INITIALIZED : UNINITIALIZED), - mutex(PTHREAD_MUTEX_INITIALIZER) {} + mutex(PTHREAD_MUTEX_INITIALIZER) { +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 + // In older versions of MacOS, mutexes initialized statically cannot be destroyed, + // so we must call the init function. + KJ_PTHREAD_CALL(pthread_mutex_init(&mutex, NULL)); +#endif +} Once::~Once() { KJ_PTHREAD_CLEANUP(pthread_mutex_destroy(&mutex)); }