From 40b02f5ea2ab9833c7555bb0490d48d9f1d9e8cc Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill@korins.ky>
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<Duration> 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));
 }
