//===-- Tests for pthread_spinlock ----------------------------------------===// // // 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 "hdr/errno_macros.h" #include "src/pthread/pthread_create.h" #include "src/pthread/pthread_join.h" #include "src/pthread/pthread_spin_destroy.h" #include "src/pthread/pthread_spin_init.h" #include "src/pthread/pthread_spin_lock.h" #include "src/pthread/pthread_spin_trylock.h" #include "src/pthread/pthread_spin_unlock.h" #include "test/IntegrationTest/test.h" #include namespace { void smoke_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); } void trylock_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), EBUSY); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); } void destroy_held_lock_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), EBUSY); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); } void use_after_destroy_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), EINVAL); } void unlock_without_holding_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), EPERM); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); } void deadlock_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), EDEADLK); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); } void null_lock_test() { ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(nullptr, 0), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(nullptr), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(nullptr), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(nullptr), EINVAL); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(nullptr), EINVAL); } void pshared_attribute_test() { pthread_spinlock_t lock; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_SHARED), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, -1), EINVAL); } void multi_thread_test() { struct shared_data { pthread_spinlock_t lock; int count = 0; } shared; pthread_t thread[10]; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&shared.lock, 0), 0); for (int i = 0; i < 10; ++i) { ASSERT_EQ( LIBC_NAMESPACE::pthread_create( &thread[i], nullptr, [](void *arg) -> void * { auto *data = static_cast(arg); for (int j = 0; j < 1000; ++j) { ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&data->lock), 0); data->count += j; ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&data->lock), 0); } return nullptr; }, &shared), 0); } for (int i = 0; i < 10; ++i) { ASSERT_EQ(LIBC_NAMESPACE::pthread_join(thread[i], nullptr), 0); } ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&shared.lock), 0); ASSERT_EQ(shared.count, 1000 * 999 * 5); } } // namespace TEST_MAIN() { smoke_test(); trylock_test(); destroy_held_lock_test(); use_after_destroy_test(); unlock_without_holding_test(); deadlock_test(); multi_thread_test(); null_lock_test(); pshared_attribute_test(); return 0; }