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 | |