Serenity Operating System
1/*
2 * Copyright (c) 2021, Brian Gianforcaro <bgianf@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibTest/TestCase.h>
8#include <errno.h>
9#include <pthread.h>
10#include <unistd.h>
11
12TEST_CASE(spin_init_process_scope)
13{
14 {
15 pthread_spinlock_t lock {};
16 auto result = pthread_spin_init(&lock, PTHREAD_SCOPE_PROCESS);
17 EXPECT_EQ(0, result);
18 result = pthread_spin_destroy(&lock);
19 EXPECT_EQ(0, result);
20 }
21
22 {
23 pthread_spinlock_t garbage_lock { 0x1337 };
24 auto result = pthread_spin_init(&garbage_lock, PTHREAD_SCOPE_PROCESS);
25 EXPECT_EQ(0, result);
26 result = pthread_spin_destroy(&garbage_lock);
27 EXPECT_EQ(0, result);
28 }
29}
30
31TEST_CASE(spin_init_system_scope)
32{
33 pthread_spinlock_t lock {};
34 auto result = pthread_spin_init(&lock, PTHREAD_SCOPE_SYSTEM);
35 EXPECT_EQ(0, result);
36 pthread_spinlock_t garbage_lock { 0x99999 };
37 result = pthread_spin_init(&garbage_lock, PTHREAD_SCOPE_PROCESS);
38 EXPECT_EQ(0, result);
39}
40
41TEST_CASE(spin_lock)
42{
43 pthread_spinlock_t lock {};
44 auto result = pthread_spin_lock(&lock);
45 EXPECT_EQ(0, result);
46
47 // We should detect that this thread already holds this lock.
48 result = pthread_spin_lock(&lock);
49 EXPECT_EQ(EDEADLK, result);
50}
51
52TEST_CASE(spin_try_lock)
53{
54 {
55 pthread_spinlock_t lock {};
56 auto result = pthread_spin_trylock(&lock);
57 EXPECT_EQ(0, result);
58
59 result = pthread_spin_unlock(&lock);
60 EXPECT_EQ(0, result);
61 }
62
63 {
64 pthread_spinlock_t lock {};
65 auto result = pthread_spin_trylock(&lock);
66 EXPECT_EQ(0, result);
67
68 // We should detect that this thread already holds the lock.
69 result = pthread_spin_trylock(&lock);
70 EXPECT_EQ(EBUSY, result);
71 }
72}
73
74static void lock_from_different_thread(pthread_spinlock_t* lock)
75{
76 pthread_t thread_id {};
77 auto result = pthread_create(
78 &thread_id, nullptr, [](void* param) -> void* {
79 auto lock = (pthread_spinlock_t*)param;
80 pthread_spin_lock(lock);
81 return nullptr;
82 },
83 lock);
84 EXPECT_EQ(0, result);
85
86 result = pthread_join(thread_id, nullptr);
87 EXPECT_EQ(0, result);
88}
89
90TEST_CASE(spin_unlock)
91{
92 {
93 pthread_spinlock_t lock {};
94 auto result = pthread_spin_lock(&lock);
95 EXPECT_EQ(0, result);
96
97 result = pthread_spin_unlock(&lock);
98 EXPECT_EQ(0, result);
99 }
100
101 {
102 pthread_spinlock_t lock {};
103 lock_from_different_thread(&lock);
104
105 auto result = pthread_spin_unlock(&lock);
106 EXPECT_EQ(EPERM, result);
107 }
108}
109
110TEST_CASE(spin_destroy)
111{
112 {
113 pthread_spinlock_t lock {};
114 auto result = pthread_spin_lock(&lock);
115 EXPECT_EQ(0, result);
116
117 result = pthread_spin_destroy(&lock);
118 EXPECT_EQ(EBUSY, result);
119
120 result = pthread_spin_unlock(&lock);
121 EXPECT_EQ(0, result);
122 }
123
124 {
125 pthread_spinlock_t lock {};
126 lock_from_different_thread(&lock);
127
128 auto result = pthread_spin_destroy(&lock);
129 EXPECT_EQ(EBUSY, result);
130 }
131}