]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
81c54855ab12fdc2c5e313498d6b6ab30ea9a8da
[bacula/bacula] / bacula / src / lib / lockmgr.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19
20 /*
21   How to use mutex with bad order usage detection
22  ------------------------------------------------
23
24  Note: see file mutex_list.h for current mutexes with
25        defined priorities.
26
27  Instead of using:
28     pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
29     P(mutex);
30     ..
31     V(mutex);
32
33  use:
34     bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
35     P(mutex);
36     ...
37     V(mutex);
38
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.
41
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);
47
48  */
49
50 #define LOCKMGR_COMPLIANT
51 #include "bacula.h"
52
53 #undef ASSERT
54 #define ASSERT(x) if (!(x)) { \
55    char *jcr = NULL; \
56    Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
57    jcr[0] = 0; }
58
59 #define ASSERT_p(x,f,l) if (!(x)) {              \
60    char *jcr = NULL; \
61    Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
62    jcr[0] = 0; }
63
64 #define ASSERT2_p(x,m,f,l) if (!(x)) {          \
65    char *jcr = NULL; \
66    set_assert_msg(f, l, m); \
67    Pmsg4(000, _("ASSERT failed at %s:%i: %s (%s)\n"), f, l, #x, m);        \
68    jcr[0] = 0; }
69
70 /*
71   Inspired from
72   http://www.cs.berkeley.edu/~kamil/teaching/sp03/041403.pdf
73
74   This lock manager will replace some pthread calls. It can be
75   enabled with USE_LOCKMGR
76
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"
80
81   cd build/src/tools
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
84
85 */
86
87 #define DBGLEVEL_EVENT 50
88
89 /*
90  * pthread_mutex_lock for memory allocator and other
91  * parts that are LOCKMGR_COMPLIANT
92  */
93 void lmgr_p(pthread_mutex_t *m)
94 {
95    int errstat;
96    if ((errstat=pthread_mutex_lock(m))) {
97       berrno be;
98       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
99             be.bstrerror(errstat));
100    }
101 }
102
103 void lmgr_v(pthread_mutex_t *m)
104 {
105    int errstat;
106    if ((errstat=pthread_mutex_unlock(m))) {
107       berrno be;
108       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
109             be.bstrerror(errstat));
110    }
111 }
112
113 #ifdef USE_LOCKMGR
114
115 typedef enum
116 {
117    LMGR_WHITE,                  /* never seen */
118    LMGR_BLACK,                  /* no loop */
119    LMGR_GRAY                    /* already seen */
120 } lmgr_color_t;
121
122 /*
123  * Node used by the Lock Manager
124  * If the lock is GRANTED, we have mutex -> proc, else it's a proc -> mutex
125  * relation.
126  *
127  * Note, each mutex can be GRANTED once, and each proc can have only one WANTED
128  * mutex.
129  */
130 class lmgr_node_t: public SMARTALLOC
131 {
132 public:
133    dlink link;
134    void *node;
135    void *child;
136    lmgr_color_t seen;
137
138    lmgr_node_t() {
139       child = node = NULL;
140       seen = LMGR_WHITE;
141    }
142
143    lmgr_node_t(void *n, void *c) {
144       init(n,c);
145    }
146
147    void init(void *n, void *c) {
148       node = n;
149       child = c;
150       seen = LMGR_WHITE;
151    }
152
153    void mark_as_seen(lmgr_color_t c) {
154       seen = c;
155    }
156
157    ~lmgr_node_t() {printf("delete node\n");}
158 };
159
160 typedef enum {
161    LMGR_LOCK_EMPTY   = 'E',      /* unused */
162    LMGR_LOCK_WANTED  = 'W',      /* before mutex_lock */
163    LMGR_LOCK_GRANTED = 'G'       /* after mutex_lock */
164 } lmgr_state_t;
165
166 /*
167  * Object associated with each mutex per thread
168  */
169 class lmgr_lock_t: public SMARTALLOC
170 {
171 public:
172    dlink link;
173    void *lock;                  /* Link to the mutex (or any value) */
174    lmgr_state_t state;
175    int max_priority;
176    int priority;                /* Current node priority */
177
178    const char *file;
179    int line;
180
181    lmgr_lock_t() {
182       lock = NULL;
183       state = LMGR_LOCK_EMPTY;
184       priority = max_priority = 0;
185    }
186
187    lmgr_lock_t(void *l) {
188       lock = l;
189       state = LMGR_LOCK_WANTED;
190    }
191
192    void set_granted() {
193       state = LMGR_LOCK_GRANTED;
194    }
195
196    ~lmgr_lock_t() {}
197
198 };
199
200 /*
201  * Get the child list, ret must be already allocated
202  */
203 static void search_all_node(dlist *g, lmgr_node_t *v, alist *ret)
204 {
205    lmgr_node_t *n;
206    foreach_dlist(n, g) {
207       if (v->child == n->node) {
208          ret->append(n);
209       }
210    }
211 }
212
213 static bool visit(dlist *g, lmgr_node_t *v)
214 {
215    bool ret=false;
216    lmgr_node_t *n;
217    v->mark_as_seen(LMGR_GRAY);
218
219    alist *d = New(alist(5, false)); /* use alist because own=false */
220    search_all_node(g, v, d);
221
222    //foreach_alist(n, d) {
223    //   printf("node n=%p c=%p s=%c\n", n->node, n->child, n->seen);
224    //}
225
226    foreach_alist(n, d) {
227       if (n->seen == LMGR_GRAY) { /* already seen this node */
228          ret = true;
229          goto bail_out;
230       } else if (n->seen == LMGR_WHITE) {
231          if (visit(g, n)) {
232             ret = true;
233             goto bail_out;
234          }
235       }
236    }
237    v->mark_as_seen(LMGR_BLACK); /* no loop detected, node is clean */
238 bail_out:
239    delete d;
240    return ret;
241 }
242
243 static bool contains_cycle(dlist *g)
244 {
245    lmgr_node_t *n;
246    foreach_dlist(n, g) {
247       if (n->seen == LMGR_WHITE) {
248          if (visit(g, n)) {
249             return true;
250          }
251       }
252    }
253    return false;
254 }
255
256 /****************************************************************/
257
258 /* lmgr_thread_event struct, some call can add events, and they will
259  * be dumped during a lockdump
260  */
261 typedef struct
262 {
263    int32_t     id;              /* Id of the event */
264    int32_t     global_id;       /* Current global id */
265    int32_t     flags;           /* Flags for this event */
266
267    int32_t     line;            /* from which line in filename */
268    const char *from;            /* From where in the code (filename) */
269
270    char       *comment;         /* Comment */
271    intptr_t    user_data;       /* Optionnal user data (will print address) */
272
273 }  lmgr_thread_event;
274
275 static int32_t global_event_id=0;
276
277 static int global_int_thread_id=0; /* Keep an integer for each thread */
278
279 /* Keep this number of event per thread */
280 #ifdef _TEST_IT
281 # define LMGR_THREAD_EVENT_MAX  15
282 #else
283 # define LMGR_THREAD_EVENT_MAX  1024
284 #endif
285
286 #define lmgr_thread_event_get_pos(x)   ((x) % LMGR_THREAD_EVENT_MAX)
287
288 class lmgr_thread_t: public SMARTALLOC
289 {
290 public:
291    dlink link;
292    pthread_mutex_t mutex;
293    pthread_t       thread_id;
294    intptr_t        int_thread_id;
295    lmgr_lock_t     lock_list[LMGR_MAX_LOCK];
296    int current;
297    int max;
298    int max_priority;
299
300    lmgr_thread_event events[LMGR_THREAD_EVENT_MAX];
301    int event_id;
302
303    lmgr_thread_t() {
304       int status;
305       if ((status = pthread_mutex_init(&mutex, NULL)) != 0) {
306          berrno be;
307          Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
308                  be.bstrerror(status));
309          ASSERT2(0, "pthread_mutex_init failed");
310       }
311       event_id = 0;
312       thread_id = pthread_self();
313       current = -1;
314       max = 0;
315       max_priority = 0;
316    }
317
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)
321    {
322       char *p;
323       int   i = lmgr_thread_event_get_pos(event_id);
324
325       events[i].flags = LMGR_EVENT_INVALID;
326       p = events[i].comment;
327       events[i].comment = (char *)"*Freed*";
328
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;
334
335       /* It means we are looping over the ring, so we need
336        * to check if the memory need to be freed
337        */
338       if (event_id >= LMGR_THREAD_EVENT_MAX) {
339          if (events[i].flags & LMGR_EVENT_FREE) {
340             free(p);
341          }
342       }
343
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 */
348
349       } else {
350          events[i].comment = (char *)comment;
351       }
352       events[i].user_data = user_data;
353       events[i].flags = flags;  /* mark it valid */
354       event_id++;
355    }
356
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);
360       char *p;
361
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*";
367             free(p);
368          }
369       }
370    }
371
372    void print_event(lmgr_thread_event *ev, FILE *fp) {
373       if (ev->flags & LMGR_EVENT_INVALID) {
374          return;
375       }
376       fprintf(fp, "    %010d id=%010d %s data=%p at %s:%d\n",
377               ev->global_id,
378               ev->id,
379               NPRT(ev->comment),
380               (void *)ev->user_data,
381               ev->from,
382               ev->line);
383    }
384
385    void _dump(FILE *fp) {
386 #ifdef HAVE_WIN32
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);
389 #else
390       fprintf(fp, "threadid=%p max=%i current=%i\n",
391               (void *)thread_id, max, current);
392 #endif
393       for(int i=0; i<=current; i++) {
394          fprintf(fp, "   lock=%p state=%s priority=%i %s:%i\n",
395                  lock_list[i].lock,
396                  (lock_list[i].state=='W')?"Wanted ":"Granted",
397                  lock_list[i].priority,
398                  lock_list[i].file, lock_list[i].line);
399       }
400
401       if (debug_flags & DEBUG_PRINT_EVENT) {
402          /* Debug events */
403          fprintf(fp, "   events:\n");
404
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++)
408             {
409                print_event(&events[i], fp);
410             }
411          }
412
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++)
415          {
416             print_event(&events[i], fp);
417          }
418       }
419    }
420
421    void dump(FILE *fp) {
422       lmgr_p(&mutex);
423       {
424          _dump(fp);
425       }
426       lmgr_v(&mutex);
427    }
428
429    /*
430     * Call before a lock operation (mark mutex as WANTED)
431     */
432    virtual void pre_P(void *m, int priority,
433                       const char *f="*unknown*", int l=0)
434    {
435       int max_prio = max_priority;
436
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);
440       }
441
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);
446       lmgr_p(&mutex);
447       {
448          current++;
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);
457       }
458       lmgr_v(&mutex);
459
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.
464        *
465        * Look the *.lockdump generated to get the list of all mutexes,
466        * and where they were granted to find the priority problem.
467        */
468       ASSERT2_p(!priority || priority >= max_prio,
469                 "Mutex priority problem found, locking done in wrong order",
470                 f, l);
471    }
472
473    /*
474     * Call after the lock operation (mark mutex as GRANTED)
475     */
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;
480    }
481
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];
486       }
487       if (current >= 0) {
488          lock_list[current].lock = NULL;
489          lock_list[current].state = LMGR_LOCK_EMPTY;
490       }
491       /* rebuild the priority list */
492       max_priority = 0;
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;
496       }
497    }
498
499    /*
500     * Remove the mutex from the list
501     */
502    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
503       int old_current = current;
504
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);
508       }
509
510       ASSERT2_p(current >= 0, "No previous P found, the mutex list is empty", f, l);
511       lmgr_p(&mutex);
512       {
513          if (lock_list[current].lock == m) {
514             lock_list[current].lock = NULL;
515             lock_list[current].state = LMGR_LOCK_EMPTY;
516             current--;
517          } else {
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);
527                   shift_list(i);
528                   current--;
529                   break;
530                }
531             }
532          }
533          /* reset max_priority to the last one */
534          if (current >= 0) {
535             max_priority = lock_list[current].max_priority;
536          } else {
537             max_priority = 0;
538          }
539       }
540       lmgr_v(&mutex);
541       /* ASSERT2 should be called outside from the mutex lock */
542       ASSERT2_p(current != old_current, "V() called without a previous P()", f, l);
543    }
544
545    virtual ~lmgr_thread_t() {destroy();}
546
547    void destroy() {
548       free_event_list();
549       pthread_mutex_destroy(&mutex);
550    }
551 } ;
552
553 class lmgr_dummy_thread_t: public lmgr_thread_t
554 {
555    void do_V(void *m, const char *file, int l)  {}
556    void post_P()                                {}
557    void pre_P(void *m, int priority, const char *file, int l) {}
558 };
559
560 /*
561  * LMGR - Lock Manager
562  *
563  *
564  *
565  */
566
567 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT;
568 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
569
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;
574
575 #define lmgr_is_active() (global_mgr != NULL)
576
577 /*
578  * Add a new lmgr_thread_t object to the global list
579  */
580 void lmgr_register_thread(lmgr_thread_t *item)
581 {
582    lmgr_p(&lmgr_global_mutex);
583    {
584       item->int_thread_id = ++global_int_thread_id;
585       global_mgr->prepend(item);
586    }
587    lmgr_v(&lmgr_global_mutex);
588 }
589
590 /*
591  * Call this function to cleanup specific lock thread data
592  */
593 void lmgr_unregister_thread(lmgr_thread_t *item)
594 {
595    if (!lmgr_is_active()) {
596       return;
597    }
598    lmgr_p(&lmgr_global_mutex);
599    {
600       global_mgr->remove(item);
601    }
602    lmgr_v(&lmgr_global_mutex);
603 }
604
605 #ifdef HAVE_WIN32
606 # define TID int_thread_id
607 #else
608 # define TID thread_id
609 #endif
610 /*
611  * Search for a deadlock when it's secure to walk across
612  * locks list. (after lmgr_detect_deadlock or a fatal signal)
613  */
614 bool lmgr_detect_deadlock_unlocked()
615 {
616    bool ret=false;
617    lmgr_node_t *node=NULL;
618    lmgr_lock_t *lock;
619    lmgr_thread_t *item;
620    dlist *g = New(dlist(node, &node->link));
621
622    /* First, get a list of all node */
623    foreach_dlist(item, global_mgr) {
624       for(int i=0; i<=item->current; i++) {
625          node = NULL;
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
630           *
631           * Note: a Mutex can be locked only once, a thread can request only
632           * one mutex.
633           *
634           */
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));
639          }
640          if (node) {
641             g->append(node);
642          }
643       }
644    }
645
646    //foreach_dlist(node, g) {
647    //   printf("g n=%p c=%p\n", node->node, node->child);
648    //}
649
650    ret = contains_cycle(g);
651    if (ret) {
652       printf("Found a deadlock !!!!\n");
653    }
654
655    delete g;
656    return ret;
657 }
658
659 /*
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.
663  */
664 bool lmgr_detect_deadlock()
665 {
666    bool ret=false;
667    if (!lmgr_is_active()) {
668       return ret;
669    }
670
671    lmgr_p(&lmgr_global_mutex);
672    {
673       lmgr_thread_t *item;
674       foreach_dlist(item, global_mgr) {
675          lmgr_p(&item->mutex);
676       }
677
678       ret = lmgr_detect_deadlock_unlocked();
679
680       foreach_dlist(item, global_mgr) {
681          lmgr_v(&item->mutex);
682       }
683    }
684    lmgr_v(&lmgr_global_mutex);
685
686    return ret;
687 }
688
689 /*
690  * !!! WARNING !!!
691  * Use this function is used only after a fatal signal
692  * We don't use locking to display the information
693  */
694 void dbg_print_lock(FILE *fp)
695 {
696    fprintf(fp, "Attempt to dump locks\n");
697    if (!lmgr_is_active()) {
698       return ;
699    }
700    lmgr_thread_t *item;
701    foreach_dlist(item, global_mgr) {
702       item->_dump(fp);
703    }
704 }
705
706 /*
707  * Dump each lmgr_thread_t object
708  */
709 void lmgr_dump()
710 {
711    lmgr_p(&lmgr_global_mutex);
712    {
713       lmgr_thread_t *item;
714       foreach_dlist(item, global_mgr) {
715          item->dump(stderr);
716       }
717    }
718    lmgr_v(&lmgr_global_mutex);
719 }
720
721 void cln_hdl(void *a)
722 {
723    lmgr_cleanup_thread();
724 }
725
726 void *check_deadlock(void *)
727 {
728    int old;
729    lmgr_init_thread();
730    pthread_cleanup_push(cln_hdl, NULL);
731
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;
738          }
739          lmgr_dump();
740          ASSERT2(0, "Lock deadlock");   /* Abort if we found a deadlock */
741       }
742       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
743       pthread_testcancel();
744    }
745    Dmsg0(100, "Exit check_deadlock.\n");
746    pthread_cleanup_pop(1);
747    return NULL;
748 }
749
750 /* This object is used when LMGR is not initialized */
751 static lmgr_dummy_thread_t dummy_lmgr;
752
753 /*
754  * Retrieve the lmgr_thread_t object from the stack
755  */
756 inline lmgr_thread_t *lmgr_get_thread_info()
757 {
758    if (lmgr_is_active()) {
759       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
760    } else {
761       return &dummy_lmgr;
762    }
763 }
764
765 /* On windows, the thread id is a struct, and sometime (for debug or openssl),
766  * we need a int
767  */
768 intptr_t bthread_get_thread_id()
769 {
770    lmgr_thread_t *self = lmgr_get_thread_info();
771    return self->int_thread_id;
772 }
773
774 /*
775  * launch once for all threads
776  */
777 void create_lmgr_key()
778 {
779    int status = pthread_key_create(&lmgr_key, NULL);
780    if (status != 0) {
781       berrno be;
782       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
783             be.bstrerror(status));
784       ASSERT2(0, "pthread_key_create failed");
785    }
786
787    lmgr_thread_t *n=NULL;
788    global_mgr = New(dlist(n, &n->link));
789
790    if (use_undertaker) {
791       status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
792       if (status != 0) {
793          berrno be;
794          Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
795                be.bstrerror(status));
796          ASSERT2(0, "pthread_create failed");
797       }
798    }
799 }
800
801 /*
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
804  */
805 void lmgr_init_thread()
806 {
807    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
808    if (status != 0) {
809       berrno be;
810       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
811             be.bstrerror(status));
812       ASSERT2(0, "pthread_once failed");
813    }
814    lmgr_thread_t *l = New(lmgr_thread_t());
815    pthread_setspecific(lmgr_key, l);
816    lmgr_register_thread(l);
817 }
818
819 /*
820  * Call this function at the end of the thread
821  */
822 void lmgr_cleanup_thread()
823 {
824    if (!lmgr_is_active()) {
825       return ;
826    }
827    lmgr_thread_t *self = lmgr_get_thread_info();
828    lmgr_unregister_thread(self);
829    delete(self);
830 }
831
832 /*
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.
836  */
837 void lmgr_cleanup_main()
838 {
839    dlist *temp;
840
841    if (!global_mgr) {
842       return;
843    }
844    if (use_undertaker) {
845       pthread_cancel(undertaker);
846 #ifdef DEVELOPER
847       /* Should avoid memory leak reporting */
848       pthread_join(undertaker, NULL);
849 #endif
850    }
851    lmgr_cleanup_thread();
852    lmgr_p(&lmgr_global_mutex);
853    {
854       temp = global_mgr;
855       global_mgr = NULL;
856       delete temp;
857    }
858    lmgr_v(&lmgr_global_mutex);
859 }
860
861 void lmgr_add_event_p(const char *comment, intptr_t user_data, int32_t flags,
862                       const char *file, int32_t line)
863 {
864    lmgr_thread_t *self = lmgr_get_thread_info();
865    self->add_event(comment, user_data, flags, file, line);
866 }
867
868 /*
869  * Set the priority of the lmgr mutex object
870  */
871 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
872 {
873 #ifdef USE_LOCKMGR_PRIORITY
874    m->priority = prio;
875 #endif
876 }
877
878 /*
879  * Replacement for pthread_mutex_init()
880  */
881 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
882 {
883    m->priority = 0;
884    return pthread_mutex_init(&m->mutex, attr);
885 }
886
887 /*
888  * Replacement for pthread_mutex_destroy()
889  */
890 int pthread_mutex_destroy(bthread_mutex_t *m)
891 {
892    return pthread_mutex_destroy(&m->mutex);
893 }
894
895 /*
896  * Replacement for pthread_kill (only with USE_LOCKMGR_SAFEKILL)
897  */
898 int bthread_kill(pthread_t thread, int sig,
899                  const char *file, int line)
900 {
901    bool thread_found_in_process=false;
902
903    /* We doesn't allow to send signal to ourself */
904    ASSERT(!pthread_equal(thread, pthread_self()));
905
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
908     */
909    lmgr_p(&lmgr_global_mutex);
910    {
911       lmgr_thread_t *item;
912       foreach_dlist(item, global_mgr) {
913          if (pthread_equal(thread, item->thread_id)) {
914             thread_found_in_process=true;
915             break;
916          }
917       }
918    }
919    lmgr_v(&lmgr_global_mutex);
920
921    /* Sending a signal to non existing thread can create problem
922     * so, we can stop here.
923     */
924    ASSERT2(thread_found_in_process, "Wanted to pthread_kill non-existant thread");
925
926    Dmsg3(100, "%s:%d send kill to existing thread %p\n", file, line, thread);
927    return pthread_kill(thread, sig);
928 }
929
930 /*
931  * Replacement for pthread_mutex_lock()
932  * Returns always ok
933  */
934 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
935 {
936    lmgr_thread_t *self = lmgr_get_thread_info();
937    self->pre_P(m, m->priority, file, line);
938    lmgr_p(&m->mutex);
939    self->post_P();
940    return 0;
941 }
942
943 /*
944  * Replacement for pthread_mutex_unlock()
945  * Returns always ok
946  */
947 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
948 {
949    lmgr_thread_t *self = lmgr_get_thread_info();
950    self->do_V(m, file, line);
951    lmgr_v(&m->mutex);
952    return 0;
953 }
954
955 /*
956  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
957  * Returns always ok
958  */
959 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
960 {
961    lmgr_thread_t *self = lmgr_get_thread_info();
962    self->pre_P(m, 0, file, line);
963    lmgr_p(m);
964    self->post_P();
965    return 0;
966 }
967
968 /*
969  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
970  * Returns always ok
971  */
972 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
973 {
974    lmgr_thread_t *self = lmgr_get_thread_info();
975    self->do_V(m, file, line);
976    lmgr_v(m);
977    return 0;
978 }
979
980
981 /* TODO: check this
982  */
983 int bthread_cond_wait_p(pthread_cond_t *cond,
984                         pthread_mutex_t *m,
985                         const char *file, int line)
986 {
987    int ret;
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);
992    self->post_P();
993    return ret;
994 }
995
996 /* TODO: check this
997  */
998 int bthread_cond_timedwait_p(pthread_cond_t *cond,
999                              pthread_mutex_t *m,
1000                              const struct timespec * abstime,
1001                              const char *file, int line)
1002 {
1003    int ret;
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);
1008    self->post_P();
1009    return ret;
1010 }
1011
1012 /* TODO: check this
1013  */
1014 int bthread_cond_wait_p(pthread_cond_t *cond,
1015                         bthread_mutex_t *m,
1016                         const char *file, int line)
1017 {
1018    int ret;
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);
1023    self->post_P();
1024    return ret;
1025 }
1026
1027 /* TODO: check this
1028  */
1029 int bthread_cond_timedwait_p(pthread_cond_t *cond,
1030                              bthread_mutex_t *m,
1031                              const struct timespec * abstime,
1032                              const char *file, int line)
1033 {
1034    int ret;
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);
1039    self->post_P();
1040    return ret;
1041 }
1042
1043 /*  Test if this mutex is locked by the current thread
1044  *  returns:
1045  *     0 - unlocked
1046  *     1 - locked by the current thread
1047  *     2 - locked by an other thread
1048  */
1049 int lmgr_mutex_is_locked(void *m)
1050 {
1051    lmgr_thread_t *self = lmgr_get_thread_info();
1052
1053    for(int i=0; i <= self->current; i++) {
1054       if (self->lock_list[i].lock == m) {
1055          return 1;              /* locked by us */
1056       }
1057    }
1058
1059    return 0;                    /* not locked by us */
1060 }
1061
1062 /*
1063  * Use this function when the caller handle the mutex directly
1064  *
1065  * lmgr_pre_lock(m, 10);
1066  * pthread_mutex_lock(m);
1067  * lmgr_post_lock(m);
1068  */
1069 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
1070 {
1071    lmgr_thread_t *self = lmgr_get_thread_info();
1072    self->pre_P(m, prio, file, line);
1073 }
1074
1075 /*
1076  * Use this function when the caller handle the mutex directly
1077  */
1078 void lmgr_post_lock()
1079 {
1080    lmgr_thread_t *self = lmgr_get_thread_info();
1081    self->post_P();
1082 }
1083
1084 /*
1085  * Do directly pre_P and post_P (used by trylock)
1086  */
1087 void lmgr_do_lock(void *m, int prio, const char *file, int line)
1088 {
1089    lmgr_thread_t *self = lmgr_get_thread_info();
1090    self->pre_P(m, prio, file, line);
1091    self->post_P();
1092 }
1093
1094 /*
1095  * Use this function when the caller handle the mutex directly
1096  */
1097 void lmgr_do_unlock(void *m)
1098 {
1099    lmgr_thread_t *self = lmgr_get_thread_info();
1100    self->do_V(m);
1101 }
1102
1103 typedef struct {
1104    void *(*start_routine)(void*);
1105    void *arg;
1106 } lmgr_thread_arg_t;
1107
1108 extern "C"
1109 void *lmgr_thread_launcher(void *x)
1110 {
1111    void *ret=NULL;
1112    lmgr_init_thread();
1113    pthread_cleanup_push(cln_hdl, NULL);
1114
1115    lmgr_thread_arg_t arg;
1116    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
1117    arg.start_routine = a->start_routine;
1118    arg.arg = a->arg;
1119    free(a);
1120
1121    ret = arg.start_routine(arg.arg);
1122    pthread_cleanup_pop(1);
1123    return ret;
1124 }
1125
1126 int lmgr_thread_create(pthread_t *thread,
1127                        const pthread_attr_t *attr,
1128                        void *(*start_routine)(void*), void *arg)
1129 {
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;
1135    a->arg = arg;
1136    return pthread_create(thread, attr, lmgr_thread_launcher, a);
1137 }
1138
1139 #else  /* USE_LOCKMGR */
1140
1141 intptr_t bthread_get_thread_id()
1142 {
1143 # ifdef HAVE_WIN32
1144    return (intptr_t)GetCurrentThreadId();
1145 # else
1146    return (intptr_t)pthread_self();
1147 # endif
1148 }
1149
1150 /*
1151  * !!! WARNING !!!
1152  * Use this function is used only after a fatal signal
1153  * We don't use locking to display information
1154  */
1155 void dbg_print_lock(FILE *fp)
1156 {
1157    Pmsg0(000, "lockmgr disabled\n");
1158 }
1159
1160 #endif  /* USE_LOCKMGR */
1161
1162 #ifdef _TEST_IT
1163
1164 #include "lockmgr.h"
1165 #undef P
1166 #undef V
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)
1170
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;
1181
1182 void *self_lock(void *temp)
1183 {
1184    P(mutex1);
1185    P(mutex1);
1186    V(mutex1);
1187
1188    return NULL;
1189 }
1190
1191 void *nolock(void *temp)
1192 {
1193    P(mutex2);
1194    sleep(5);
1195    V(mutex2);
1196    return NULL;
1197 }
1198
1199 void *locker(void *temp)
1200 {
1201    bthread_mutex_t *m = (bthread_mutex_t*) temp;
1202    P(*m);
1203    V(*m);
1204    return NULL;
1205 }
1206
1207 void *rwlocker(void *temp)
1208 {
1209    brwlock_t *m = (brwlock_t*) temp;
1210    rwl_writelock(m);
1211    rwl_writelock(m);
1212
1213    rwl_writeunlock(m);
1214    rwl_writeunlock(m);
1215    return NULL;
1216 }
1217
1218 void *mix_rwl_mutex(void *temp)
1219 {
1220    brwlock_t *m = (brwlock_t*) temp;
1221    P(mutex1);
1222    rwl_writelock(m);
1223    rwl_writeunlock(m);
1224    V(mutex1);
1225    return NULL;
1226 }
1227
1228
1229 void *th2(void *temp)
1230 {
1231    P(mutex2);
1232    P(mutex1);
1233
1234    lmgr_dump();
1235
1236    sleep(10);
1237
1238    V(mutex1);
1239    V(mutex2);
1240
1241    lmgr_dump();
1242    return NULL;
1243 }
1244 void *th1(void *temp)
1245 {
1246    P(mutex1);
1247    sleep(2);
1248    P(mutex2);
1249
1250    lmgr_dump();
1251
1252    sleep(10);
1253
1254    V(mutex2);
1255    V(mutex1);
1256
1257    lmgr_dump();
1258    return NULL;
1259 }
1260
1261 void *thx(void *temp)
1262 {
1263    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1264    P(mutex1);
1265    bmicrosleep(0,s);
1266    P(mutex2);
1267    bmicrosleep(0,s);
1268
1269    V(mutex2);
1270    V(mutex1);
1271    return NULL;
1272 }
1273
1274 void *th3(void *a) {
1275    while (1) {
1276       fprintf(stderr, "undertaker sleep()\n");
1277       sleep(10);
1278       lmgr_dump();
1279       if (lmgr_detect_deadlock()) {
1280          lmgr_dump();
1281          exit(1);
1282       }
1283    }
1284    return NULL;
1285 }
1286
1287 void *th_prio(void *a) {
1288    char buf[512];
1289    bstrncpy(buf, my_prog, sizeof(buf));
1290    bstrncat(buf, " priority", sizeof(buf));
1291    intptr_t ret = system(buf);
1292    return (void*) ret;
1293 }
1294
1295 void *th_event1(void *a) {
1296    for (int i=0; i < 10000; i++) {
1297       if ((i % 7) == 0) {
1298          lmgr_add_event_flag("strdup test", i, LMGR_EVENT_DUP);
1299       } else {
1300          lmgr_add_event("My comment", i);
1301       }
1302    }
1303    sleep(5);
1304    return NULL;
1305 }
1306
1307 void *th_event2(void *a) {
1308    for (int i=0; i < 10000; i++) {
1309       if ((i % 2) == 0) {
1310          lmgr_add_event_flag(bstrdup("free test"), i, LMGR_EVENT_FREE);
1311       } else {
1312          lmgr_add_event("My comment", i);
1313       }
1314    }
1315    sleep(5);
1316    return NULL;
1317 }
1318
1319 int err=0;
1320 int nb=0;
1321 void _ok(const char *file, int l, const char *op, int value, const char *label)
1322 {
1323    nb++;
1324    if (!value) {
1325       err++;
1326       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1327    } else {
1328       printf("OK  %.30s\n", label);
1329    }
1330 }
1331
1332 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1333
1334 void _nok(const char *file, int l, const char *op, int value, const char *label)
1335 {
1336    nb++;
1337    if (value) {
1338       err++;
1339       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1340    } else {
1341       printf("OK  %.30s\n", label);
1342    }
1343 }
1344
1345 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1346
1347 int report()
1348 {
1349    printf("Result %i/%i OK\n", nb - err, nb);
1350    return err>0;
1351 }
1352
1353 /*
1354  * TODO:
1355  *  - Must detect multiple lock
1356  *  - lock/unlock in wrong order
1357  *  - deadlock with 2 or 3 threads
1358  */
1359 int main(int argc, char **argv)
1360 {
1361    void *ret=NULL;
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;
1366    debug_level = 10;
1367    my_prog = argv[0];
1368
1369    use_undertaker = false;
1370    lmgr_init_thread();
1371    self = lmgr_get_thread_info();
1372
1373    if (argc == 2) {             /* do priority check */
1374       P(mutex_p2);                /* not permited */
1375       P(mutex_p1);
1376       V(mutex_p1);                /* never goes here */
1377       V(mutex_p2);
1378       return 0;
1379    }
1380
1381    pthread_mutex_init(&bmutex1, NULL);
1382    bthread_mutex_set_priority(&bmutex1, 10);
1383
1384    pthread_mutex_init(&pmutex2, NULL);
1385    P(bmutex1);
1386    ok(self->max_priority == 10, "Check self max_priority");
1387    P(pmutex2);
1388    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1389    V(pmutex2);
1390    V(bmutex1);
1391    ok(self->max_priority == 0, "Check self max_priority");
1392
1393    pthread_create(&id1, NULL, self_lock, NULL);
1394    sleep(2);
1395    ok(lmgr_detect_deadlock(), "Check self deadlock");
1396    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1397    pthread_join(id1, NULL);
1398
1399
1400    pthread_create(&id1, NULL, nolock, NULL);
1401    sleep(2);
1402    nok(lmgr_detect_deadlock(), "Check for nolock");
1403    pthread_join(id1, NULL);
1404
1405    P(mutex1);
1406    pthread_create(&id1, NULL, locker, &mutex1);
1407    pthread_create(&id2, NULL, locker, &mutex1);
1408    pthread_create(&id3, NULL, locker, &mutex1);
1409    sleep(2);
1410    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1411    V(mutex1);
1412    pthread_join(id1, NULL);
1413    pthread_join(id2, NULL);
1414    pthread_join(id3, NULL);
1415
1416
1417    brwlock_t wr;
1418    rwl_init(&wr);
1419    rwl_writelock(&wr);
1420    rwl_writelock(&wr);
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");
1429
1430    pthread_join(id1, NULL);
1431    pthread_join(id2, NULL);
1432    pthread_join(id3, NULL);
1433
1434    rwl_writelock(&wr);
1435    P(mutex1);
1436    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1437    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1438    V(mutex1);
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);
1443
1444    P(mutex5);
1445    P(mutex6);
1446    V(mutex5);
1447    V(mutex6);
1448
1449    nok(lmgr_detect_deadlock(), "Check for wrong order");
1450
1451    for(int j=0; j<200; j++) {
1452       pthread_create(&tab[j], NULL, thx, NULL);
1453    }
1454    for(int j=0; j<200; j++) {
1455       pthread_join(tab[j], NULL);
1456       if (j%3) { lmgr_detect_deadlock();}
1457    }
1458    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1459
1460    P(mutex4);
1461    P(mutex5);
1462    P(mutex6);
1463    ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked");
1464    V(mutex6);
1465    ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is locked");
1466    V(mutex5);
1467    V(mutex4);
1468
1469    pthread_create(&id1, NULL, th1, NULL);
1470    sleep(1);
1471    pthread_create(&id2, NULL, th2, NULL);
1472    sleep(1);
1473    ok(lmgr_detect_deadlock(), "Check for deadlock");
1474
1475    pthread_create(&id3, NULL, th_prio, NULL);
1476    pthread_join(id3, &ret);
1477    ok(ret != 0, "Check for priority segfault");
1478
1479    P(mutex_p1);
1480    ok(self->max_priority == 1, "Check max_priority 1/4");
1481    P(mutex_p2);
1482    ok(self->max_priority == 2, "Check max_priority 2/4");
1483    P(mutex_p3);
1484    ok(self->max_priority == 3, "Check max_priority 3/4");
1485    P(mutex6);
1486    ok(self->max_priority == 3, "Check max_priority 4/4");
1487    V(mutex6);
1488    ok(self->max_priority == 3, "Check max_priority 1/5");
1489    V(mutex_p3);
1490    ok(self->max_priority == 2, "Check max_priority 4/5");
1491    V(mutex_p2);
1492    ok(self->max_priority == 1, "Check max_priority 4/5");
1493    V(mutex_p1);
1494    ok(self->max_priority == 0, "Check max_priority 5/5");
1495
1496
1497    P(mutex_p1);
1498    P(mutex_p2);
1499    P(mutex_p3);
1500    P(mutex6);
1501    ok(self->max_priority == 3, "Check max_priority mixed");
1502    V(mutex_p2);
1503    ok(self->max_priority == 3, "Check max_priority mixed");
1504    V(mutex_p1);
1505    ok(self->max_priority == 3, "Check max_priority mixed");
1506    V(mutex_p3);
1507    ok(self->max_priority == 0, "Check max_priority mixed");
1508    V(mutex6);
1509    ok(self->max_priority == 0, "Check max_priority mixed");
1510
1511    P(mutex_p1);
1512    P(mutex_p2);
1513    V(mutex_p1);
1514    V(mutex_p2);
1515
1516    for (int i=0; i < 10000; i++) {
1517       if ((i % 7) == 0) {
1518          lmgr_add_event_flag("xxxxxxxxxxxxxxxx strdup test xxxxxxxxxxxxxxxx", i, LMGR_EVENT_DUP);
1519       } else {
1520          lmgr_add_event("My comment", i);
1521       }
1522    }
1523
1524    pthread_create(&id4, NULL, th_event1, NULL);
1525    pthread_create(&id5, NULL, th_event2, NULL);
1526
1527    sleep(2);
1528
1529    lmgr_dump();
1530
1531    pthread_join(id4, NULL);
1532    pthread_join(id5, NULL);
1533
1534 //
1535 //   pthread_create(&id3, NULL, th3, NULL);
1536 //
1537 //   pthread_join(id1, NULL);
1538 //   pthread_join(id2, NULL);
1539    lmgr_cleanup_main();
1540    sm_check(__FILE__, __LINE__, false);
1541    return report();
1542 }
1543
1544 #endif