2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 How to use mutex with bad order usage detection
22 ------------------------------------------------
24 Note: see file mutex_list.h for current mutexes with
28 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
34 bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
39 Mutex that doesn't need this extra check can be declared as pthread_mutex_t.
40 You can use this object on pthread_mutex_lock/unlock/cond_wait/cond_timewait.
42 With dynamic creation, you can use:
43 bthread_mutex_t mutex;
44 pthread_mutex_init(&mutex);
45 bthread_mutex_set_priority(&mutex, 10);
46 pthread_mutex_destroy(&mutex);
50 #define LOCKMGR_COMPLIANT
54 #define ASSERT(x) if (!(x)) { \
56 Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
59 #define ASSERT_p(x,f,l) if (!(x)) { \
61 Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
64 #define ASSERT2_p(x,m,f,l) if (!(x)) { \
66 set_assert_msg(f, l, m); \
67 Pmsg4(000, _("ASSERT failed at %s:%i: %s (%s)\n"), f, l, #x, m); \
72 http://www.cs.berkeley.edu/~kamil/teaching/sp03/041403.pdf
74 This lock manager will replace some pthread calls. It can be
75 enabled with USE_LOCKMGR
77 Some part of the code can't use this manager, for example the
78 rwlock object or the smartalloc lib. To disable LMGR, just add
79 LOCKMGR_COMPLIANT before the inclusion of "bacula.h"
82 g++ -g -c lockmgr.c -I.. -I../lib -DUSE_LOCKMGR -D_TEST_IT
83 g++ -o lockmgr lockmgr.o -lbac -L../lib/.libs -lssl -lpthread
87 #define DBGLEVEL_EVENT 50
90 * pthread_mutex_lock for memory allocator and other
91 * parts that are LOCKMGR_COMPLIANT
93 void lmgr_p(pthread_mutex_t *m)
96 if ((errstat=pthread_mutex_lock(m))) {
98 e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
99 be.bstrerror(errstat));
103 void lmgr_v(pthread_mutex_t *m)
106 if ((errstat=pthread_mutex_unlock(m))) {
108 e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
109 be.bstrerror(errstat));
117 LMGR_WHITE, /* never seen */
118 LMGR_BLACK, /* no loop */
119 LMGR_GRAY /* already seen */
123 * Node used by the Lock Manager
124 * If the lock is GRANTED, we have mutex -> proc, else it's a proc -> mutex
127 * Note, each mutex can be GRANTED once, and each proc can have only one WANTED
130 class lmgr_node_t: public SMARTALLOC
143 lmgr_node_t(void *n, void *c) {
147 void init(void *n, void *c) {
153 void mark_as_seen(lmgr_color_t c) {
157 ~lmgr_node_t() {printf("delete node\n");}
161 LMGR_LOCK_EMPTY = 'E', /* unused */
162 LMGR_LOCK_WANTED = 'W', /* before mutex_lock */
163 LMGR_LOCK_GRANTED = 'G' /* after mutex_lock */
167 * Object associated with each mutex per thread
169 class lmgr_lock_t: public SMARTALLOC
173 void *lock; /* Link to the mutex (or any value) */
176 int priority; /* Current node priority */
183 state = LMGR_LOCK_EMPTY;
184 priority = max_priority = 0;
187 lmgr_lock_t(void *l) {
189 state = LMGR_LOCK_WANTED;
193 state = LMGR_LOCK_GRANTED;
201 * Get the child list, ret must be already allocated
203 static void search_all_node(dlist *g, lmgr_node_t *v, alist *ret)
206 foreach_dlist(n, g) {
207 if (v->child == n->node) {
213 static bool visit(dlist *g, lmgr_node_t *v)
217 v->mark_as_seen(LMGR_GRAY);
219 alist *d = New(alist(5, false)); /* use alist because own=false */
220 search_all_node(g, v, d);
222 //foreach_alist(n, d) {
223 // printf("node n=%p c=%p s=%c\n", n->node, n->child, n->seen);
226 foreach_alist(n, d) {
227 if (n->seen == LMGR_GRAY) { /* already seen this node */
230 } else if (n->seen == LMGR_WHITE) {
237 v->mark_as_seen(LMGR_BLACK); /* no loop detected, node is clean */
243 static bool contains_cycle(dlist *g)
246 foreach_dlist(n, g) {
247 if (n->seen == LMGR_WHITE) {
256 /****************************************************************/
258 /* lmgr_thread_event struct, some call can add events, and they will
259 * be dumped during a lockdump
263 int32_t id; /* Id of the event */
264 int32_t global_id; /* Current global id */
265 int32_t flags; /* Flags for this event */
267 int32_t line; /* from which line in filename */
268 const char *from; /* From where in the code (filename) */
270 char *comment; /* Comment */
271 intptr_t user_data; /* Optionnal user data (will print address) */
275 static int32_t global_event_id=0;
277 static int global_int_thread_id=0; /* Keep an integer for each thread */
279 /* Keep this number of event per thread */
281 # define LMGR_THREAD_EVENT_MAX 15
283 # define LMGR_THREAD_EVENT_MAX 1024
286 #define lmgr_thread_event_get_pos(x) ((x) % LMGR_THREAD_EVENT_MAX)
288 class lmgr_thread_t: public SMARTALLOC
292 pthread_mutex_t mutex;
294 intptr_t int_thread_id;
295 lmgr_lock_t lock_list[LMGR_MAX_LOCK];
300 lmgr_thread_event events[LMGR_THREAD_EVENT_MAX];
305 if ((status = pthread_mutex_init(&mutex, NULL)) != 0) {
307 Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
308 be.bstrerror(status));
309 ASSERT2(0, "pthread_mutex_init failed");
312 thread_id = pthread_self();
318 /* Add event to the event list of the thread */
319 void add_event(const char *comment, intptr_t user_data, int32_t flags,
320 const char *from, int32_t line)
323 int i = lmgr_thread_event_get_pos(event_id);
325 events[i].flags = LMGR_EVENT_INVALID;
326 p = events[i].comment;
327 events[i].comment = (char *)"*Freed*";
329 /* Shared between thread, just an indication about timing */
330 events[i].global_id = global_event_id++;
331 events[i].id = event_id;
332 events[i].line = line;
333 events[i].from = from;
335 /* It means we are looping over the ring, so we need
336 * to check if the memory need to be freed
338 if (event_id >= LMGR_THREAD_EVENT_MAX) {
339 if (events[i].flags & LMGR_EVENT_FREE) {
344 /* We need to copy the memory */
345 if (flags & LMGR_EVENT_DUP) {
346 events[i].comment = bstrdup(comment);
347 flags |= LMGR_EVENT_FREE; /* force the free */
350 events[i].comment = (char *)comment;
352 events[i].user_data = user_data;
353 events[i].flags = flags; /* mark it valid */
357 void free_event_list() {
358 /* We first check how far we go in the event list */
359 int max = MIN(event_id, LMGR_THREAD_EVENT_MAX);
362 for (int i = 0; i < max ; i++) {
363 if (events[i].flags & LMGR_EVENT_FREE) {
364 p = events[i].comment;
365 events[i].flags = LMGR_EVENT_INVALID;
366 events[i].comment = (char *)"*Freed*";
372 void print_event(lmgr_thread_event *ev, FILE *fp) {
373 if (ev->flags & LMGR_EVENT_INVALID) {
376 fprintf(fp, " %010d id=%010d %s data=%p at %s:%d\n",
380 (void *)ev->user_data,
385 void _dump(FILE *fp) {
387 fprintf(fp, "thread_id=%p int_threadid=%p max=%i current=%i\n",
388 (void *)(intptr_t)GetCurrentThreadId(), (void *)int_thread_id, max, current);
390 fprintf(fp, "threadid=%p max=%i current=%i\n",
391 (void *)thread_id, max, current);
393 for(int i=0; i<=current; i++) {
394 fprintf(fp, " lock=%p state=%s priority=%i %s:%i\n",
396 (lock_list[i].state=='W')?"Wanted ":"Granted",
397 lock_list[i].priority,
398 lock_list[i].file, lock_list[i].line);
401 if (debug_flags & DEBUG_PRINT_EVENT) {
403 fprintf(fp, " events:\n");
405 /* Display events between (event_id % LMGR_THREAD_EVENT_MAX) and LMGR_THREAD_EVENT_MAX */
406 if (event_id > LMGR_THREAD_EVENT_MAX) {
407 for (int i = event_id % LMGR_THREAD_EVENT_MAX ; i < LMGR_THREAD_EVENT_MAX ; i++)
409 print_event(&events[i], fp);
413 /* Display events between 0 and event_id % LMGR_THREAD_EVENT_MAX*/
414 for (int i = 0 ; i < (event_id % LMGR_THREAD_EVENT_MAX) ; i++)
416 print_event(&events[i], fp);
421 void dump(FILE *fp) {
430 * Call before a lock operation (mark mutex as WANTED)
432 virtual void pre_P(void *m, int priority,
433 const char *f="*unknown*", int l=0)
435 int max_prio = max_priority;
437 if (chk_dbglvl(DBGLEVEL_EVENT) || debug_flags & DEBUG_MUTEX_EVENT) {
438 /* Keep track of this event */
439 add_event("P()", (intptr_t)m, 0, f, l);
442 /* Fail if too many locks in use */
443 ASSERT2_p(current < LMGR_MAX_LOCK, "Too many locks in use", f, l);
444 /* Fail if the "current" value is out of bounds */
445 ASSERT2_p(current >= -1, "current lock value is out of bounds", f, l);
449 lock_list[current].lock = m;
450 lock_list[current].state = LMGR_LOCK_WANTED;
451 lock_list[current].file = f;
452 lock_list[current].line = l;
453 lock_list[current].priority = priority;
454 lock_list[current].max_priority = MAX(priority, max_priority);
455 max = MAX(current, max);
456 max_priority = MAX(priority, max_priority);
460 /* Fail if we tried to lock a mutex with a lower priority than
461 * the current value. It means that you need to lock mutex in a
462 * different order to ensure that the priority field is always
463 * increasing. The mutex priority list is defined in mutex_list.h.
465 * Look the *.lockdump generated to get the list of all mutexes,
466 * and where they were granted to find the priority problem.
468 ASSERT2_p(!priority || priority >= max_prio,
469 "Mutex priority problem found, locking done in wrong order",
474 * Call after the lock operation (mark mutex as GRANTED)
476 virtual void post_P() {
477 ASSERT2(current >= 0, "Lock stack when negative");
478 ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
479 lock_list[current].state = LMGR_LOCK_GRANTED;
482 /* Using this function is some sort of bug */
483 void shift_list(int i) {
484 for(int j=i+1; j<=current; j++) {
485 lock_list[i] = lock_list[j];
488 lock_list[current].lock = NULL;
489 lock_list[current].state = LMGR_LOCK_EMPTY;
491 /* rebuild the priority list */
493 for(int j=0; j< current; j++) {
494 max_priority = MAX(lock_list[j].priority, max_priority);
495 lock_list[j].max_priority = max_priority;
500 * Remove the mutex from the list
502 virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
503 int old_current = current;
505 /* Keep track of this event */
506 if (chk_dbglvl(DBGLEVEL_EVENT) || debug_flags & DEBUG_MUTEX_EVENT) {
507 add_event("V()", (intptr_t)m, 0, f, l);
510 ASSERT2_p(current >= 0, "No previous P found, the mutex list is empty", f, l);
513 if (lock_list[current].lock == m) {
514 lock_list[current].lock = NULL;
515 lock_list[current].state = LMGR_LOCK_EMPTY;
518 Pmsg3(0, "ERROR: V out of order lock=%p %s:%i dumping locks...\n", m, f, l);
519 Pmsg4(000, " wrong P/V order pos=%i lock=%p %s:%i\n",
520 current, lock_list[current].lock, lock_list[current].file,
521 lock_list[current].line);
522 for (int i=current-1; i >= 0; i--) { /* already seen current */
523 Pmsg4(000, " wrong P/V order pos=%i lock=%p %s:%i\n",
524 i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
525 if (lock_list[i].lock == m) {
526 Pmsg3(000, "ERROR: FOUND P for out of order V at pos=%i %s:%i\n", i, f, l);
533 /* reset max_priority to the last one */
535 max_priority = lock_list[current].max_priority;
541 /* ASSERT2 should be called outside from the mutex lock */
542 ASSERT2_p(current != old_current, "V() called without a previous P()", f, l);
545 virtual ~lmgr_thread_t() {destroy();}
549 pthread_mutex_destroy(&mutex);
553 class lmgr_dummy_thread_t: public lmgr_thread_t
555 void do_V(void *m, const char *file, int l) {}
557 void pre_P(void *m, int priority, const char *file, int l) {}
561 * LMGR - Lock Manager
567 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT;
568 static pthread_key_t lmgr_key; /* used to get lgmr_thread_t object */
570 static dlist *global_mgr = NULL; /* used to store all lgmr_thread_t objects */
571 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
572 static pthread_t undertaker;
573 static bool use_undertaker=true;
575 #define lmgr_is_active() (global_mgr != NULL)
578 * Add a new lmgr_thread_t object to the global list
580 void lmgr_register_thread(lmgr_thread_t *item)
582 lmgr_p(&lmgr_global_mutex);
584 item->int_thread_id = ++global_int_thread_id;
585 global_mgr->prepend(item);
587 lmgr_v(&lmgr_global_mutex);
591 * Call this function to cleanup specific lock thread data
593 void lmgr_unregister_thread(lmgr_thread_t *item)
595 if (!lmgr_is_active()) {
598 lmgr_p(&lmgr_global_mutex);
600 global_mgr->remove(item);
602 lmgr_v(&lmgr_global_mutex);
606 # define TID int_thread_id
608 # define TID thread_id
611 * Search for a deadlock when it's secure to walk across
612 * locks list. (after lmgr_detect_deadlock or a fatal signal)
614 bool lmgr_detect_deadlock_unlocked()
617 lmgr_node_t *node=NULL;
620 dlist *g = New(dlist(node, &node->link));
622 /* First, get a list of all node */
623 foreach_dlist(item, global_mgr) {
624 for(int i=0; i<=item->current; i++) {
626 lock = &item->lock_list[i];
627 /* Depending if the lock is granted or not, it's a child or a root
628 * Granted: Mutex -> Thread
629 * Wanted: Thread -> Mutex
631 * Note: a Mutex can be locked only once, a thread can request only
635 if (lock->state == LMGR_LOCK_GRANTED) {
636 node = New(lmgr_node_t((void*)lock->lock, (void*)item->TID));
637 } else if (lock->state == LMGR_LOCK_WANTED) {
638 node = New(lmgr_node_t((void*)item->TID, (void*)lock->lock));
646 //foreach_dlist(node, g) {
647 // printf("g n=%p c=%p\n", node->node, node->child);
650 ret = contains_cycle(g);
652 printf("Found a deadlock !!!!\n");
660 * Search for a deadlock in during the runtime
661 * It will lock all thread specific lock manager, nothing
662 * can be locked during this check.
664 bool lmgr_detect_deadlock()
667 if (!lmgr_is_active()) {
671 lmgr_p(&lmgr_global_mutex);
674 foreach_dlist(item, global_mgr) {
675 lmgr_p(&item->mutex);
678 ret = lmgr_detect_deadlock_unlocked();
680 foreach_dlist(item, global_mgr) {
681 lmgr_v(&item->mutex);
684 lmgr_v(&lmgr_global_mutex);
691 * Use this function is used only after a fatal signal
692 * We don't use locking to display the information
694 void dbg_print_lock(FILE *fp)
696 fprintf(fp, "Attempt to dump locks\n");
697 if (!lmgr_is_active()) {
701 foreach_dlist(item, global_mgr) {
707 * Dump each lmgr_thread_t object
711 lmgr_p(&lmgr_global_mutex);
714 foreach_dlist(item, global_mgr) {
718 lmgr_v(&lmgr_global_mutex);
721 void cln_hdl(void *a)
723 lmgr_cleanup_thread();
726 void *check_deadlock(void *)
730 pthread_cleanup_push(cln_hdl, NULL);
732 while (!bmicrosleep(30, 0)) {
733 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
734 if (lmgr_detect_deadlock()) {
735 /* If we have information about P()/V(), display them */
736 if (debug_flags & DEBUG_MUTEX_EVENT || chk_dbglvl(DBGLEVEL_EVENT)) {
737 debug_flags |= DEBUG_PRINT_EVENT;
740 ASSERT2(0, "Lock deadlock"); /* Abort if we found a deadlock */
742 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
743 pthread_testcancel();
745 Dmsg0(100, "Exit check_deadlock.\n");
746 pthread_cleanup_pop(1);
750 /* This object is used when LMGR is not initialized */
751 static lmgr_dummy_thread_t dummy_lmgr;
754 * Retrieve the lmgr_thread_t object from the stack
756 inline lmgr_thread_t *lmgr_get_thread_info()
758 if (lmgr_is_active()) {
759 return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
765 /* On windows, the thread id is a struct, and sometime (for debug or openssl),
768 intptr_t bthread_get_thread_id()
770 lmgr_thread_t *self = lmgr_get_thread_info();
771 return self->int_thread_id;
775 * launch once for all threads
777 void create_lmgr_key()
779 int status = pthread_key_create(&lmgr_key, NULL);
782 Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
783 be.bstrerror(status));
784 ASSERT2(0, "pthread_key_create failed");
787 lmgr_thread_t *n=NULL;
788 global_mgr = New(dlist(n, &n->link));
790 if (use_undertaker) {
791 status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
794 Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
795 be.bstrerror(status));
796 ASSERT2(0, "pthread_create failed");
802 * Each thread have to call this function to put a lmgr_thread_t object
803 * in the stack and be able to call mutex_lock/unlock
805 void lmgr_init_thread()
807 int status = pthread_once(&key_lmgr_once, create_lmgr_key);
810 Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
811 be.bstrerror(status));
812 ASSERT2(0, "pthread_once failed");
814 lmgr_thread_t *l = New(lmgr_thread_t());
815 pthread_setspecific(lmgr_key, l);
816 lmgr_register_thread(l);
820 * Call this function at the end of the thread
822 void lmgr_cleanup_thread()
824 if (!lmgr_is_active()) {
827 lmgr_thread_t *self = lmgr_get_thread_info();
828 lmgr_unregister_thread(self);
833 * This function should be call at the end of the main thread
834 * Some thread like the watchdog are already present, so the global_mgr
835 * list is never empty. Should carefully clear the memory.
837 void lmgr_cleanup_main()
844 if (use_undertaker) {
845 pthread_cancel(undertaker);
847 /* Should avoid memory leak reporting */
848 pthread_join(undertaker, NULL);
851 lmgr_cleanup_thread();
852 lmgr_p(&lmgr_global_mutex);
858 lmgr_v(&lmgr_global_mutex);
861 void lmgr_add_event_p(const char *comment, intptr_t user_data, int32_t flags,
862 const char *file, int32_t line)
864 lmgr_thread_t *self = lmgr_get_thread_info();
865 self->add_event(comment, user_data, flags, file, line);
869 * Set the priority of the lmgr mutex object
871 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
873 #ifdef USE_LOCKMGR_PRIORITY
879 * Replacement for pthread_mutex_init()
881 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
884 return pthread_mutex_init(&m->mutex, attr);
888 * Replacement for pthread_mutex_destroy()
890 int pthread_mutex_destroy(bthread_mutex_t *m)
892 return pthread_mutex_destroy(&m->mutex);
896 * Replacement for pthread_kill (only with USE_LOCKMGR_SAFEKILL)
898 int bthread_kill(pthread_t thread, int sig,
899 const char *file, int line)
901 bool thread_found_in_process=false;
903 /* We doesn't allow to send signal to ourself */
904 ASSERT(!pthread_equal(thread, pthread_self()));
906 /* This loop isn't very efficient with dozens of threads but we don't use
907 * signal very much, and this feature is for testing only
909 lmgr_p(&lmgr_global_mutex);
912 foreach_dlist(item, global_mgr) {
913 if (pthread_equal(thread, item->thread_id)) {
914 thread_found_in_process=true;
919 lmgr_v(&lmgr_global_mutex);
921 /* Sending a signal to non existing thread can create problem
922 * so, we can stop here.
924 ASSERT2(thread_found_in_process, "Wanted to pthread_kill non-existant thread");
926 Dmsg3(100, "%s:%d send kill to existing thread %p\n", file, line, thread);
927 return pthread_kill(thread, sig);
931 * Replacement for pthread_mutex_lock()
934 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
936 lmgr_thread_t *self = lmgr_get_thread_info();
937 self->pre_P(m, m->priority, file, line);
944 * Replacement for pthread_mutex_unlock()
947 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
949 lmgr_thread_t *self = lmgr_get_thread_info();
950 self->do_V(m, file, line);
956 * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
959 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
961 lmgr_thread_t *self = lmgr_get_thread_info();
962 self->pre_P(m, 0, file, line);
969 * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
972 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
974 lmgr_thread_t *self = lmgr_get_thread_info();
975 self->do_V(m, file, line);
983 int bthread_cond_wait_p(pthread_cond_t *cond,
985 const char *file, int line)
988 lmgr_thread_t *self = lmgr_get_thread_info();
989 self->do_V(m, file, line);
990 ret = pthread_cond_wait(cond, m);
991 self->pre_P(m, 0, file, line);
998 int bthread_cond_timedwait_p(pthread_cond_t *cond,
1000 const struct timespec * abstime,
1001 const char *file, int line)
1004 lmgr_thread_t *self = lmgr_get_thread_info();
1005 self->do_V(m, file, line);
1006 ret = pthread_cond_timedwait(cond, m, abstime);
1007 self->pre_P(m, 0, file, line);
1014 int bthread_cond_wait_p(pthread_cond_t *cond,
1016 const char *file, int line)
1019 lmgr_thread_t *self = lmgr_get_thread_info();
1020 self->do_V(m, file, line);
1021 ret = pthread_cond_wait(cond, &m->mutex);
1022 self->pre_P(m, m->priority, file, line);
1029 int bthread_cond_timedwait_p(pthread_cond_t *cond,
1031 const struct timespec * abstime,
1032 const char *file, int line)
1035 lmgr_thread_t *self = lmgr_get_thread_info();
1036 self->do_V(m, file, line);
1037 ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
1038 self->pre_P(m, m->priority, file, line);
1043 /* Test if this mutex is locked by the current thread
1046 * 1 - locked by the current thread
1047 * 2 - locked by an other thread
1049 int lmgr_mutex_is_locked(void *m)
1051 lmgr_thread_t *self = lmgr_get_thread_info();
1053 for(int i=0; i <= self->current; i++) {
1054 if (self->lock_list[i].lock == m) {
1055 return 1; /* locked by us */
1059 return 0; /* not locked by us */
1063 * Use this function when the caller handle the mutex directly
1065 * lmgr_pre_lock(m, 10);
1066 * pthread_mutex_lock(m);
1067 * lmgr_post_lock(m);
1069 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
1071 lmgr_thread_t *self = lmgr_get_thread_info();
1072 self->pre_P(m, prio, file, line);
1076 * Use this function when the caller handle the mutex directly
1078 void lmgr_post_lock()
1080 lmgr_thread_t *self = lmgr_get_thread_info();
1085 * Do directly pre_P and post_P (used by trylock)
1087 void lmgr_do_lock(void *m, int prio, const char *file, int line)
1089 lmgr_thread_t *self = lmgr_get_thread_info();
1090 self->pre_P(m, prio, file, line);
1095 * Use this function when the caller handle the mutex directly
1097 void lmgr_do_unlock(void *m)
1099 lmgr_thread_t *self = lmgr_get_thread_info();
1104 void *(*start_routine)(void*);
1106 } lmgr_thread_arg_t;
1109 void *lmgr_thread_launcher(void *x)
1113 pthread_cleanup_push(cln_hdl, NULL);
1115 lmgr_thread_arg_t arg;
1116 lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
1117 arg.start_routine = a->start_routine;
1121 ret = arg.start_routine(arg.arg);
1122 pthread_cleanup_pop(1);
1126 int lmgr_thread_create(pthread_t *thread,
1127 const pthread_attr_t *attr,
1128 void *(*start_routine)(void*), void *arg)
1130 /* lmgr should be active (lmgr_init_thread() call in main()) */
1131 ASSERT2(lmgr_is_active(), "Lock manager not active");
1132 /* Will be freed by the child */
1133 lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
1134 a->start_routine = start_routine;
1136 return pthread_create(thread, attr, lmgr_thread_launcher, a);
1139 #else /* USE_LOCKMGR */
1141 intptr_t bthread_get_thread_id()
1144 return (intptr_t)GetCurrentThreadId();
1146 return (intptr_t)pthread_self();
1152 * Use this function is used only after a fatal signal
1153 * We don't use locking to display information
1155 void dbg_print_lock(FILE *fp)
1157 Pmsg0(000, "lockmgr disabled\n");
1160 #endif /* USE_LOCKMGR */
1164 #include "lockmgr.h"
1167 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
1168 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
1169 #define pthread_create(a, b, c, d) lmgr_thread_create(a,b,c,d)
1171 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
1172 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
1173 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
1174 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
1175 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
1176 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
1177 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
1178 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
1179 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
1180 static const char *my_prog;
1182 void *self_lock(void *temp)
1191 void *nolock(void *temp)
1199 void *locker(void *temp)
1201 bthread_mutex_t *m = (bthread_mutex_t*) temp;
1207 void *rwlocker(void *temp)
1209 brwlock_t *m = (brwlock_t*) temp;
1218 void *mix_rwl_mutex(void *temp)
1220 brwlock_t *m = (brwlock_t*) temp;
1229 void *th2(void *temp)
1244 void *th1(void *temp)
1261 void *thx(void *temp)
1263 int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1274 void *th3(void *a) {
1276 fprintf(stderr, "undertaker sleep()\n");
1279 if (lmgr_detect_deadlock()) {
1287 void *th_prio(void *a) {
1289 bstrncpy(buf, my_prog, sizeof(buf));
1290 bstrncat(buf, " priority", sizeof(buf));
1291 intptr_t ret = system(buf);
1295 void *th_event1(void *a) {
1296 for (int i=0; i < 10000; i++) {
1298 lmgr_add_event_flag("strdup test", i, LMGR_EVENT_DUP);
1300 lmgr_add_event("My comment", i);
1307 void *th_event2(void *a) {
1308 for (int i=0; i < 10000; i++) {
1310 lmgr_add_event_flag(bstrdup("free test"), i, LMGR_EVENT_FREE);
1312 lmgr_add_event("My comment", i);
1321 void _ok(const char *file, int l, const char *op, int value, const char *label)
1326 printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1328 printf("OK %.30s\n", label);
1332 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1334 void _nok(const char *file, int l, const char *op, int value, const char *label)
1339 printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1341 printf("OK %.30s\n", label);
1345 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1349 printf("Result %i/%i OK\n", nb - err, nb);
1355 * - Must detect multiple lock
1356 * - lock/unlock in wrong order
1357 * - deadlock with 2 or 3 threads
1359 int main(int argc, char **argv)
1362 lmgr_thread_t *self;
1363 pthread_t id1, id2, id3, id4, id5, tab[200];
1364 bthread_mutex_t bmutex1;
1365 pthread_mutex_t pmutex2;
1369 use_undertaker = false;
1371 self = lmgr_get_thread_info();
1373 if (argc == 2) { /* do priority check */
1374 P(mutex_p2); /* not permited */
1376 V(mutex_p1); /* never goes here */
1381 pthread_mutex_init(&bmutex1, NULL);
1382 bthread_mutex_set_priority(&bmutex1, 10);
1384 pthread_mutex_init(&pmutex2, NULL);
1386 ok(self->max_priority == 10, "Check self max_priority");
1388 ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1391 ok(self->max_priority == 0, "Check self max_priority");
1393 pthread_create(&id1, NULL, self_lock, NULL);
1395 ok(lmgr_detect_deadlock(), "Check self deadlock");
1396 lmgr_v(&mutex1.mutex); /* a bit dirty */
1397 pthread_join(id1, NULL);
1400 pthread_create(&id1, NULL, nolock, NULL);
1402 nok(lmgr_detect_deadlock(), "Check for nolock");
1403 pthread_join(id1, NULL);
1406 pthread_create(&id1, NULL, locker, &mutex1);
1407 pthread_create(&id2, NULL, locker, &mutex1);
1408 pthread_create(&id3, NULL, locker, &mutex1);
1410 nok(lmgr_detect_deadlock(), "Check for multiple lock");
1412 pthread_join(id1, NULL);
1413 pthread_join(id2, NULL);
1414 pthread_join(id3, NULL);
1421 pthread_create(&id1, NULL, rwlocker, &wr);
1422 pthread_create(&id2, NULL, rwlocker, &wr);
1423 pthread_create(&id3, NULL, rwlocker, &wr);
1424 nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1425 rwl_writeunlock(&wr);
1426 nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1427 rwl_writeunlock(&wr);
1428 nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1430 pthread_join(id1, NULL);
1431 pthread_join(id2, NULL);
1432 pthread_join(id3, NULL);
1436 pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1437 nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1439 nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1440 rwl_writeunlock(&wr);
1441 nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1442 pthread_join(id1, NULL);
1449 nok(lmgr_detect_deadlock(), "Check for wrong order");
1451 for(int j=0; j<200; j++) {
1452 pthread_create(&tab[j], NULL, thx, NULL);
1454 for(int j=0; j<200; j++) {
1455 pthread_join(tab[j], NULL);
1456 if (j%3) { lmgr_detect_deadlock();}
1458 nok(lmgr_detect_deadlock(), "Check 200 lockers");
1463 ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked");
1465 ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is locked");
1469 pthread_create(&id1, NULL, th1, NULL);
1471 pthread_create(&id2, NULL, th2, NULL);
1473 ok(lmgr_detect_deadlock(), "Check for deadlock");
1475 pthread_create(&id3, NULL, th_prio, NULL);
1476 pthread_join(id3, &ret);
1477 ok(ret != 0, "Check for priority segfault");
1480 ok(self->max_priority == 1, "Check max_priority 1/4");
1482 ok(self->max_priority == 2, "Check max_priority 2/4");
1484 ok(self->max_priority == 3, "Check max_priority 3/4");
1486 ok(self->max_priority == 3, "Check max_priority 4/4");
1488 ok(self->max_priority == 3, "Check max_priority 1/5");
1490 ok(self->max_priority == 2, "Check max_priority 4/5");
1492 ok(self->max_priority == 1, "Check max_priority 4/5");
1494 ok(self->max_priority == 0, "Check max_priority 5/5");
1501 ok(self->max_priority == 3, "Check max_priority mixed");
1503 ok(self->max_priority == 3, "Check max_priority mixed");
1505 ok(self->max_priority == 3, "Check max_priority mixed");
1507 ok(self->max_priority == 0, "Check max_priority mixed");
1509 ok(self->max_priority == 0, "Check max_priority mixed");
1516 for (int i=0; i < 10000; i++) {
1518 lmgr_add_event_flag("xxxxxxxxxxxxxxxx strdup test xxxxxxxxxxxxxxxx", i, LMGR_EVENT_DUP);
1520 lmgr_add_event("My comment", i);
1524 pthread_create(&id4, NULL, th_event1, NULL);
1525 pthread_create(&id5, NULL, th_event2, NULL);
1531 pthread_join(id4, NULL);
1532 pthread_join(id5, NULL);
1535 // pthread_create(&id3, NULL, th3, NULL);
1537 // pthread_join(id1, NULL);
1538 // pthread_join(id2, NULL);
1539 lmgr_cleanup_main();
1540 sm_check(__FILE__, __LINE__, false);