1 //===-- Tests for pthread_spinlock ----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "hdr/errno_macros.h" 10 #include "src/pthread/pthread_create.h" 11 #include "src/pthread/pthread_join.h" 12 #include "src/pthread/pthread_spin_destroy.h" 13 #include "src/pthread/pthread_spin_init.h" 14 #include "src/pthread/pthread_spin_lock.h" 15 #include "src/pthread/pthread_spin_trylock.h" 16 #include "src/pthread/pthread_spin_unlock.h" 17 #include "test/IntegrationTest/test.h" 18 #include <pthread.h> 19 20 namespace { 21 void smoke_test() { 22 pthread_spinlock_t lock; 23 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 24 0); 25 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); 26 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); 27 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 28 } 29 30 void trylock_test() { 31 pthread_spinlock_t lock; 32 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 33 0); 34 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), 0); 35 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), EBUSY); 36 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); 37 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), 0); 38 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); 39 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 40 } 41 42 void destroy_held_lock_test() { 43 pthread_spinlock_t lock; 44 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 45 0); 46 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); 47 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), EBUSY); 48 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); 49 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 50 } 51 52 void use_after_destroy_test() { 53 pthread_spinlock_t lock; 54 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 55 0); 56 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 57 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), EINVAL); 58 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), EINVAL); 59 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(&lock), EINVAL); 60 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), EINVAL); 61 } 62 63 void unlock_without_holding_test() { 64 pthread_spinlock_t lock; 65 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 66 0); 67 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), EPERM); 68 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 69 } 70 71 void deadlock_test() { 72 pthread_spinlock_t lock; 73 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 74 0); 75 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), 0); 76 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&lock), EDEADLK); 77 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&lock), 0); 78 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 79 } 80 81 void null_lock_test() { 82 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(nullptr, 0), EINVAL); 83 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(nullptr), EINVAL); 84 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_trylock(nullptr), EINVAL); 85 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(nullptr), EINVAL); 86 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(nullptr), EINVAL); 87 } 88 89 void pshared_attribute_test() { 90 pthread_spinlock_t lock; 91 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_SHARED), 92 0); 93 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 94 95 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE), 96 0); 97 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&lock), 0); 98 99 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&lock, -1), EINVAL); 100 } 101 102 void multi_thread_test() { 103 struct shared_data { 104 pthread_spinlock_t lock; 105 int count = 0; 106 } shared; 107 pthread_t thread[10]; 108 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_init(&shared.lock, 0), 0); 109 for (int i = 0; i < 10; ++i) { 110 ASSERT_EQ( 111 LIBC_NAMESPACE::pthread_create( 112 &thread[i], nullptr, 113 [](void *arg) -> void * { 114 auto *data = static_cast<shared_data *>(arg); 115 for (int j = 0; j < 1000; ++j) { 116 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_lock(&data->lock), 0); 117 data->count += j; 118 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_unlock(&data->lock), 0); 119 } 120 return nullptr; 121 }, 122 &shared), 123 0); 124 } 125 for (int i = 0; i < 10; ++i) { 126 ASSERT_EQ(LIBC_NAMESPACE::pthread_join(thread[i], nullptr), 0); 127 } 128 ASSERT_EQ(LIBC_NAMESPACE::pthread_spin_destroy(&shared.lock), 0); 129 ASSERT_EQ(shared.count, 1000 * 999 * 5); 130 } 131 132 } // namespace 133 134 TEST_MAIN() { 135 smoke_test(); 136 trylock_test(); 137 destroy_held_lock_test(); 138 use_after_destroy_test(); 139 unlock_without_holding_test(); 140 deadlock_test(); 141 multi_thread_test(); 142 null_lock_test(); 143 pshared_attribute_test(); 144 return 0; 145 } 146