1//------------------------------------------------------------------------------
2// Copyright (c) 2016 by Lukasz Janyst <lukasz@jany.st>
3//------------------------------------------------------------------------------
4// This file is part of thread-bites.
5//
6// thread-bites is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// thread-bites is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with thread-bites. If not, see <http://www.gnu.org/licenses/>.
18//------------------------------------------------------------------------------
19
20#include <tb.h>
21#include <string.h>
22
23//------------------------------------------------------------------------------
24// Test normal mutex
25//------------------------------------------------------------------------------
26void *thread_func_normal(void *arg)
27{
28 tbthread_t self = tbthread_self();
29 tbthread_mutex_t *mutex = (tbthread_mutex_t*)arg;
30 int locked = 0;
31 if(!tbthread_mutex_trylock(mutex)) {
32 tbprint("[thread 0x%llx] Trying to actuire the mutex succeeded\n", self);
33 locked = 1;
34 }
35 else
36 tbprint("[thread 0x%llx] Trying to actuire the mutex failed\n", self);
37
38 if(!locked)
39 tbthread_mutex_lock(mutex);
40 tbprint("[thread 0x%llx] Starting normal mutex test\n", self);
41 tbsleep(1);
42 tbprint("[thread 0x%llx] Finishing normal mutex test\n", self);
43 tbthread_mutex_unlock(mutex);
44 return 0;
45}
46
47//------------------------------------------------------------------------------
48// Test errorcheck mutex
49//------------------------------------------------------------------------------
50void *thread_func_errorcheck1(void *arg)
51{
52 tbthread_t self = tbthread_self();
53 tbthread_mutex_t *mutex = (tbthread_mutex_t*)arg;
54
55 tbthread_mutex_lock(mutex);
56 tbprint("[thread 0x%llx] Starting errorcheck mutex test\n", self);
57 if(tbthread_mutex_lock(mutex) == -EDEADLK)
58 tbprint("[thread 0x%llx] Trying to lock again would deadlock\n", self);
59 tbsleep(2);
60 tbprint("[thread 0x%llx] Finishing errorcheck mutex test\n", self);
61 tbthread_mutex_unlock(mutex);
62 return 0;
63}
64
65void *thread_func_errorcheck2(void *arg)
66{
67 tbthread_t self = tbthread_self();
68 tbthread_mutex_t *mutex = (tbthread_mutex_t*)arg;
69 tbsleep(1);
70 if(tbthread_mutex_unlock(mutex) == -EPERM)
71 tbprint("[thread 0x%llx] Trying to unlock a mutex we don't own\n", self);
72 tbthread_mutex_lock(mutex);
73 tbprint("[thread 0x%llx] Starting errorcheck mutex test\n", self);
74 tbsleep(1);
75 tbprint("[thread 0x%llx] Finishing errorcheck mutex test\n", self);
76 tbthread_mutex_unlock(mutex);
77 if(tbthread_mutex_unlock(mutex) == -EPERM)
78 tbprint("[thread 0x%llx] Trying to unlock unlocked mutex\n", self);
79 return 0;
80}
81
82//------------------------------------------------------------------------------
83// Test recursive mutex
84//------------------------------------------------------------------------------
85void *thread_func_recursive(void *arg)
86{
87 tbthread_t self = tbthread_self();
88 tbthread_mutex_t *mutex = (tbthread_mutex_t*)arg;
89 int locked = 0;
90 if(!tbthread_mutex_trylock(mutex)) {
91 tbprint("[thread 0x%llx] Trying to actuire the mutex succeeded\n", self);
92 locked = 1;
93 }
94 else
95 tbprint("[thread 0x%llx] Trying to actuire the mutex failed\n", self);
96
97 if(!locked)
98 tbthread_mutex_lock(mutex);
99 tbthread_mutex_lock(mutex);
100 tbthread_mutex_lock(mutex);
101 tbprint("[thread 0x%llx] Starting recursive mutex test\n", self);
102 tbsleep(1);
103 tbprint("[thread 0x%llx] Finishing recursive mutex test\n", self);
104 tbthread_mutex_unlock(mutex);
105 tbthread_mutex_unlock(mutex);
106 tbthread_mutex_unlock(mutex);
107 return 0;
108}
109
110//------------------------------------------------------------------------------
111// Start the show
112//------------------------------------------------------------------------------
113int main(int argc, char **argv)
114{
115 tbthread_init();
116
117 tbthread_t thread[5];
118 tbthread_attr_t attr;
119 void *ret;
120 int st = 0;
121
122 //----------------------------------------------------------------------------
123 // Initialize the mutexes
124 //----------------------------------------------------------------------------
125 tbthread_mutexattr_t mattr;
126 tbthread_mutex_t mutex_normal;
127 tbthread_mutex_t mutex_errorcheck;
128 tbthread_mutex_t mutex_recursive;
129
130 tbthread_mutexattr_init(&mattr);
131 tbthread_mutex_init(&mutex_normal, 0);
132 tbthread_mutexattr_settype(&mattr, TBTHREAD_MUTEX_ERRORCHECK);
133 tbthread_mutex_init(&mutex_errorcheck, &mattr);
134 tbthread_mutexattr_settype(&mattr, TBTHREAD_MUTEX_RECURSIVE);;
135 tbthread_mutex_init(&mutex_recursive, &mattr);
136
137 //----------------------------------------------------------------------------
138 // Spawn the threads to test the normal mutex
139 //----------------------------------------------------------------------------
140 tbprint("[thread main] Testing normal mutex\n");
141 tbthread_attr_init(&attr);
142 for(int i = 0; i < 5; ++i) {
143 st = tbthread_create(&thread[i], &attr, thread_func_normal, &mutex_normal);
144 if(st != 0) {
145 tbprint("Failed to spawn thread %d: %s\n", i, tbstrerror(-st));
146 goto exit;
147 }
148 tbthread_detach(thread[i]);
149 }
150
151 tbprint("[thread main] Threads spawned successfully\n");
152 tbprint("[thread main] Sleeping 7 seconds\n");
153 tbsleep(7);
154
155 //----------------------------------------------------------------------------
156 // Spawn threads to thest the errorcheck mutex
157 //----------------------------------------------------------------------------
158 void *(*errChkFunc[2])(void *) = {
159 thread_func_errorcheck1, thread_func_errorcheck2 };
160 tbprint("---\n");
161 tbprint("[thread main] Testing errorcheck mutex\n");
162 for(int i = 0; i < 2; ++i) {
163 st = tbthread_create(&thread[i], &attr, errChkFunc[i], &mutex_errorcheck);
164 if(st != 0) {
165 tbprint("Failed to spawn thread %d: %s\n", i, tbstrerror(-st));
166 goto exit;
167 }
168 tbthread_detach(thread[i]);
169 }
170
171 tbprint("[thread main] Threads spawned successfully\n");
172 tbprint("[thread main] Sleeping 5 seconds\n");
173 tbsleep(5);
174
175 //----------------------------------------------------------------------------
176 // Spawn the threads to test the recursive mutex
177 //----------------------------------------------------------------------------
178 tbprint("---\n");
179 tbprint("[thread main] Testing recursive mutex\n");
180 tbthread_attr_init(&attr);
181 for(int i = 0; i < 5; ++i) {
182 st = tbthread_create(&thread[i], &attr, thread_func_recursive,
183 &mutex_recursive);
184 if(st != 0) {
185 tbprint("Failed to spawn thread %d: %s\n", i, tbstrerror(-st));
186 goto exit;
187 }
188 tbthread_detach(thread[i]);
189 }
190
191 tbprint("[thread main] Threads spawned successfully\n");
192 tbprint("[thread main] Sleeping 7 seconds\n");
193 tbsleep(7);
194
195exit:
196 tbthread_finit();
197 return st;
198};
199