diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -241,6 +241,7 @@ def PThreadAPI : PublicAPI<"pthread.h"> { let Types = [ "pthread_attr_t", + "pthread_mutex_t", "pthread_mutexattr_t" ]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -236,6 +236,10 @@ libc.src.pthread.pthread_attr_setstack libc.src.pthread.pthread_attr_setstacksize libc.src.pthread.pthread_attr_init + libc.src.pthread.pthread_mutex_destroy + libc.src.pthread.pthread_mutex_init + libc.src.pthread.pthread_mutex_lock + libc.src.pthread.pthread_mutex_unlock libc.src.pthread.pthread_mutexattr_destroy libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_getpshared diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -163,6 +163,7 @@ DEPENDS .llvm_libc_common_h .llvm-libc-types.pthread_attr_t + .llvm-libc-types.pthread_mutex_t .llvm-libc-types.pthread_mutexattr_t ) diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -20,7 +20,8 @@ add_header(off_t HDR off_t.h) add_header(off64_t HDR off64_t.h) add_header(once_flag HDR once_flag.h DEPENDS .__futex_word) -add_header(pthread_attr_t HDR pthread_attr_t.h) +add_header(pthread_attr_t HDR pthread_attr_t.h DEPENDS .size_t) +add_header(pthread_mutex_t HDR pthread_mutex_t.h DEPENDS .__futex_word .__mutex_type) add_header(pthread_mutexattr_t HDR pthread_mutexattr_t.h) add_header(size_t HDR size_t.h) add_header(ssize_t HDR ssize_t.h) diff --git a/libc/include/llvm-libc-types/__mutex_type.h b/libc/include/llvm-libc-types/__mutex_type.h --- a/libc/include/llvm-libc-types/__mutex_type.h +++ b/libc/include/llvm-libc-types/__mutex_type.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +#ifndef __LLVM_LIBC_TYPES___MUTEX_T_H +#define __LLVM_LIBC_TYPES___MUTEX_T_H + #include typedef struct { @@ -22,3 +25,5 @@ #error "Mutex type not defined for the target platform." #endif } __mutex_type; + +#endif // __LLVM_LIBC_TYPES___MUTEX_T_H diff --git a/libc/include/llvm-libc-types/pthread_mutex_t.h b/libc/include/llvm-libc-types/pthread_mutex_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/pthread_mutex_t.h @@ -0,0 +1,16 @@ +//===-- Definition of pthread_mutex_t type --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H +#define __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H + +#include + +typedef __mutex_type pthread_mutex_t; + +#endif // __LLVM_LIBC_TYPES_PTHREAD_MUTEX_T_H diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -33,6 +33,12 @@ ConstType ConstPThreadMutexAttrTPtr = ConstType; ConstType ConstRestrictedPThreadMutexAttrTPtr = ConstType; + NamedType PThreadMutexTType = NamedType<"pthread_mutex_t">; + PtrType PThreadMutexTPtr = PtrType; + RestrictedPtrType RestrictedPThreadMutexTPtr = RestrictedPtrType; + ConstType ConstPThreadMutexTPtr = ConstType; + ConstType ConstRestrictedPThreadMutexTPtr = ConstType; + HeaderSpec Errno = HeaderSpec< "errno.h", [ @@ -386,7 +392,7 @@ HeaderSpec PThread = HeaderSpec< "pthread.h", [], // Macros - [PThreadAttrTType, PThreadMutexAttrTType], // Types + [PThreadAttrTType, PThreadMutexAttrTType, PThreadMutexTType], // Types [], // Enumerations [ FunctionSpec< @@ -499,6 +505,26 @@ RetValSpec, [ArgSpec, ArgSpec] >, + FunctionSpec< + "pthread_mutex_init", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< + "pthread_mutex_destroy", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "pthread_mutex_lock", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "pthread_mutex_unlock", + RetValSpec, + [ArgSpec] + >, ] >; diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt --- a/libc/src/pthread/CMakeLists.txt +++ b/libc/src/pthread/CMakeLists.txt @@ -196,3 +196,49 @@ libc.include.errno libc.include.pthread ) + +add_entrypoint_object( + pthread_mutex_init + SRCS + pthread_mutex_init.cpp + HDRS + pthread_mutex_init.h + DEPENDS + .pthread_mutexattr + libc.include.errno + libc.include.pthread + libc.src.__support.threads.mutex +) + +add_entrypoint_object( + pthread_mutex_destroy + SRCS + pthread_mutex_destroy.cpp + HDRS + pthread_mutex_destroy.h + DEPENDS + libc.include.pthread + libc.src.__support.threads.mutex +) + +add_entrypoint_object( + pthread_mutex_lock + SRCS + pthread_mutex_lock.cpp + HDRS + pthread_mutex_lock.h + DEPENDS + libc.include.pthread + libc.src.__support.threads.mutex +) + +add_entrypoint_object( + pthread_mutex_unlock + SRCS + pthread_mutex_unlock.cpp + HDRS + pthread_mutex_unlock.h + DEPENDS + libc.include.pthread + libc.src.__support.threads.mutex +) diff --git a/libc/src/pthread/pthread_mutex_destroy.h b/libc/src/pthread/pthread_mutex_destroy.h new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_destroy.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pthread_mutex_destroy ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H +#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX__DESTROY_H + +#include + +namespace __llvm_libc { + +int pthread_mutex_destroy(pthread_mutex_t *mutex); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_DESTROY_H diff --git a/libc/src/pthread/pthread_mutex_destroy.cpp b/libc/src/pthread/pthread_mutex_destroy.cpp new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_destroy.cpp @@ -0,0 +1,26 @@ +//===-- Linux implementation of the pthread_mutex_destroy function --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "pthread_mutex_destroy.h" + +#include "src/__support/common.h" +#include "src/__support/threads/mutex.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, pthread_mutex_destroy, (pthread_mutex_t * mutex)) { + auto *m = reinterpret_cast(mutex); + Mutex::destroy(m); + // TODO: When the Mutex class supports all the possible error conditions + // return the appropriate error value here. + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_mutex_init.h b/libc/src/pthread/pthread_mutex_init.h new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_init.h @@ -0,0 +1,21 @@ +//===-- Implementation header for pthread_mutex_init function ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H +#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_INIT_H + +#include "include/pthread.h" + +namespace __llvm_libc { + +int pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *__restrict attr); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_PTHREAD_pthread_mutex_INIT_H diff --git a/libc/src/pthread/pthread_mutex_init.cpp b/libc/src/pthread/pthread_mutex_init.cpp new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_init.cpp @@ -0,0 +1,35 @@ +//===-- Linux implementation of the pthread_mutex_init function -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "pthread_mutex_init.h" +#include "pthread_mutexattr.h" + +#include "src/__support/common.h" +#include "src/__support/threads/mutex.h" + +#include +#include + +namespace __llvm_libc { + +static_assert(sizeof(Mutex) <= sizeof(pthread_mutex_t), + "The public pthread_mutex_t type cannot accommodate the internal " + "mutex type."); + +LLVM_LIBC_FUNCTION(int, pthread_mutex_init, + (pthread_mutex_t * m, + const pthread_mutexattr_t *__restrict attr)) { + auto mutexattr = attr == nullptr ? DEFAULT_MUTEXATTR : *attr; + auto err = + Mutex::init(reinterpret_cast(m), false, + get_mutexattr_type(mutexattr) & PTHREAD_MUTEX_RECURSIVE, + get_mutexattr_robust(mutexattr) & PTHREAD_MUTEX_ROBUST); + return err == MutexError::NONE ? 0 : EAGAIN; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_mutex_lock.h b/libc/src/pthread/pthread_mutex_lock.h new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_lock.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pthread_mutex_lock function ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H +#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H + +#include + +namespace __llvm_libc { + +int pthread_mutex_lock(pthread_mutex_t *mutex); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_LOCK_H diff --git a/libc/src/pthread/pthread_mutex_lock.cpp b/libc/src/pthread/pthread_mutex_lock.cpp new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_lock.cpp @@ -0,0 +1,26 @@ +//===-- Linux implementation of the pthread_mutex_lock function -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "pthread_mutex_lock.h" + +#include "src/__support/common.h" +#include "src/__support/threads/mutex.h" + +#include + +namespace __llvm_libc { + +// The implementation currently handles only plain mutexes. +LLVM_LIBC_FUNCTION(int, pthread_mutex_lock, (pthread_mutex_t * mutex)) { + reinterpret_cast(mutex)->lock(); + // TODO: When the Mutex class supports all the possible error conditions + // return the appropriate error value here. + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_mutex_unlock.h b/libc/src/pthread/pthread_mutex_unlock.h new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_unlock.h @@ -0,0 +1,20 @@ +//===-- Implementation header for pthread_mutex_unlock function -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H +#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H + +#include + +namespace __llvm_libc { + +int pthread_mutex_unlock(pthread_mutex_t *mutex); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEX_UNLOCK_H diff --git a/libc/src/pthread/pthread_mutex_unlock.cpp b/libc/src/pthread/pthread_mutex_unlock.cpp new file mode 100644 --- /dev/null +++ b/libc/src/pthread/pthread_mutex_unlock.cpp @@ -0,0 +1,26 @@ +//===-- Linux implementation of the pthread_mutex_unlock function ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "pthread_mutex_unlock.h" + +#include "src/__support/common.h" +#include "src/__support/threads/mutex.h" + +#include + +namespace __llvm_libc { + +// The implementation currently handles only plain mutexes. +LLVM_LIBC_FUNCTION(int, pthread_mutex_unlock, (pthread_mutex_t * mutex)) { + reinterpret_cast(mutex)->unlock(); + // TODO: When the Mutex class supports all the possible error conditions + // return the appropriate error value here. + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/pthread/pthread_mutexattr.h b/libc/src/pthread/pthread_mutexattr.h --- a/libc/src/pthread/pthread_mutexattr.h +++ b/libc/src/pthread/pthread_mutexattr.h @@ -31,6 +31,16 @@ PTHREAD_MUTEX_STALLED << unsigned(PThreadMutexAttrPos::ROBUST_SHIFT) | PTHREAD_PROCESS_PRIVATE << unsigned(PThreadMutexAttrPos::PSHARED_SHIFT); +static inline int get_mutexattr_type(pthread_mutexattr_t attr) { + return (attr & unsigned(PThreadMutexAttrPos::TYPE_MASK)) >> + unsigned(PThreadMutexAttrPos::TYPE_SHIFT); +} + +static inline int get_mutexattr_robust(pthread_mutexattr_t attr) { + return (attr & unsigned(PThreadMutexAttrPos::ROBUST_MASK)) >> + unsigned(PThreadMutexAttrPos::ROBUST_SHIFT); +} + } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_MUTEXATTR_H diff --git a/libc/test/src/pthread/CMakeLists.txt b/libc/test/src/pthread/CMakeLists.txt --- a/libc/test/src/pthread/CMakeLists.txt +++ b/libc/test/src/pthread/CMakeLists.txt @@ -39,3 +39,20 @@ libc.src.pthread.pthread_mutexattr_setrobust libc.src.pthread.pthread_mutexattr_settype ) + +add_libc_unittest( + phtread_mutex_test + SUITE + libc_pthread_unittests + SRCS + pthread_mutex_test.cpp + DEPENDS + libc.include.pthread + libc.src.errno.errno + libc.src.pthread.pthread_mutex_destroy + libc.src.pthread.pthread_mutex_init + libc.src.pthread.pthread_mutex_lock + libc.src.pthread.pthread_mutex_unlock + libc.src.threads.thrd_create + libc.src.threads.thrd_join +) diff --git a/libc/test/src/pthread/pthread_mutex_test.cpp b/libc/test/src/pthread/pthread_mutex_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/pthread/pthread_mutex_test.cpp @@ -0,0 +1,188 @@ +//===-- Unittests for pthread_mutex_t -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/pthread/pthread_mutex_destroy.h" +#include "src/pthread/pthread_mutex_init.h" +#include "src/pthread/pthread_mutex_lock.h" +#include "src/pthread/pthread_mutex_unlock.h" + +// TODO: When pthread_t type is available, use it to spawn threads instead of +// thrd_t. +#include "src/threads/thrd_create.h" +#include "src/threads/thrd_join.h" + +#include "utils/UnitTest/Test.h" + +#include + +constexpr int START = 0; +constexpr int MAX = 10000; + +pthread_mutex_t mutex; +static int shared_int = START; + +int counter(void *arg) { + int last_count = START; + while (true) { + __llvm_libc::pthread_mutex_lock(&mutex); + if (shared_int == last_count + 1) { + shared_int++; + last_count = shared_int; + } + __llvm_libc::pthread_mutex_unlock(&mutex); + if (last_count >= MAX) + break; + } + return 0; +} + +TEST(LlvmLibcMutexTest, RelayCounter) { + ASSERT_EQ(__llvm_libc::pthread_mutex_init(&mutex, nullptr), 0); + + // The idea of this test is that two competing threads will update + // a counter only if the other thread has updated it. + thrd_t thread; + __llvm_libc::thrd_create(&thread, counter, nullptr); + + int last_count = START; + while (true) { + ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&mutex), 0); + if (shared_int == START) { + ++shared_int; + last_count = shared_int; + } else if (shared_int != last_count) { + ASSERT_EQ(shared_int, last_count + 1); + ++shared_int; + last_count = shared_int; + } + ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&mutex), 0); + if (last_count > MAX) + break; + } + + int retval = 123; + __llvm_libc::thrd_join(&thread, &retval); + ASSERT_EQ(retval, 0); + + __llvm_libc::pthread_mutex_destroy(&mutex); +} + +pthread_mutex_t start_lock, step_lock; +bool started, step; + +int stepper(void *arg) { + __llvm_libc::pthread_mutex_lock(&start_lock); + started = true; + __llvm_libc::pthread_mutex_unlock(&start_lock); + + __llvm_libc::pthread_mutex_lock(&step_lock); + step = true; + __llvm_libc::pthread_mutex_unlock(&step_lock); + return 0; +} + +TEST(LlvmLibcMutexTest, WaitAndStep) { + ASSERT_EQ(__llvm_libc::pthread_mutex_init(&start_lock, nullptr), 0); + ASSERT_EQ(__llvm_libc::pthread_mutex_init(&step_lock, nullptr), 0); + + // In this test, we start a new thread but block it before it can make a + // step. Once we ensure that the thread is blocked, we unblock it. + // After unblocking, we then verify that the thread was indeed unblocked. + step = false; + started = false; + ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0); + + thrd_t thread; + __llvm_libc::thrd_create(&thread, stepper, nullptr); + + while (true) { + // Make sure the thread actually started. + ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&start_lock), 0); + bool s = started; + ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&start_lock), 0); + if (s) + break; + } + + // Since |step_lock| is still locked, |step| should be false. + ASSERT_FALSE(step); + + // Unlock the step lock and wait until the step is made. + ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0); + + while (true) { + ASSERT_EQ(__llvm_libc::pthread_mutex_lock(&step_lock), 0); + bool current_step_value = step; + ASSERT_EQ(__llvm_libc::pthread_mutex_unlock(&step_lock), 0); + if (current_step_value) + break; + } + + int retval = 123; + __llvm_libc::thrd_join(&thread, &retval); + ASSERT_EQ(retval, 0); + + __llvm_libc::pthread_mutex_destroy(&start_lock); + __llvm_libc::pthread_mutex_destroy(&step_lock); +} + +static constexpr int THREAD_COUNT = 10; +static pthread_mutex_t multiple_waiter_lock; +static pthread_mutex_t counter_lock; +static int wait_count = 0; + +int waiter_func(void *) { + __llvm_libc::pthread_mutex_lock(&counter_lock); + ++wait_count; + __llvm_libc::pthread_mutex_unlock(&counter_lock); + + // Block on the waiter lock until the main + // thread unblocks. + __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock); + __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock); + + __llvm_libc::pthread_mutex_lock(&counter_lock); + --wait_count; + __llvm_libc::pthread_mutex_unlock(&counter_lock); + + return 0; +} + +TEST(LlvmLibcMutexTest, MultipleWaiters) { + __llvm_libc::pthread_mutex_init(&multiple_waiter_lock, nullptr); + __llvm_libc::pthread_mutex_init(&counter_lock, nullptr); + + __llvm_libc::pthread_mutex_lock(&multiple_waiter_lock); + thrd_t waiters[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; ++i) { + __llvm_libc::thrd_create(waiters + i, waiter_func, nullptr); + } + + // Spin until the counter is incremented to the desired + // value. + while (true) { + __llvm_libc::pthread_mutex_lock(&counter_lock); + if (wait_count == THREAD_COUNT) { + __llvm_libc::pthread_mutex_unlock(&counter_lock); + break; + } + __llvm_libc::pthread_mutex_unlock(&counter_lock); + } + + __llvm_libc::pthread_mutex_unlock(&multiple_waiter_lock); + + int retval; + for (int i = 0; i < THREAD_COUNT; ++i) { + __llvm_libc::thrd_join(waiters + i, &retval); + } + + ASSERT_EQ(wait_count, 0); + + __llvm_libc::pthread_mutex_destroy(&multiple_waiter_lock); + __llvm_libc::pthread_mutex_destroy(&counter_lock); +}