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 {
smoke_test()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
trylock_test()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
destroy_held_lock_test()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
use_after_destroy_test()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
unlock_without_holding_test()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
deadlock_test()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
null_lock_test()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
pshared_attribute_test()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
multi_thread_test()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
TEST_MAIN()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