1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup threading mutexes, ...
36 * @ingroup dnscore
37 * @brief
38 *
39 * @{
40 *
41 *----------------------------------------------------------------------------*/
42
43 // CentOS 5.9 requires this to have PTHREAD_MUTEX_RECURSIVE
44 #define _GNU_SOURCE 1
45
46 #include "dnscore/dnscore-config.h"
47 #include "dnscore/thread.h"
48
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include "dnscore/ptr_set.h"
52 #include "dnscore/timems.h"
53 #include "dnscore/bytezarray_output_stream.h"
54 #include "dnscore/format.h"
55 #include "dnscore/thread-tag.h"
56 #include "dnscore/process.h"
57
58 #if __OpenBSD__
59 #error "OpenBSD doesn't handle PTHREAD_PROCESS_SHARED"
60 #endif
61
62 #include "dnscore/logger.h"
63
64 #include "dnscore/mutex.h"
65
66 // export TSAN_OPTIONS=detect_deadlocks=1:second_deadlock_stack=1
67 // -sanitize=thread
68
69 #define MTXCOBJ_TAG 0x4a424f4358544d
70 #define MTXCPT_TAG 0x54504358544d
71 #define MTXCTHRD_TAG 0x445248544358544d
72 #define MTXCMON_TAG 0x4e4f4d5358544d
73
74 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
75 static void
mutex_debug_logger_handle_msg(const void * handle,u32 level,const char * fmt,...)76 mutex_debug_logger_handle_msg(const void* handle, u32 level, const char* fmt, ...)
77 {
78 (void)handle;
79 (void)level;
80
81 format("%llT | %i | %p | ", timeus(), getpid(), thread_self());
82
83 output_stream baos;
84 bytezarray_output_stream_context baos_context;
85
86 va_list args;
87 va_start(args, fmt);
88 u8 text_buffer[512];
89 bytezarray_output_stream_init_ex_static(&baos, text_buffer, sizeof(text_buffer), 0, &baos_context);
90
91 if(FAIL(vosformat(&baos, fmt, args)))
92 {
93 bytezarray_output_stream_reset(&baos);
94 osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
95 }
96
97 //output_stream_write_u8(&baos, 0);
98 output_stream_write(termout, bytezarray_output_stream_buffer(&baos), bytezarray_output_stream_buffer_offset(&baos));
99 output_stream_write_u8(termout, (u8)'\n');
100 }
101 #endif
102
103 void
mutex_debug_stacktrace_log(void * handle,u32 level,stacktrace trace)104 mutex_debug_stacktrace_log(void* handle, u32 level, stacktrace trace)
105 {
106 (void)handle;
107 (void)level;
108 debug_stacktrace_print(termout, trace);
109 output_stream_write_u8(termout, (u8)'\n');
110 }
111
112 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
113 static void
mutex_debug_log_stacktrace(void * handle,u32 level,const char * prefix)114 mutex_debug_log_stacktrace(void* handle, u32 level, const char *prefix)
115 {
116 println(prefix);
117 stacktrace trace = debug_stacktrace_get();
118 mutex_debug_stacktrace_log(handle, level, trace);
119 }
120
121 #define logger_handle_msg mutex_debug_logger_handle_msg
122 #define debug_stacktrace_log mutex_debug_stacktrace_log
123 #define debug_log_stacktrace mutex_debug_log_stacktrace
124 #define logger_flush flushout
125
126 #define MODULE_MSG_HANDLE NULL
127 #define LOG_TEXT_PREFIX ""
128 #define MSG_DEBUG7 0
129 #define MSG_DEBUG6 0
130 #define MSG_DEBUG5 0
131 #define MSG_DEBUG4 0
132 #define MSG_DEBUG3 0
133 #define MSG_DEBUG2 0
134 #define MSG_DEBUG1 0
135 #define MSG_DEBUG 0
136 #define MSG_WARNING 0
137 #define MSG_ERR 0
138
139 #define log_debug7(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
140 #define log_debug6(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
141 #define log_debug5(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
142 #define log_debug4(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
143 #define log_debug3(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
144 #define log_debug2(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
145 #define log_debug1(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
146 #define log_debug(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
147 #define log_notice(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
148 #define log_info(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
149 #define log_warn(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
150 #define log_err(...) logger_handle_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
151
152 #define log_try_debug7(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
153 #define log_try_debug6(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
154 #define log_try_debug5(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
155 #define log_try_debug4(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
156 #define log_try_debug3(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
157 #define log_try_debug2(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
158 #define log_try_debug1(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
159 #define log_try_debug(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
160 #define log_try_notice(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
161 #define log_try_info(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
162 #define log_try_warn(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
163 #define log_try_err(...) logger_handle_try_msg(0,0,LOG_TEXT_PREFIX __VA_ARGS__)
164 #endif
165
166 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
167
168 volatile bool mutex_ultraverbose = FALSE;
169 //volatile bool mutex_ultraverbose = TRUE;
170
171 #if MUTEX_CONTENTION_MONITOR
172
173 struct mutex_contention_point_s
174 {
175 stacktrace st; // stack trace to that point
176 s64 lock_wait; // time spent waiting for the lock (but successfully acquired)
177 s64 lock_loops; // loops made before acquiring the lock
178 s64 owner_time; // time spent owning that mutex on that stack trace
179 s64 use_count;
180 s64 lock_fail; // try-locks that failed
181 };
182
183 typedef struct mutex_contention_point_s mutex_contention_point_t;
184
185 struct mutex_contention_object_s
186 {
187 void *mutex;
188 ptr_set threads; // set of mutex_contention_monitor
189 bool recursive;
190 };
191
192 typedef struct mutex_contention_object_s mutex_contention_object_t;
193
194 typedef ptr_set mutex_contention_thread_t;
195
196 struct mutex_contention_monitor_s
197 {
198 thread_t owning_thread;
199 mutex_contention_point_t *contention_point;
200 //
201 mutex_contention_object_t *mutex_object;
202 mutex_contention_thread_t *mutex_thread;
203 const char *type_name;
204 s64 lock_begin_timestamp;
205 s64 lock_wait_loops;
206 s64 lock_end_timestamp; // 0 until the mutex is acquired
207 s32 multi_lock_count;
208 pid_t pid;
209 bool used_by_condition; // true means not really locked
210 };
211
212 typedef struct mutex_contention_monitor_s mutex_contention_monitor_t;
213
mutex_contention_monitor_lock_count_inc(mutex_contention_monitor_t * mcm)214 void mutex_contention_monitor_lock_count_inc(mutex_contention_monitor_t *mcm)
215 {
216 //log_info("mutex_contention_monitor_lock_count_inc(%p) (%i -> %i)", mcm, mcm->multi_lock_count, mcm->multi_lock_count + 1);
217 ++mcm->multi_lock_count;
218 }
219
mutex_contention_monitor_lock_count_dec(mutex_contention_monitor_t * mcm)220 bool mutex_contention_monitor_lock_count_dec(mutex_contention_monitor_t *mcm)
221 {
222 //log_info("mutex_contention_monitor_lock_count_dec(%p) (%i -> %i)", mcm, mcm->multi_lock_count, mcm->multi_lock_count - 1);
223 assert(mcm->multi_lock_count > 0);
224
225 return (--mcm->multi_lock_count == 0);
226 }
227
228 static pthread_mutex_t mutex_contention_mtx = PTHREAD_MUTEX_INITIALIZER;
229 static ptr_set mutex_contention_mutex_to_threads_set = PTR_SET_PTR_EMPTY; // mutex -> mutex_contention_object_t
230 static ptr_set mutex_contention_stacktrace_to_point_set = PTR_SET_EMPTY; // stacktrace -> mutex_contention_point_t
231 static ptr_set mutex_contention_thread_to_monitor_set = PTR_SET_EMPTY;
232 // thread -> mutex_contention_monitor_t
233
234 static const char *mutex_type_name = "mutex_lock";
235 static const char *group_mutex_type_name = "group_mutex_lock";
236 static const char *shared_group_mutex_type_name = "shared_group_mutex_lock";
237
mutex_contention_object_create(void * mutex_ptr,bool recursive)238 void mutex_contention_object_create(void *mutex_ptr, bool recursive)
239 {
240 mutex_contention_object_t *mcu;
241 pthread_mutex_lock(&mutex_contention_mtx);
242 ptr_node *mutex_node = ptr_set_insert(&mutex_contention_mutex_to_threads_set, mutex_ptr);
243 if(mutex_node->value == NULL)
244 {
245 MALLOC_OBJECT_OR_DIE(mcu, mutex_contention_object_t, MTXCOBJ_TAG);
246 mcu->mutex = mutex_ptr;
247 ptr_set_init(&mcu->threads);
248 mcu->threads.compare = ptr_set_ptr_node_compare;
249 mcu->recursive = recursive;
250 }
251 else
252 {
253 logger_flush();
254 abort(); // already exists
255 }
256 pthread_mutex_unlock(&mutex_contention_mtx);
257 }
258
mutex_contention_object_destroy(void * mutex_ptr)259 void mutex_contention_object_destroy(void *mutex_ptr)
260 {
261 pthread_mutex_lock(&mutex_contention_mtx);
262 ptr_node *mutex_node = ptr_set_find(&mutex_contention_mutex_to_threads_set, mutex_ptr);
263 if(mutex_node != NULL)
264 {
265 if(mutex_node->value != NULL)
266 {
267 mutex_contention_object_t *mcu = (mutex_contention_object_t*)mutex_node->value;
268 s64 now = timeus();
269
270 if(!ptr_set_isempty(&mcu->threads))
271 {
272 ptr_set_iterator iter;
273 ptr_set_iterator_init(&mcu->threads, &iter);
274 while(ptr_set_iterator_hasnext(&iter))
275 {
276 ptr_node *node = ptr_set_iterator_next_node(&iter);
277 mutex_contention_monitor_t* other_mcm = (mutex_contention_monitor_t*)node->value;
278
279 if(other_mcm->lock_end_timestamp == 0)
280 {
281 s64 other_wait_time = (now - other_mcm->lock_begin_timestamp);
282 log_err("mutex-monitor: unsafe destruction: thread %p has also been waiting for mutex @%p for %llius (looped %lli)",
283 other_mcm->owning_thread, other_mcm->mutex_object->mutex, other_wait_time, other_mcm->lock_wait_loops);
284 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, other_mcm->contention_point->st);
285 }
286 else
287 {
288 s64 other_wait_time = (now - other_mcm->lock_end_timestamp);
289 log_err("mutex-monitor: unsafe destruction: thread %p has been owning the mutex @%p for %llius (a)",
290 other_mcm->owning_thread, other_mcm->mutex_object->mutex, other_wait_time, other_mcm->lock_wait_loops);
291 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, other_mcm->contention_point->st);
292 }
293 }
294
295 logger_flush();
296 abort();
297 }
298 }
299
300 ptr_set_delete(&mutex_contention_mutex_to_threads_set, mutex_ptr);
301 }
302 else
303 {
304 abort(); // already exists
305 }
306 pthread_mutex_unlock(&mutex_contention_mtx);
307 }
308
309 mutex_contention_monitor_t *
mutex_contention_lock_begin(thread_t thread,void * mutex_ptr,stacktrace st,const char * type_name)310 mutex_contention_lock_begin(thread_t thread, void *mutex_ptr, stacktrace st, const char *type_name)
311 {
312 mutex_contention_object_t *mco;
313 mutex_contention_point_t *mcp;
314 mutex_contention_thread_t *mct;
315 mutex_contention_monitor_t *mcm;
316
317 pthread_mutex_lock(&mutex_contention_mtx);
318
319 // insert/find mutex contention users
320 // mutex->currently locking threads
321
322 ptr_node *mutex_node = ptr_set_insert(&mutex_contention_mutex_to_threads_set, mutex_ptr);
323 if(mutex_node->value != NULL)
324 {
325 mco = (mutex_contention_object_t*)mutex_node->value;
326 }
327 else
328 {
329 log_info("mutex monitor: %p has not been passed to mutex_contention_object_create(void*,bool): static?", mutex_ptr);
330
331 MALLOC_OBJECT_OR_DIE(mco, mutex_contention_object_t, MTXCOBJ_TAG);
332 mco->mutex = mutex_ptr;
333 ptr_set_init(&mco->threads);
334 mco->threads.compare = ptr_set_ptr_node_compare;
335 mco->recursive = FALSE;
336 mutex_node->value = mco;
337 }
338
339 // insert/find mutex contention points
340 // stacktrace->lock statistics
341
342 ptr_node *contention_node = ptr_set_insert(&mutex_contention_stacktrace_to_point_set, st);
343 if(contention_node->value != NULL)
344 {
345 mcp = (mutex_contention_point_t*)contention_node->value;
346 }
347 else
348 {
349 MALLOC_OBJECT_OR_DIE(mcp, mutex_contention_point_t, MTXCPT_TAG);
350 mcp->st = st;
351 mcp->lock_wait = 0;
352 mcp->lock_loops = 0;
353 mcp->owner_time = 0;
354 mcp->use_count = 0;
355 mcp->lock_fail = 0;
356 contention_node->value = mcp;
357 }
358
359 ++mcp->use_count;
360
361 // insert/find threads using mutexes
362 // thread->monitored mutexes set
363
364 ptr_node *thread_node = ptr_set_insert(&mutex_contention_thread_to_monitor_set, (void*)thread);
365
366 if(thread_node->value != NULL)
367 {
368 mct = (mutex_contention_thread_t*)thread_node->value;
369 }
370 else
371 {
372 MALLOC_OBJECT_OR_DIE(mct, mutex_contention_thread_t, MTXCTHRD_TAG);
373 ptr_set_init(mct);
374 mct->compare = ptr_set_ptr_node_compare;
375 thread_node->value = mct;
376 }
377
378 // insert/find mutexes in the thread monitored set
379
380 ptr_node *monitor_node = ptr_set_insert(mct, st);
381 if(monitor_node->value != NULL)
382 {
383 mcm = (mutex_contention_monitor_t*)monitor_node->value;
384 // double lock ... ?
385 mutex_contention_monitor_lock_count_inc(mcm);
386 }
387 else
388 {
389 MALLOC_OBJECT_OR_DIE(mcm, mutex_contention_monitor_t, MTXCMON_TAG);
390 mcm->owning_thread = thread;
391 mcm->contention_point = mcp;
392 mcm->mutex_object = mco;
393 mcm->mutex_thread = mct;
394 mcm->type_name = type_name;
395 mcm->lock_begin_timestamp = timeus();
396 mcm->lock_end_timestamp = 0;
397 mcm->lock_wait_loops = 0;
398 mcm->multi_lock_count = 1;
399 mcm->pid = getpid_ex();
400 monitor_node->value = mcm;
401 mcm->used_by_condition = FALSE;
402 }
403
404 ptr_node *user_thread_node = ptr_set_insert(&mco->threads, (void*)thread);
405 if(user_thread_node->value == NULL)
406 {
407 user_thread_node->value = mcm;
408 }
409 else
410 {
411 mutex_contention_monitor_t *old_mcm = (mutex_contention_monitor_t*)user_thread_node->value;
412 log_err("lock monitor: mutex %p already locked by %p (old@%p now@%p)", mutex_ptr, old_mcm->lock_begin_timestamp, old_mcm, mcm);
413 log_err("lock monitor: locked by");
414 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_ERR, old_mcm->contention_point->st);
415 log_err("lock monitor: failed by");
416 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_ERR, mcm->contention_point->st);
417
418 debug_stacktrace_print(termout, old_mcm->contention_point->st);
419 debug_stacktrace_print(termout, mcm->contention_point->st);
420 logger_flush();
421 flushout();
422 assert(user_thread_node->value == mcm);
423 }
424
425 pthread_mutex_unlock(&mutex_contention_mtx);
426
427 return mcm;
428 }
429
mutex_contention_lock_wait(mutex_contention_monitor_t * mcm)430 void mutex_contention_lock_wait(mutex_contention_monitor_t *mcm)
431 {
432 // insert/find mutex_contention_users
433
434 pthread_mutex_lock(&mutex_contention_mtx);
435 ++mcm->lock_end_timestamp;
436
437 if(mutex_contention_monitor_lock_count_dec(mcm))
438 {
439 mcm->contention_point->owner_time += timeus() - mcm->lock_end_timestamp;
440
441 mcm->used_by_condition = TRUE;
442 }
443
444 pthread_mutex_unlock(&mutex_contention_mtx);
445 }
446
mutex_contention_lock_wait_with_mutex(thread_t thread,void * mutex_ptr)447 void mutex_contention_lock_wait_with_mutex(thread_t thread, void *mutex_ptr)
448 {
449 mutex_contention_object_t *mco;
450 mutex_contention_monitor_t *mcm;
451
452 pthread_mutex_lock(&mutex_contention_mtx);
453
454 ptr_node *mutex_node = ptr_set_find(&mutex_contention_mutex_to_threads_set, mutex_ptr);
455 if(mutex_node == NULL)
456 {
457 log_err("mutex monitor: can't wait on %p as it has not been passed to mutex_contention_object_create(void*,bool)");
458 abort();
459 }
460
461 mco = (mutex_contention_object_t*)mutex_node->value;
462
463 ptr_node *monitor_node = ptr_set_find(&mco->threads, (void*)thread);
464 if(monitor_node == NULL)
465 {
466 log_err("mutex monitor: can't wait on %p as it's not used by thread %p", thread);
467 abort();
468 }
469
470 mcm = (mutex_contention_monitor_t*)monitor_node->value;
471
472 if(mutex_contention_monitor_lock_count_dec(mcm))
473 {
474 mcm->contention_point->owner_time += timeus() - mcm->lock_end_timestamp;
475 }
476
477 mcm->used_by_condition = TRUE;
478
479 pthread_mutex_unlock(&mutex_contention_mtx);
480 }
481
mutex_contention_lock_resume(mutex_contention_monitor_t * mcm)482 void mutex_contention_lock_resume(mutex_contention_monitor_t *mcm)
483 {
484 // insert/find mutex_contention_users
485
486 pthread_mutex_lock(&mutex_contention_mtx);
487 ++mcm->lock_end_timestamp;
488 mutex_contention_monitor_lock_count_inc(mcm);
489 mcm->used_by_condition = FALSE;
490 pthread_mutex_unlock(&mutex_contention_mtx);
491 }
492
mutex_contention_lock_resume_with_mutex(thread_t thread,void * mutex_ptr)493 void mutex_contention_lock_resume_with_mutex(thread_t thread, void *mutex_ptr)
494 {
495 mutex_contention_object_t *mco;
496 mutex_contention_monitor_t *mcm;
497
498 pthread_mutex_lock(&mutex_contention_mtx);
499
500 ptr_node *mutex_node = ptr_set_find(&mutex_contention_mutex_to_threads_set, mutex_ptr);
501 if(mutex_node == NULL)
502 {
503 log_err("mutex monitor: can't wait on %p as it has not been passed to mutex_contention_object_create(void*,bool)");
504 abort();
505 }
506
507 mco = (mutex_contention_object_t*)mutex_node->value;
508
509 ptr_node *monitor_node = ptr_set_find(&mco->threads, (void*)thread);
510 if(monitor_node == NULL)
511 {
512 log_err("mutex monitor: can't wait on %p as it's not used by thread %p", thread);
513 abort();
514 }
515
516 mcm = (mutex_contention_monitor_t*)monitor_node->value;
517
518 assert(mcm->used_by_condition);
519
520 mutex_contention_monitor_lock_count_inc(mcm);
521 mcm->used_by_condition = FALSE;
522
523 pthread_mutex_unlock(&mutex_contention_mtx);
524 }
525
mutex_contention_lock_end(mutex_contention_monitor_t * mcm)526 void mutex_contention_lock_end(mutex_contention_monitor_t *mcm)
527 {
528 pthread_mutex_lock(&mutex_contention_mtx);
529
530 mcm->lock_end_timestamp = timeus();
531
532 s64 wait_time = mcm->lock_end_timestamp - mcm->lock_begin_timestamp;
533
534 mcm->contention_point->lock_wait += wait_time;
535 mcm->contention_point->lock_loops += mcm->lock_wait_loops;
536
537 pthread_mutex_unlock(&mutex_contention_mtx);
538 }
539
mutex_contention_lock_fail(mutex_contention_monitor_t * mcm)540 void mutex_contention_lock_fail(mutex_contention_monitor_t *mcm)
541 {
542 pthread_mutex_lock(&mutex_contention_mtx);
543
544 mcm->lock_end_timestamp = timeus();
545
546 s64 wait_time = mcm->lock_end_timestamp - mcm->lock_begin_timestamp;
547
548 mcm->contention_point->lock_wait += wait_time;
549 mcm->contention_point->lock_loops += mcm->lock_wait_loops;
550 ++mcm->contention_point->lock_fail;
551
552 pthread_mutex_unlock(&mutex_contention_mtx);
553 }
554
mutex_contention_unlock(thread_t thread,void * mutex_ptr)555 void mutex_contention_unlock(thread_t thread, void *mutex_ptr)
556 {
557 mutex_contention_object_t *mco;
558 mutex_contention_monitor_t *mcm;
559
560 pthread_mutex_lock(&mutex_contention_mtx);
561
562 ptr_node *mutex_node = ptr_set_find(&mutex_contention_mutex_to_threads_set, mutex_ptr);
563 if(mutex_node == NULL)
564 {
565 log_err("mutex monitor: can't unlock %p as it has not been passed to mutex_contention_object_create(void*,bool)");
566 abort();
567 }
568
569 mco = (mutex_contention_object_t*)mutex_node->value;
570
571 ptr_node *monitor_node = ptr_set_find(&mco->threads, (void*)thread);
572 if(monitor_node == NULL)
573 {
574 log_err("mutex monitor: can't unlock %p as it's not used by thread %p", thread);
575 abort();
576 }
577
578 mcm = (mutex_contention_monitor_t*)monitor_node->value;
579
580 if(mutex_contention_monitor_lock_count_dec(mcm))
581 {
582 mcm->contention_point->owner_time += timeus() - mcm->lock_end_timestamp;
583
584 ptr_set_delete(&mco->threads, (void*)mcm->owning_thread);
585 ptr_set_delete(mcm->mutex_thread, mcm->contention_point->st);
586
587 free(mcm);
588 }
589 else
590 {
591 log_info("mutex monitor: mcm@%p multi_lock_count = %i", mcm, mcm->multi_lock_count);
592 logger_flush();
593 flushout();
594 }
595
596 pthread_mutex_unlock(&mutex_contention_mtx);
597 }
598
mutex_contention_unlock_with_monitor(mutex_contention_monitor_t * mcm)599 void mutex_contention_unlock_with_monitor(mutex_contention_monitor_t *mcm)
600 {
601 pthread_mutex_lock(&mutex_contention_mtx);
602
603 thread_t tid = thread_self();
604
605 if(mcm->owning_thread != tid)
606 {
607 log_err("mutex-monitor: locked with %p, unlocked with %p", mcm->owning_thread, tid);
608 }
609
610 if(mutex_contention_monitor_lock_count_dec(mcm))
611 {
612 mcm->contention_point->owner_time += timeus() - mcm->lock_end_timestamp;
613
614 ptr_set_delete(&mcm->mutex_object->threads, (void*)mcm->owning_thread);
615
616 ptr_set_delete(mcm->mutex_thread, mcm->contention_point->st);
617
618 free(mcm);
619 }
620
621 pthread_mutex_unlock(&mutex_contention_mtx);
622 }
623
624 static smp_int mutex_contention_monitor_thread_should_stop = SMP_INT_INITIALIZER_AT(0);
625 static pthread_mutex_t mutex_contention_monitor_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
626 static thread_t mutex_contention_monitor_thread_id = 0;
627
628 static void*
mutex_contention_monitor_thread(void * args_)629 mutex_contention_monitor_thread(void* args_)
630 {
631 (void)args_;
632
633 while(smp_int_get(&mutex_contention_monitor_thread_should_stop) == 0)
634 {
635 pthread_mutex_lock(&mutex_contention_mtx);
636
637 ptr_set_iterator thread_iter;
638 ptr_set_iterator monitor_iter;
639 ptr_set_iterator other_iter;
640 ptr_set_iterator_init(&mutex_contention_thread_to_monitor_set, &thread_iter);
641
642 log_info("mutex-monitor: tick");
643
644 while(ptr_set_iterator_hasnext(&thread_iter))
645 {
646 s64 now = timeus();
647
648 ptr_node *thread_node = ptr_set_iterator_next_node(&thread_iter);
649 mutex_contention_thread_t *mct = (mutex_contention_thread_t*)thread_node->value;
650
651 ptr_set_iterator_init(mct, &monitor_iter);
652 while(ptr_set_iterator_hasnext(&monitor_iter))
653 {
654 ptr_node *monitor_node = ptr_set_iterator_next_node(&monitor_iter);
655 mutex_contention_monitor_t *mcm = (mutex_contention_monitor_t*)monitor_node->value;
656
657 if(mcm->lock_end_timestamp == 0)
658 {
659 s64 wait_time = (now - mcm->lock_begin_timestamp);
660
661 if(wait_time >= MUTEX_LOCKED_TOO_MUCH_TIME_US)
662 {
663 // not fine at all
664 // tell this thread has been waiting for this node for quite some time
665 // tell who is owning the mutex and since when
666 log_warn("mutex-monitor: thread %p (%s) has been waiting for mutex @%p for %llius (looped %lli)",
667 mcm->owning_thread, thread_get_tag_with_pid_and_tid(getpid_ex(), mcm->owning_thread),
668 mcm->mutex_object->mutex, wait_time, mcm->lock_wait_loops);
669 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, mcm->contention_point->st);
670
671 ptr_set_iterator_init(&mcm->mutex_object->threads, &other_iter);
672 while(ptr_set_iterator_hasnext(&other_iter))
673 {
674 ptr_node *other_node = ptr_set_iterator_next_node(&other_iter);
675 mutex_contention_monitor_t* other_mcm = (mutex_contention_monitor_t*)other_node->value;
676
677 if(other_mcm->lock_end_timestamp == 0)
678 {
679 s64 other_wait_time = (now - other_mcm->lock_begin_timestamp);
680 log_warn("mutex-monitor: thread %p (%s) has also been waiting for mutex @%p for %llius (looped %lli)",
681 other_mcm->owning_thread, thread_get_tag_with_pid_and_tid(getpid_ex(), other_mcm->owning_thread),
682 other_mcm->mutex_object->mutex, other_wait_time, other_mcm->lock_wait_loops);
683 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, other_mcm->contention_point->st);
684 }
685 else
686 {
687 s64 other_wait_time = (now - other_mcm->lock_end_timestamp);
688 log_warn("mutex-monitor: thread %p (%s) has been owning the mutex @%p for %llius (b)",
689 other_mcm->owning_thread, thread_get_tag_with_pid_and_tid(getpid_ex(), other_mcm->owning_thread),
690 other_mcm->mutex_object->mutex, other_wait_time, other_mcm->lock_wait_loops);
691 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, other_mcm->contention_point->st);
692 }
693 }
694 }
695 }
696 else
697 {
698 if(!mcm->used_by_condition)
699 {
700 s64 lock_time = (now - mcm->lock_end_timestamp);
701
702 if(lock_time >= MUTEX_LOCKED_TOO_MUCH_TIME_US)
703 {
704 log_warn("mutex-monitor: thread %p (%s) has been owning the mutex @%p for %llius (looped %lli) (a long time)",
705 mcm->owning_thread, thread_get_tag_with_pid_and_tid(getpid_ex(), mcm->owning_thread),
706 mcm->mutex_object->mutex, lock_time, mcm->lock_wait_loops);
707 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, mcm->contention_point->st);
708 }
709 }
710 else
711 {
712 // mutex is used by a condition
713
714 s64 wait_time = (now - mcm->lock_end_timestamp);
715
716 if(wait_time >= MUTEX_WAITED_TOO_MUCH_TIME_US)
717 {
718 log_warn("mutex-monitor: thread %p (%s) has been waiting for %llius (looped %lli) (a long time)",
719 mcm->owning_thread, thread_get_tag_with_pid_and_tid(getpid_ex(), mcm->owning_thread),
720 wait_time, mcm->lock_wait_loops);
721 mutex_debug_stacktrace_log(MODULE_MSG_HANDLE, MSG_WARNING, mcm->contention_point->st);
722 }
723 }
724 }
725 }
726 }
727
728 pthread_mutex_unlock(&mutex_contention_mtx);
729
730 sleep(1);
731 }
732
733 return NULL;
734 }
735
mutex_contention_monitor_start()736 void mutex_contention_monitor_start()
737 {
738 pthread_mutex_lock(&mutex_contention_monitor_thread_mtx);
739 if(mutex_contention_monitor_thread_id == 0)
740 {
741 thread_t tid;
742 int ret = thread_create(&tid, mutex_contention_monitor_thread, NULL);
743 if(ret == 0)
744 {
745 mutex_contention_monitor_thread_id = tid;
746 }
747 }
748 pthread_mutex_unlock(&mutex_contention_monitor_thread_mtx);
749 }
750
mutex_contention_monitor_stop()751 void mutex_contention_monitor_stop()
752 {
753 pthread_mutex_lock(&mutex_contention_monitor_thread_mtx);
754 if(mutex_contention_monitor_thread_id != 0)
755 {
756 smp_int_add(&mutex_contention_monitor_thread_should_stop, 1);
757
758 thread_join(mutex_contention_monitor_thread_id, NULL);
759
760 smp_int_sub(&mutex_contention_monitor_thread_should_stop, 1);
761 mutex_contention_monitor_thread_id = 0;
762 }
763 pthread_mutex_unlock(&mutex_contention_monitor_thread_mtx);
764 }
765
766 #endif // !MUTEX_CONTENTION_MONITOR
767
768 #endif
769
cond_init_process_shared(cond_t * cond)770 int cond_init_process_shared(cond_t *cond)
771 {
772 int ret;
773 pthread_condattr_t attr;
774 if((ret = pthread_condattr_init(&attr)) == 0)
775 {
776 if((ret = pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) == 0)
777 {
778 ret = pthread_cond_init(cond, &attr);
779
780 if(ret != 0)
781 {
782 ret = MAKE_ERRNO_ERROR(ret);
783 }
784 }
785 else
786 {
787 ret = MAKE_ERRNO_ERROR(ret);
788 }
789
790 pthread_condattr_destroy(&attr);
791 }
792 else
793 {
794 ret = MAKE_ERRNO_ERROR(ret);
795 }
796 return ret;
797 }
798
799
800 /*
801 * Group mutex lock
802 */
803
804 void
group_mutex_init(group_mutex_t * mtx)805 group_mutex_init(group_mutex_t* mtx)
806 {
807 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
808 #ifdef MODULE_MSG_HANDLE
809 log_debug7("group_mutex: init mutex@%p", mtx);
810 #endif
811 #endif
812
813 mutex_init(&mtx->mutex);
814 cond_init(&mtx->cond);
815 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
816 #if MUTEX_CONTENTION_MONITOR
817 mutex_contention_object_create(mtx, FALSE);
818 #endif
819 #endif
820 mtx->count = 0;
821 mtx->owner = GROUP_MUTEX_NOBODY;
822 mtx->reserved_owner = GROUP_MUTEX_NOBODY;
823 }
824
825 bool
group_mutex_islocked(group_mutex_t * mtx)826 group_mutex_islocked(group_mutex_t *mtx)
827 {
828 mutex_lock(&mtx->mutex);
829 bool r = mtx->owner != 0;
830 mutex_unlock(&mtx->mutex);
831 return r;
832 }
833
834 void
group_mutex_lock(group_mutex_t * mtx,u8 owner)835 group_mutex_lock(group_mutex_t *mtx, u8 owner)
836 {
837 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
838 #if MUTEX_CONTENTION_MONITOR
839 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), group_mutex_type_name);
840 #endif
841 #endif
842 mutex_lock(&mtx->mutex);
843
844 for(;;)
845 {
846 /*
847 A simple way to ensure that a lock can be shared
848 by similar entities or not.
849 Sharable entities have their msb off.
850 */
851
852 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
853
854 if(co == GROUP_MUTEX_NOBODY || co == owner)
855 {
856 yassert(mtx->count != MAX_S32);
857
858 mtx->owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
859 mtx->count++;
860
861 break;
862 }
863 /*
864 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
865 #if MUTEX_CONTENTION_MONITOR
866 mutex_contention_lock_wait(mcm); // counts the loops
867 #endif
868 #endif
869 */
870 cond_wait(&mtx->cond, &mtx->mutex);
871 }
872
873 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
874 #if MUTEX_CONTENTION_MONITOR
875 mutex_contention_lock_end(mcm);
876 #endif
877 #endif
878
879 mutex_unlock(&mtx->mutex);
880
881 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
882 #ifdef MODULE_MSG_HANDLE
883 log_debug7("group_mutex: locked mutex@%p for %x", mtx, owner);
884 #endif
885 #endif
886 }
887
888 bool
group_mutex_trylock(group_mutex_t * mtx,u8 owner)889 group_mutex_trylock(group_mutex_t *mtx, u8 owner)
890 {
891 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
892 #ifdef MODULE_MSG_HANDLE
893 log_debug7("group_mutex: trying to lock mutex@%p for %x", mtx, owner);
894 #endif
895 #endif
896
897 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
898 #if MUTEX_CONTENTION_MONITOR
899 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), group_mutex_type_name);
900 #endif
901 #endif
902 mutex_lock(&mtx->mutex);
903
904 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
905
906 if(co == GROUP_MUTEX_NOBODY || co == owner)
907 {
908 yassert(mtx->count != MAX_S32);
909
910 mtx->owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
911 mtx->count++;
912
913 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
914 #if MUTEX_CONTENTION_MONITOR
915 mutex_contention_lock_end(mcm);
916 #endif
917 #endif
918
919 mutex_unlock(&mtx->mutex);
920
921 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
922 #ifdef MODULE_MSG_HANDLE
923 log_debug7("group_mutex: locked mutex@%p for %x", mtx, owner);
924 #endif
925 #endif
926 return TRUE;
927 }
928 else
929 {
930 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
931 #if MUTEX_CONTENTION_MONITOR
932 mutex_contention_lock_fail(mcm);
933 #endif
934 #endif
935 mutex_unlock(&mtx->mutex);
936
937 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
938 #ifdef MODULE_MSG_HANDLE
939 log_debug7("group_mutex: failed to lock mutex@%p for %x", mtx, owner);
940 #endif
941 #endif
942 return FALSE;
943 }
944 }
945
946 void
group_mutex_unlock(group_mutex_t * mtx,u8 owner)947 group_mutex_unlock(group_mutex_t *mtx, u8 owner)
948 {
949 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
950 #ifdef MODULE_MSG_HANDLE
951 log_debug7("group_mutex: unlocking mutex@%p for %x (owned by %x)", mtx, owner, mtx->owner);
952 #endif
953 #endif
954 mutex_lock(&mtx->mutex);
955
956 yassert(mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG));
957 yassert(mtx->count != 0);
958
959 (void)owner;
960
961 mtx->count--;
962
963 if(mtx->count == 0)
964 {
965 mtx->owner = GROUP_MUTEX_NOBODY;
966
967 // wake up all the ones that were waiting for a clean ownership
968
969 cond_notify(&mtx->cond);
970 }
971
972 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
973 #if MUTEX_CONTENTION_MONITOR
974 mutex_contention_unlock(thread_self(), mtx);
975 #endif
976 #endif
977
978 mutex_unlock(&mtx->mutex);
979 }
980
981 void
group_mutex_double_lock(group_mutex_t * mtx,u8 owner,u8 secondary_owner)982 group_mutex_double_lock(group_mutex_t *mtx, u8 owner, u8 secondary_owner)
983 {
984 yassert(owner == GROUP_MUTEX_READ);
985
986 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
987
988 #ifdef MODULE_MSG_HANDLE
989 log_debug7("group_mutex: double-locking mutex@%p for %x", mtx, secondary_owner);
990 #endif
991
992 #endif
993
994 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
995 #if MUTEX_CONTENTION_MONITOR
996 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), group_mutex_type_name);
997 #endif
998 #endif
999 mutex_lock(&mtx->mutex);
1000
1001 for(;;)
1002 {
1003 /*
1004 * A simple way to ensure that a lock can be shared
1005 * by similar entities or not.
1006 * Sharable entities have their msb off.
1007 */
1008
1009 u8 so = mtx->reserved_owner & GROUP_MUTEX_LOCKMASK_FLAG;
1010
1011 if(so == GROUP_MUTEX_NOBODY || so == secondary_owner)
1012 {
1013 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
1014
1015 if(co == GROUP_MUTEX_NOBODY || co == owner)
1016 {
1017 yassert(!SIGNED_VAR_VALUE_IS_MAX(mtx->count));
1018
1019 mtx->owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
1020 mtx->count++;
1021 mtx->reserved_owner = secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG;
1022
1023 break;
1024 }
1025 }
1026 else
1027 {
1028 // the secondary owner is already taken
1029 }
1030
1031 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1032 #if MUTEX_CONTENTION_MONITOR
1033 mutex_contention_lock_wait(mcm);
1034 #endif
1035 #endif
1036 cond_wait(&mtx->cond, &mtx->mutex);
1037 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1038 #if MUTEX_CONTENTION_MONITOR
1039 mutex_contention_lock_resume(mcm);
1040 #endif
1041 #endif
1042 }
1043
1044 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1045 #if MUTEX_CONTENTION_MONITOR
1046 mutex_contention_lock_end(mcm);
1047 #endif
1048 #endif
1049
1050 mutex_unlock(&mtx->mutex);
1051
1052 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1053 #ifdef MODULE_MSG_HANDLE
1054 log_debug7("group_mutex: double-locked mutex@%p for %x", mtx, secondary_owner);
1055 #endif
1056 #endif
1057 }
1058
1059 void
group_mutex_double_unlock(group_mutex_t * mtx,u8 owner,u8 secondary_owner)1060 group_mutex_double_unlock(group_mutex_t *mtx, u8 owner, u8 secondary_owner)
1061 {
1062 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1063 #ifdef MODULE_MSG_HANDLE
1064 log_debug7("group_mutex: double-unlocking mutex@%p for %x (owned by %x)", mtx, secondary_owner, mtx->reserved_owner);
1065 #endif
1066 #endif
1067
1068 yassert(owner == GROUP_MUTEX_READ);
1069
1070 mutex_lock(&mtx->mutex);
1071
1072 yassert(mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG));
1073 yassert(mtx->reserved_owner == (secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG));
1074 yassert(mtx->count != 0);
1075
1076 (void)owner;
1077 (void)secondary_owner;
1078
1079 mtx->reserved_owner = GROUP_MUTEX_NOBODY;
1080
1081 --mtx->count;
1082
1083 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1084 #ifdef MODULE_MSG_HANDLE
1085 log_debug7("group_mutex: double-unlocked mutex@%p for %x,%x", mtx, owner, secondary_owner);
1086 #endif
1087 #endif
1088
1089 yassert((mtx->owner & 0xc0) == 0);
1090
1091 if(mtx->count == 0)
1092 {
1093 mtx->owner = GROUP_MUTEX_NOBODY;
1094 cond_notify(&mtx->cond);
1095 }
1096
1097 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1098 #if MUTEX_CONTENTION_MONITOR
1099 mutex_contention_unlock(thread_self(), mtx);
1100 #endif
1101 #endif
1102
1103 mutex_unlock(&mtx->mutex);
1104 }
1105
1106 void
group_mutex_exchange_locks(group_mutex_t * mtx,u8 owner,u8 secondary_owner)1107 group_mutex_exchange_locks(group_mutex_t *mtx, u8 owner, u8 secondary_owner)
1108 {
1109 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1110 #ifdef MODULE_MSG_HANDLE
1111 log_debug7("group_mutex: exchanging-locks of mutex@%p %x,%x (", mtx, owner, secondary_owner, mtx->owner, mtx->reserved_owner);
1112 #endif
1113 #endif
1114
1115 yassert(owner == GROUP_MUTEX_READ || secondary_owner == GROUP_MUTEX_READ);
1116
1117 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1118 #ifdef MODULE_MSG_HANDLE
1119 s64 start = timeus();
1120 #endif
1121
1122 mutex_lock(&mtx->mutex);
1123
1124 if((mtx->owner != (owner & GROUP_MUTEX_LOCKMASK_FLAG)) || (mtx->reserved_owner != (secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG)) || (mtx->count == 0))
1125 {
1126 #ifdef MODULE_MSG_HANDLE
1127 debug_log_stacktrace(g_system_logger, MSG_ERR, "group_mutex_exchange_locks");
1128 #endif
1129 abort();
1130 }
1131 #else
1132 mutex_lock(&mtx->mutex);
1133
1134 yassert(mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG));
1135 yassert(mtx->reserved_owner == (secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG));
1136 yassert(mtx->count != 0);
1137 #endif
1138
1139 #if DEBUG
1140 if((mtx->owner != (owner & GROUP_MUTEX_LOCKMASK_FLAG)) || (mtx->count == 0))
1141 {
1142 mutex_unlock(&mtx->mutex);
1143 yassert(mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG));
1144 yassert(mtx->count != 0);
1145 abort(); // unreachable
1146 }
1147
1148 if(mtx->reserved_owner != (secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG))
1149 {
1150 mutex_unlock(&mtx->mutex);
1151 yassert(mtx->reserved_owner != (secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG));
1152 abort(); // unreachable
1153 }
1154 #endif
1155
1156 // wait to be the last one
1157
1158 while(mtx->count != 1)
1159 {
1160 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1161 #ifdef MODULE_MSG_HANDLE
1162 s64 d = timeus() - start;
1163 if(d > MUTEX_WAITED_TOO_MUCH_TIME_US)
1164 {
1165 log_warn("group_mutex_exchange_locks(%p,%x,%x) : waited for %llius already ...", mtx, owner, secondary_owner, d);
1166 debug_log_stacktrace(MODULE_MSG_HANDLE, MSG_WARNING, "group_mutex_exchange_locks:");
1167 }
1168 #endif
1169 #endif
1170 cond_timedwait(&mtx->cond, &mtx->mutex, 100);
1171 }
1172
1173 mtx->owner = secondary_owner & GROUP_MUTEX_LOCKMASK_FLAG;
1174 mtx->reserved_owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
1175
1176 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1177 #ifdef MODULE_MSG_HANDLE
1178 log_debug7("group_mutex: exchanged locks of mutex@%p to %x, %x", mtx, secondary_owner, owner);
1179 #endif
1180 #endif
1181
1182 if((secondary_owner & GROUP_MUTEX_EXCLUSIVE_FLAG) == 0)
1183 {
1184 cond_notify(&mtx->cond);
1185 }
1186
1187 mutex_unlock(&mtx->mutex);
1188 }
1189
1190 void
group_mutex_destroy(group_mutex_t * mtx)1191 group_mutex_destroy(group_mutex_t* mtx)
1192 {
1193 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1194 #ifdef MODULE_MSG_HANDLE
1195 log_debug7("group_mutex: destroy mutex@%p", mtx);
1196 #endif
1197 #endif
1198
1199 mutex_lock(&mtx->mutex);
1200 yassert(mtx->count == 0);
1201
1202 mutex_unlock(&mtx->mutex);
1203
1204 group_mutex_lock(mtx, GROUP_MUTEX_DESTROY);
1205 group_mutex_unlock(mtx, GROUP_MUTEX_DESTROY);
1206
1207 cond_notify(&mtx->cond);
1208 cond_finalize(&mtx->cond);
1209 mutex_destroy(&mtx->mutex);
1210 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1211 #if MUTEX_CONTENTION_MONITOR
1212 mutex_contention_object_destroy(mtx);
1213 #endif
1214 #endif
1215 }
1216
1217 void
mutex_init_recursive(mutex_t * mtx)1218 mutex_init_recursive(mutex_t *mtx)
1219 {
1220 int err;
1221
1222 ZEROMEMORY(mtx, sizeof(mutex_t));
1223
1224 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1225 #if MUTEX_CONTENTION_MONITOR
1226 mutex_contention_object_create(mtx, FALSE);
1227 #endif
1228 #endif
1229
1230 pthread_mutexattr_t mta;
1231
1232 err = pthread_mutexattr_init(&mta);
1233
1234 if(err != 0)
1235 {
1236 #ifdef MODULE_MSG_HANDLE
1237 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_init_recursive: attr %r", MAKE_ERRNO_ERROR(err));
1238 #endif
1239 }
1240
1241 err = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
1242
1243 if(err != 0)
1244 {
1245 #ifdef MODULE_MSG_HANDLE
1246 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_init_recursive: set %r", MAKE_ERRNO_ERROR(err));
1247 #endif
1248 }
1249
1250 err = pthread_mutex_init(mtx, &mta);
1251
1252 if(err != 0)
1253 {
1254 #ifdef MODULE_MSG_HANDLE
1255 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_init_recursive: %r", MAKE_ERRNO_ERROR(err));
1256 #endif
1257 }
1258
1259 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1260 if(mutex_ultraverbose)
1261 {
1262 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_init(%p)", mtx);
1263 }
1264 #endif
1265
1266 pthread_mutexattr_destroy(&mta);
1267 }
1268
1269 int
mutex_init_process_shared(mutex_t * mtx)1270 mutex_init_process_shared(mutex_t *mtx)
1271 {
1272 int ret;
1273
1274 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1275 #if MUTEX_CONTENTION_MONITOR
1276 mutex_contention_object_create(mtx, FALSE);
1277 #endif
1278 #endif
1279
1280 pthread_mutexattr_t attr;
1281 if((ret = pthread_mutexattr_init(&attr)) == 0)
1282 {
1283 ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1284
1285 if(ret == 0)
1286 {
1287 if((ret = pthread_mutex_init(mtx, &attr)) != 0)
1288 {
1289 ret = MAKE_ERRNO_ERROR(ret);
1290 }
1291 }
1292 else
1293 {
1294 ret = MAKE_ERRNO_ERROR(ret);
1295 }
1296
1297 pthread_mutexattr_destroy(&attr);
1298 }
1299 else
1300 {
1301 ret = MAKE_ERRNO_ERROR(ret);
1302 }
1303
1304 return ret;
1305 }
1306
1307 void
mutex_init(mutex_t * mtx)1308 mutex_init(mutex_t *mtx)
1309 {
1310 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1311 #if MUTEX_CONTENTION_MONITOR
1312 mutex_contention_object_create(mtx, FALSE);
1313 #endif
1314 #endif
1315 int err = pthread_mutex_init(mtx, NULL);
1316
1317 if(err != 0)
1318 {
1319 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_init: %r", MAKE_ERRNO_ERROR(err));
1320 }
1321 }
1322
1323 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1324
1325 void
mutex_lock(mutex_t * mtx)1326 mutex_lock(mutex_t *mtx)
1327 {
1328 if(mutex_ultraverbose)
1329 {
1330 #ifdef MODULE_MSG_HANDLE
1331 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_lock(%p)", mtx);
1332 #endif
1333 }
1334
1335 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1336 #if MUTEX_CONTENTION_MONITOR
1337 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), mutex_type_name);
1338 #endif
1339 #endif
1340
1341 pthread_mutex_lock(mtx);
1342
1343 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1344 #if MUTEX_CONTENTION_MONITOR
1345 mutex_contention_lock_end(mcm);
1346 #endif
1347 #endif
1348
1349 if(mutex_ultraverbose)
1350 {
1351 #ifdef MODULE_MSG_HANDLE
1352 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_lock(%p): locked", mtx);
1353 #endif
1354 }
1355 }
1356
1357 bool
mutex_trylock(mutex_t * mtx)1358 mutex_trylock(mutex_t *mtx)
1359 {
1360 if(mutex_ultraverbose)
1361 {
1362 logger_handle_msg(g_system_logger, MSG_DEBUG7, "mutex_trylock(%p)", mtx);
1363 }
1364
1365 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1366 #if MUTEX_CONTENTION_MONITOR
1367 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), mutex_type_name);
1368 #endif
1369 #endif
1370
1371 int err = pthread_mutex_trylock(mtx);
1372
1373 if((err != 0) && (err != EBUSY))
1374 {
1375 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_trylock(%p): %r", mtx, MAKE_ERRNO_ERROR(err));
1376 logger_flush();
1377 abort();
1378 }
1379
1380 if(err == 0)
1381 {
1382 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1383 #if MUTEX_CONTENTION_MONITOR
1384 mutex_contention_lock_end(mcm);
1385 #endif
1386 #endif
1387 }
1388 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1389 #if MUTEX_CONTENTION_MONITOR
1390 else
1391 {
1392 mutex_contention_lock_fail(mcm);
1393 }
1394 #endif
1395 #endif
1396
1397 if(mutex_ultraverbose)
1398 {
1399 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_trylock(%p): %s", mtx, (err == 0)?"locked":"failed");
1400 }
1401
1402 return err == 0;
1403 }
1404
1405 void
mutex_unlock(mutex_t * mtx)1406 mutex_unlock(mutex_t *mtx)
1407 {
1408 if(mutex_ultraverbose)
1409 {
1410 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_unlock(%p)", mtx);
1411 }
1412
1413 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1414 #if MUTEX_CONTENTION_MONITOR
1415 mutex_contention_unlock(thread_self(), mtx);
1416 #endif
1417 #endif
1418
1419 int err = pthread_mutex_unlock(mtx);
1420
1421 if(err != 0)
1422 {
1423 logger_handle_msg(g_system_logger, MSG_ERR, "mutex_unlock(%p) self=%p: %r", mtx, (intptr)thread_self(), MAKE_ERRNO_ERROR(err));
1424 debug_stacktrace_log(g_system_logger, MSG_ERR, debug_stacktrace_get());
1425 logger_flush();
1426 abort();
1427 }
1428 }
1429
1430 int
mutex_lock_unchecked(mutex_t * mtx)1431 mutex_lock_unchecked(mutex_t *mtx)
1432 {
1433 if(mutex_ultraverbose)
1434 {
1435 #ifdef MODULE_MSG_HANDLE
1436 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_lock(%p)", mtx);
1437 #endif
1438 }
1439
1440 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1441 #if MUTEX_CONTENTION_MONITOR
1442 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), mutex_type_name);
1443 #endif
1444 #endif
1445
1446 int ret = pthread_mutex_lock(mtx);
1447
1448 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1449 #if MUTEX_CONTENTION_MONITOR
1450 mutex_contention_lock_end(mcm);
1451 #endif
1452 #endif
1453
1454 if(mutex_ultraverbose)
1455 {
1456 #ifdef MODULE_MSG_HANDLE
1457 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_lock(%p): locked", mtx);
1458 #endif
1459 }
1460
1461 return ret;
1462 }
1463
1464 int
mutex_unlock_unchecked(mutex_t * mtx)1465 mutex_unlock_unchecked(mutex_t *mtx)
1466 {
1467 if(mutex_ultraverbose)
1468 {
1469 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_unlock(%p)", mtx);
1470 }
1471
1472 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1473 #if MUTEX_CONTENTION_MONITOR
1474 mutex_contention_unlock(thread_self(), mtx);
1475 #endif
1476 #endif
1477
1478 int ret = pthread_mutex_unlock(mtx);
1479
1480 if(ret != 0)
1481 {
1482 logger_handle_msg(g_system_logger, MSG_ERR, "mutex_unlock(%p) self=%p: %r", mtx, (intptr)thread_self(), MAKE_ERRNO_ERROR(ret));
1483 debug_stacktrace_log(g_system_logger, MSG_ERR, debug_stacktrace_get());
1484 logger_flush();
1485 }
1486
1487 return ret;
1488 }
1489
1490 #endif
1491
1492 void
mutex_destroy(mutex_t * mtx)1493 mutex_destroy(mutex_t *mtx)
1494 {
1495 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1496 int ebusy_count = 0;
1497
1498 if(mutex_ultraverbose)
1499 {
1500 #ifdef MODULE_MSG_HANDLE
1501 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_destroy(%p)", mtx);
1502 #endif
1503 }
1504 #endif
1505
1506 for(;;)
1507 {
1508 int err = pthread_mutex_destroy(mtx);
1509
1510 switch(err)
1511 {
1512 case 0:
1513 {
1514 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1515 #if MUTEX_CONTENTION_MONITOR
1516 mutex_contention_object_destroy(mtx);
1517 #endif
1518 #endif
1519
1520 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1521 if(ebusy_count > 0)
1522 {
1523 logger_handle_msg(g_system_logger,MSG_DEBUG7, "mutex_destroy: EBUSY #%i", ebusy_count);
1524 }
1525 #endif
1526 return;
1527 }
1528 case EBUSY:
1529 {
1530 usleep(1000);
1531 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1532 ebusy_count++;
1533
1534 #ifdef MODULE_MSG_HANDLE
1535 if((ebusy_count & 0xfffff) == 0)
1536 {
1537 debug_stacktrace_log(g_system_logger, MSG_DEBUG7, debug_stacktrace_get());
1538 }
1539
1540 if((ebusy_count & 0xfff) == 0)
1541 {
1542 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_destroy: EBUSY #%i", ebusy_count);
1543 }
1544 #endif
1545 #endif
1546 break;
1547 }
1548 default:
1549 {
1550 #ifdef MODULE_MSG_HANDLE
1551 logger_handle_msg(g_system_logger,MSG_ERR, "mutex_destroy: %r", MAKE_ERRNO_ERROR(err));
1552 logger_flush();
1553 #endif
1554 abort();
1555 }
1556 }
1557 }
1558 }
1559
1560 ///////////////////////////////////////////////////////////////////////////////
1561
1562 /*
1563 * Group mutex lock
1564 */
1565
1566 void
shared_group_shared_mutex_init(shared_group_shared_mutex_t * smtx)1567 shared_group_shared_mutex_init(shared_group_shared_mutex_t* smtx)
1568 {
1569 mutex_init(&smtx->mutex);
1570 cond_init(&smtx->cond);
1571 smtx->rc = 0;
1572
1573 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1574 #if MUTEX_CONTENTION_MONITOR
1575 mutex_contention_object_create(smtx, FALSE);
1576 #endif
1577 #endif
1578 }
1579
1580 void
shared_group_shared_mutex_init_recursive(shared_group_shared_mutex_t * smtx)1581 shared_group_shared_mutex_init_recursive(shared_group_shared_mutex_t* smtx)
1582 {
1583 mutex_init_recursive(&smtx->mutex);
1584 cond_init(&smtx->cond);
1585 smtx->rc = 0;
1586
1587 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1588 #if MUTEX_CONTENTION_MONITOR
1589 mutex_contention_object_create(smtx, TRUE);
1590 #endif
1591 #endif
1592 }
1593
1594 void
shared_group_shared_mutex_destroy(shared_group_shared_mutex_t * smtx)1595 shared_group_shared_mutex_destroy(shared_group_shared_mutex_t* smtx)
1596 {
1597 yassert(smtx->rc == 0);
1598
1599 cond_finalize(&smtx->cond);
1600 mutex_destroy(&smtx->mutex);
1601
1602 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1603 #if MUTEX_CONTENTION_MONITOR
1604 mutex_contention_object_destroy(smtx);
1605 #endif
1606 #endif
1607 }
1608
1609 void
shared_group_mutex_init(shared_group_mutex_t * mtx,shared_group_shared_mutex_t * smtx,const char * name)1610 shared_group_mutex_init(shared_group_mutex_t* mtx, shared_group_shared_mutex_t* smtx, const char *name)
1611 {
1612 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1613 #ifdef MODULE_MSG_HANDLE
1614 log_debug7("shared_group_mutex: init mutex@%p+%p '%s'", mtx, smtx, name);
1615 #endif
1616 #else
1617 (void)name;
1618 #endif
1619
1620 mutex_lock(&smtx->mutex);
1621 smtx->rc++;
1622 mutex_unlock(&smtx->mutex);
1623 mtx->shared_mutex = smtx;
1624
1625 mtx->count = 0;
1626 mtx->owner = GROUP_MUTEX_NOBODY;
1627
1628 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1629 #if MUTEX_CONTENTION_MONITOR
1630 mutex_contention_object_create(mtx, TRUE);
1631 #endif
1632 #endif
1633 }
1634
1635 bool
shared_group_mutex_islocked(shared_group_mutex_t * mtx)1636 shared_group_mutex_islocked(shared_group_mutex_t *mtx)
1637 {
1638 mutex_lock(&mtx->shared_mutex->mutex);
1639 bool r = mtx->owner != 0;
1640 mutex_unlock(&mtx->shared_mutex->mutex);
1641 return r;
1642 }
1643
1644 bool
shared_group_mutex_islocked_by(shared_group_mutex_t * mtx,u8 owner)1645 shared_group_mutex_islocked_by(shared_group_mutex_t *mtx, u8 owner)
1646 {
1647 mutex_lock(&mtx->shared_mutex->mutex);
1648 bool r = mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG);
1649 mutex_unlock(&mtx->shared_mutex->mutex);
1650 return r;
1651 }
1652
1653 void
shared_group_mutex_lock(shared_group_mutex_t * mtx,u8 owner)1654 shared_group_mutex_lock(shared_group_mutex_t *mtx, u8 owner)
1655 {
1656 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1657 #ifdef MODULE_MSG_HANDLE
1658 log_debug7("shared_group_mutex: locking mutex@%p for %x", mtx, owner);
1659 #endif
1660 #endif
1661
1662 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1663 #if MUTEX_CONTENTION_MONITOR
1664 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), shared_group_mutex_type_name);
1665 #endif
1666 #endif
1667
1668 mutex_lock(&mtx->shared_mutex->mutex);
1669
1670 for(;;)
1671 {
1672 /*
1673 A simple way to ensure that a lock can be shared
1674 by similar entities or not.
1675 Sharable entities have their msb off.
1676 */
1677
1678 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
1679
1680 if(co == GROUP_MUTEX_NOBODY || co == owner)
1681 {
1682 yassert(mtx->count != MAX_S32);
1683
1684 mtx->owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
1685 mtx->count++;
1686 break;
1687 }
1688
1689 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1690 #if MUTEX_CONTENTION_MONITOR
1691 mutex_contention_lock_wait(mcm);
1692 #endif
1693 #endif
1694 cond_wait(&mtx->shared_mutex->cond, &mtx->shared_mutex->mutex);
1695 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1696 #if MUTEX_CONTENTION_MONITOR
1697 mutex_contention_lock_resume(mcm);
1698 #endif
1699 #endif
1700 }
1701
1702 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1703 #if MUTEX_CONTENTION_MONITOR
1704 mutex_contention_lock_end(mcm);
1705 #endif
1706 #endif
1707
1708 mutex_unlock(&mtx->shared_mutex->mutex);
1709
1710 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1711 #ifdef MODULE_MSG_HANDLE
1712 log_debug7("shared_group_mutex: locked mutex@%p for %x", mtx, owner);
1713 #endif
1714 #endif
1715 }
1716
1717 bool
shared_group_mutex_trylock(shared_group_mutex_t * mtx,u8 owner)1718 shared_group_mutex_trylock(shared_group_mutex_t *mtx, u8 owner)
1719 {
1720 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1721 #ifdef MODULE_MSG_HANDLE
1722 log_debug7("shared_group_mutex: trying to lock mutex@%p for %x", mtx, owner);
1723 #endif
1724 #endif
1725
1726 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1727 #if MUTEX_CONTENTION_MONITOR
1728 mutex_contention_monitor_t *mcm = mutex_contention_lock_begin(thread_self(), mtx, debug_stacktrace_get(), shared_group_mutex_type_name);
1729 #endif
1730 #endif
1731
1732 mutex_lock(&mtx->shared_mutex->mutex);
1733
1734 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
1735
1736 if(co == GROUP_MUTEX_NOBODY || co == owner)
1737 {
1738 yassert(mtx->count != MAX_S32);
1739
1740 mtx->owner = owner & GROUP_MUTEX_LOCKMASK_FLAG;
1741 mtx->count++;
1742
1743 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1744 #if MUTEX_CONTENTION_MONITOR
1745 mutex_contention_lock_end(mcm);
1746 #endif
1747 #endif
1748 mutex_unlock(&mtx->shared_mutex->mutex);
1749
1750 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1751 #ifdef MODULE_MSG_HANDLE
1752 log_debug7("shared_group_mutex: locked mutex@%p for %x", mtx, owner);
1753 #endif
1754 #endif
1755 return TRUE;
1756 }
1757 else
1758 {
1759 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1760 #if MUTEX_CONTENTION_MONITOR
1761 mutex_contention_lock_fail(mcm);
1762 #endif
1763 #endif
1764 mutex_unlock(&mtx->shared_mutex->mutex);
1765
1766 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1767 #ifdef MODULE_MSG_HANDLE
1768 log_debug7("shared_group_mutex: failed to lock mutex@%p for %x", mtx, owner);
1769 #endif
1770 #endif
1771
1772 return FALSE;
1773 }
1774 }
1775
1776 void
shared_group_mutex_unlock(shared_group_mutex_t * mtx,u8 owner)1777 shared_group_mutex_unlock(shared_group_mutex_t *mtx, u8 owner)
1778 {
1779 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1780 #ifdef MODULE_MSG_HANDLE
1781 log_debug7("shared_group_mutex: unlocking mutex@%p for %x (owned by %x)", mtx, owner, mtx->owner);
1782 #endif
1783 #endif
1784
1785 mutex_lock(&mtx->shared_mutex->mutex);
1786
1787 yassert(mtx->owner == (owner & GROUP_MUTEX_LOCKMASK_FLAG));
1788 yassert(mtx->count != 0);
1789
1790 (void)owner;
1791
1792 mtx->count--;
1793
1794 if(mtx->count == 0)
1795 {
1796 mtx->owner = GROUP_MUTEX_NOBODY;
1797
1798 // wake up all the ones that were waiting for a clean ownership
1799
1800 cond_notify(&mtx->shared_mutex->cond);
1801 }
1802
1803 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1804 #if MUTEX_CONTENTION_MONITOR
1805 mutex_contention_unlock(thread_self(), mtx);
1806 #endif
1807 #endif
1808
1809 mutex_unlock(&mtx->shared_mutex->mutex);
1810 }
1811
1812 bool
shared_group_mutex_transferlock(shared_group_mutex_t * mtx,u8 owner,u8 newowner)1813 shared_group_mutex_transferlock(shared_group_mutex_t *mtx, u8 owner, u8 newowner)
1814 {
1815 bool r;
1816
1817 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1818 #ifdef MODULE_MSG_HANDLE
1819 log_debug7("shared_group_mutex: transferring ownership of mutex@%p from %x to %x (owned by %x)", mtx, owner, newowner, mtx->owner);
1820 #endif
1821 #endif
1822
1823 mutex_lock(&mtx->shared_mutex->mutex);
1824
1825 u8 co = mtx->owner & GROUP_MUTEX_LOCKMASK_FLAG;
1826
1827 if((r = (co == owner)))
1828 {
1829 mtx->owner = newowner;
1830 }
1831
1832 mutex_unlock(&mtx->shared_mutex->mutex);
1833
1834 return r;
1835 }
1836
1837 void
shared_group_mutex_destroy(shared_group_mutex_t * mtx)1838 shared_group_mutex_destroy(shared_group_mutex_t* mtx)
1839 {
1840 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT > 1
1841 #ifdef MODULE_MSG_HANDLE
1842 log_debug7("shared_group_mutex: destroy mutex@%p", mtx);
1843 #endif
1844 #endif
1845
1846 #if DNSCORE_HAS_MUTEX_DEBUG_SUPPORT
1847 #if MUTEX_CONTENTION_MONITOR
1848 mutex_contention_object_destroy(mtx);
1849 #endif
1850 #endif
1851
1852 mutex_lock(&mtx->shared_mutex->mutex);
1853 mtx->shared_mutex->rc--;
1854 mutex_unlock(&mtx->shared_mutex->mutex);
1855 }
1856
1857
1858 /** @} */
1859