fix identify_loops so that it actually identifies loops
[ajla.git] / th_com.inc
blob4d2b56a0db42eb92d43dfd97d577bdf5a620022c
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #ifdef DEBUG_OBJECT_POSSIBLE
20 #include "obj_reg.h"
21 #endif
23 #ifdef DEBUG_OBJECT_POSSIBLE
24 static bool mutex_debug = false;
25 static bool thread_debug = false;
26 #else
27 static const bool mutex_debug = false;
28 static const bool thread_debug = false;
29 #endif
31 #if defined(DEBUG_OBJECT_POSSIBLE) || !defined(THREAD_NONE)
33 void mutex_init_position(mutex_t *m argument_position)
35         if (unlikely(mutex_debug))
36                 obj_registry_insert(OBJ_TYPE_MUTEX, ptr_to_num((void *)m), position_arg);
37         do_mutex_init(m);
40 void mutex_done_position(mutex_t *m argument_position)
42         if (unlikely(mutex_debug))
43                 obj_registry_remove(OBJ_TYPE_MUTEX, ptr_to_num((void *)m), position_arg);
44         do_mutex_done(m);
47 void attr_fastcall mutex_lock_position(mutex_t *m argument_position)
49         if (unlikely(mutex_debug))
50                 obj_registry_verify(OBJ_TYPE_MUTEX, ptr_to_num((void *)m), position_arg);
51         do_mutex_lock(m);
54 bool attr_fastcall mutex_trylock_position(mutex_t *m argument_position)
56         if (unlikely(mutex_debug))
57                 obj_registry_verify(OBJ_TYPE_MUTEX, ptr_to_num((void *)m), position_arg);
58         do_mutex_trylock(m);
59         not_reached();
60         return false;
63 void attr_fastcall mutex_unlock_position(mutex_t *m argument_position)
65         if (unlikely(mutex_debug))
66                 obj_registry_verify(OBJ_TYPE_MUTEX, ptr_to_num((void *)m), position_arg);
67         do_mutex_unlock(m);
70 #endif
73 #if defined(DEBUG_OBJECT_POSSIBLE) || !defined(THREAD_NONE)
75 void rwmutex_init_position(rwmutex_t *m argument_position)
77         if (unlikely(mutex_debug))
78                 obj_registry_insert(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
79         do_rwmutex_init(m);
82 void rwmutex_done_position(rwmutex_t *m argument_position)
84         if (unlikely(mutex_debug))
85                 obj_registry_remove(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
86         do_rwmutex_done(m);
89 void attr_fastcall rwmutex_lock_read_position(rwmutex_t *m argument_position)
91         if (unlikely(mutex_debug))
92                 obj_registry_verify(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
93         do_rwmutex_lock_read(m);
96 void attr_fastcall rwmutex_unlock_read_position(rwmutex_t *m argument_position)
98         if (unlikely(mutex_debug))
99                 obj_registry_verify(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
100         do_rwmutex_unlock_read(m);
103 void attr_fastcall rwmutex_lock_write_position(rwmutex_t *m argument_position)
105         if (unlikely(mutex_debug))
106                 obj_registry_verify(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
107         do_rwmutex_lock_write(m);
110 void attr_fastcall rwmutex_unlock_write_position(rwmutex_t *m argument_position)
112         if (unlikely(mutex_debug))
113                 obj_registry_verify(OBJ_TYPE_RWMUTEX, ptr_to_num((void *)m), position_arg);
114         do_rwmutex_unlock_write(m);
117 #endif
120 #if defined(DEBUG_OBJECT_POSSIBLE) || !defined(THREAD_NONE)
122 void cond_init_position(cond_t *c argument_position)
124         if (unlikely(mutex_debug))
125                 obj_registry_insert(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
126         do_cond_init(c);
129 void cond_done_position(cond_t *c argument_position)
131         if (unlikely(mutex_debug))
132                 obj_registry_remove(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
133         do_cond_done(c);
136 void attr_fastcall cond_lock_position(cond_t *c argument_position)
138         if (unlikely(mutex_debug))
139                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
140         do_cond_lock(c);
143 void attr_fastcall cond_unlock_position(cond_t *c argument_position)
145         if (unlikely(mutex_debug))
146                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
147         do_cond_unlock(c);
150 void attr_fastcall cond_unlock_signal_position(cond_t *c argument_position)
152         if (unlikely(mutex_debug))
153                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
154         do_cond_unlock_signal(c);
157 void attr_fastcall cond_unlock_broadcast_position(cond_t *c argument_position)
159         if (unlikely(mutex_debug))
160                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
161         do_cond_unlock_broadcast(c);
164 void attr_fastcall cond_wait_position(cond_t *c argument_position)
166         if (unlikely(mutex_debug))
167                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
168         do_cond_wait(c);
171 bool attr_fastcall cond_wait_us_position(cond_t *c, uint32_t us argument_position)
173         if (unlikely(mutex_debug))
174                 obj_registry_verify(OBJ_TYPE_COND, ptr_to_num(c), position_arg);
175         do_cond_wait_us(c, us);
176         not_reached();
177         return false;
180 #endif
183 #ifndef THREAD_NONE
184 bool thread_spawn_position(thread_t *t, thread_function_t *function, void *arg, thread_priority_t attr_unused priority, ajla_error_t *err argument_position)
186         do_thread_spawn(t, function, arg, priority, err);
187         if (unlikely(thread_debug) && sizeof(thread_t) <= sizeof(obj_id)) {
188                 obj_id id = 0;
189                 memcpy(&id, t, sizeof(thread_t));
190                 obj_registry_insert(OBJ_TYPE_THREAD, id, position_arg);
191         }
192         return true;
195 void thread_join_position(thread_t *t argument_position)
197         if (unlikely(thread_debug) && sizeof(thread_t) <= sizeof(obj_id)) {
198                 obj_id id = 0;
199                 memcpy(&id, t, sizeof(thread_t));
200                 obj_registry_remove(OBJ_TYPE_THREAD, id, position_arg);
201         }
202         do_thread_join(t);
204 #endif
207 #if defined(HAVE___THREAD)
208 #define do_tls_init(m)          do { } while (0)
209 #define do_tls_done(m)          do { } while (0)
210 #endif
212 void tls_init__position(tls_t_ attr_unused *m argument_position)
214         if (unlikely(mutex_debug))
215                 obj_registry_insert(OBJ_TYPE_TLS, ptr_to_num(m), position_arg);
216         do_tls_init(m);
219 void tls_done__position(tls_t_ attr_unused *m argument_position)
221         if (unlikely(mutex_debug))
222                 obj_registry_remove(OBJ_TYPE_TLS, ptr_to_num(m), position_arg);
223         do_tls_done(m);
226 #if !defined(HAVE___THREAD)
228 uintptr_t attr_fastcall tls_get__position(const tls_t_ *m argument_position)
230         uintptr_t ret;
231         if (unlikely(mutex_debug))
232                 obj_registry_verify(OBJ_TYPE_TLS, ptr_to_num(m), position_arg);
233         do_tls_get(m, &ret);
234         return ret;
237 void attr_fastcall tls_set__position(const tls_t_ *m, uintptr_t val argument_position)
239         if (unlikely(mutex_debug))
240                 obj_registry_verify(OBJ_TYPE_TLS, ptr_to_num(m), position_arg);
241         do_tls_set(m, val);
244 uintptr_t attr_fastcall tls_get__nocheck(const tls_t_ *m)
246 #ifdef DEBUG_TRACK_FILE_LINE
247         const char attr_unused *position_arg = "tls_get__nocheck";
248 #endif
249         uintptr_t ret;
250         do_tls_get(m, &ret);
251         return ret;
254 void attr_fastcall tls_set__nocheck(const tls_t_ *m, uintptr_t val)
256 #ifdef DEBUG_TRACK_FILE_LINE
257         const char attr_unused *position_arg = "tls_set__nocheck";
258 #endif
259         do_tls_set(m, val);
262 #endif
265 #ifndef THREAD_NONE
267 static tls_decl(tls_destructor_t *, tls_destructors);
269 void tls_destructor_position(tls_destructor_t *destr, tls_destructor_fn *fn argument_position)
271         destr->fn = fn;
272         destr->previous = tls_get(tls_destructor_t *, tls_destructors);
273         tls_set(tls_destructor_t *, tls_destructors, destr);
276 void tls_destructor_call(void)
278         tls_destructor_t *destr;
279         while ((destr = tls_get(tls_destructor_t *, tls_destructors))) {
280                 tls_set(tls_destructor_t *, tls_destructors, destr->previous);
281                 destr->fn(destr);
282         }
285 #ifdef DEBUG_TRACE
286 static tls_decl(int, thread_id);
288 void thread_set_id(int id)
290         tls_set(int, thread_id, id);
293 int thread_get_id(void)
295         return tls_get(int, thread_id);
297 #endif
299 static void thread_common_init(void)
301         tls_init(tls_destructor_t *, tls_destructors);
302 #ifdef DEBUG_TRACE
303         tls_init(int, thread_id);
304 #endif
307 static void thread_common_done(void)
309         tls_destructor_call();
310         tls_done(tls_destructor_t *, tls_destructors);
311 #ifdef DEBUG_TRACE
312         tls_done(int, thread_id);
313 #endif
316 #endif
319 bool thread_enable_debugging_option(const char *option, size_t l)
321 #ifndef DEBUG_OBJECT_POSSIBLE
322         bool attr_unused mutex_debug = false;
323         bool attr_unused thread_debug = false;
324 #endif
325         if (!option)
326                 mutex_debug = thread_debug = true;
327         else if (l == 5 && !strncmp(option, "mutex", 5))
328                 mutex_debug = true;
329         else if (l == 16 && !strncmp(option, "mutex-errorcheck", 16))
330                 mutex_debug = true;
331         else if (l == 6 && !strncmp(option, "thread", 6))
332                 thread_debug = true;
333         else
334                 return false;
335 #if defined(OS_OS2) || defined(OS_WIN32)
336         mutex_debug = false;
337 #endif
338         return true;