]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Fix bug #1501 -t does not print errors
[bacula/bacula] / bacula / src / lib / lockmgr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation, which is 
11    listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 /*
30   How to use mutex with bad order usage detection
31  ------------------------------------------------
32
33  Instead of using:
34     pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
35     P(mutex);
36     ..
37     V(mutex);
38
39  use:
40     bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
41     P(mutex);
42     ...
43     V(mutex);
44
45  Mutex that doesn't need this extra check can be declared as pthread_mutex_t.
46  You can use this object on pthread_mutex_lock/unlock/cond_wait/cond_timewait.
47  
48  With dynamic creation, you can use:
49     bthread_mutex_t mutex;
50     pthread_mutex_init(&mutex);
51     bthread_mutex_set_priority(&mutex, 10);
52     pthread_mutex_destroy(&mutex);
53  
54  */
55
56 #define _LOCKMGR_COMPLIANT
57 #include "bacula.h"
58
59 #undef ASSERT
60 #define ASSERT(x) if (!(x)) { \
61    char *jcr = NULL; \
62    Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
63    jcr[0] = 0; }
64
65 #define ASSERT_p(x,f,l) if (!(x)) {              \
66    char *jcr = NULL; \
67    Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
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 -D_USE_LOCKMGR -D_TEST_IT
83   g++ -o lockmgr lockmgr.o -lbac -L../lib/.libs -lssl -lpthread
84
85 */
86
87
88 /*
89  * pthread_mutex_lock for memory allocator and other
90  * parts that are _LOCKMGR_COMPLIANT
91  */
92 void lmgr_p(pthread_mutex_t *m)
93 {
94    int errstat;
95    if ((errstat=pthread_mutex_lock(m))) {
96       berrno be;
97       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
98             be.bstrerror(errstat));
99    }
100 }
101
102 void lmgr_v(pthread_mutex_t *m)
103 {
104    int errstat;
105    if ((errstat=pthread_mutex_unlock(m))) {
106       berrno be;
107       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
108             be.bstrerror(errstat));
109    }
110 }
111
112 #ifdef _USE_LOCKMGR
113
114 typedef enum
115 {
116    LMGR_WHITE,                  /* never seen */
117    LMGR_BLACK,                  /* no loop */
118    LMGR_GREY,                   /* seen before */
119 } lmgr_color_t;
120
121 /*
122  * Node used by the Lock Manager
123  * If the lock is GRANTED, we have mutex -> proc, else it's a proc -> mutex
124  * relation.
125  *
126  * Note, each mutex can be GRANTED once, and each proc can have only one WANTED
127  * mutex.
128  */
129 class lmgr_node_t: public SMARTALLOC
130 {
131 public:
132    dlink link;
133    void *node;
134    void *child;
135    lmgr_color_t seen;
136
137    lmgr_node_t() {
138       child = node = NULL;
139       seen = LMGR_WHITE;
140    }
141
142    lmgr_node_t(void *n, void *c) {
143       init(n,c);
144    }
145
146    void init(void *n, void *c) {
147       node = n;
148       child = c;
149       seen = LMGR_WHITE;      
150    }
151
152    void mark_as_seen(lmgr_color_t c) {
153       seen = c;
154    }
155
156    ~lmgr_node_t() {printf("delete node\n");}
157 };
158
159 typedef enum {
160    LMGR_LOCK_EMPTY   = 'E',      /* unused */
161    LMGR_LOCK_WANTED  = 'W',      /* before mutex_lock */
162    LMGR_LOCK_GRANTED = 'G'       /* after mutex_lock */
163 } lmgr_state_t;
164
165 /*
166  * Object associated with each mutex per thread
167  */
168 class lmgr_lock_t: public SMARTALLOC
169 {
170 public:
171    dlink link;
172    void *lock;
173    lmgr_state_t state;
174    int max_priority;
175    int priority;
176
177    const char *file;
178    int line;
179
180    lmgr_lock_t() {
181       lock = NULL;
182       state = LMGR_LOCK_EMPTY;
183       priority = max_priority = 0;
184    }
185
186    lmgr_lock_t(void *l) {
187       lock = l;
188       state = LMGR_LOCK_WANTED;
189    }
190
191    void set_granted() {
192       state = LMGR_LOCK_GRANTED;
193    }
194
195    ~lmgr_lock_t() {}
196
197 };
198
199 /* 
200  * Get the child list, ret must be already allocated
201  */
202 static void search_all_node(dlist *g, lmgr_node_t *v, alist *ret)
203 {
204    lmgr_node_t *n;
205    foreach_dlist(n, g) {
206       if (v->child == n->node) {
207          ret->append(n);
208       }
209    }
210 }
211
212 static bool visite(dlist *g, lmgr_node_t *v)
213 {
214    bool ret=false;
215    lmgr_node_t *n;
216    v->mark_as_seen(LMGR_GREY);
217
218    alist *d = New(alist(5, false)); /* use alist because own=false */
219    search_all_node(g, v, d);
220
221    //foreach_alist(n, d) {
222    //   printf("node n=%p c=%p s=%c\n", n->node, n->child, n->seen);
223    //}
224
225    foreach_alist(n, d) {
226       if (n->seen == LMGR_GREY) { /* already seen this node */
227          ret = true;
228          goto bail_out;
229       } else if (n->seen == LMGR_WHITE) {
230          if (visite(g, n)) {
231             ret = true;
232             goto bail_out;
233          }
234       }
235    }
236    v->mark_as_seen(LMGR_BLACK); /* no loop detected, node is clean */
237 bail_out:
238    delete d;
239    return ret;
240 }
241
242 static bool contains_cycle(dlist *g)
243 {
244    lmgr_node_t *n;
245    foreach_dlist(n, g) {
246       if (n->seen == LMGR_WHITE) {
247          if (visite(g, n)) {
248             return true;
249          }
250       }
251    }
252    return false;
253 }
254
255 /****************************************************************/
256
257 class lmgr_thread_t: public SMARTALLOC
258 {
259 public:
260    dlink link;
261    pthread_mutex_t mutex;
262    pthread_t       thread_id;
263    lmgr_lock_t     lock_list[LMGR_MAX_LOCK];
264    int current;
265    int max;
266    int max_priority;
267
268    lmgr_thread_t() {
269       int status;
270       if ((status = pthread_mutex_init(&mutex, NULL)) != 0) {
271          berrno be;
272          Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
273                  be.bstrerror(status));
274          ASSERT(0);
275       }
276       thread_id = pthread_self();
277       current = -1;
278       max = 0;
279       max_priority = 0;
280    }
281
282    void _dump(FILE *fp) {
283       fprintf(fp, "threadid=%p max=%i current=%i\n", 
284               (void *)thread_id, max, current);
285       for(int i=0; i<=current; i++) {
286          fprintf(fp, "   lock=%p state=%s priority=%i %s:%i\n", 
287                  lock_list[i].lock, 
288                  (lock_list[i].state=='W')?"Wanted ":"Granted",
289                  lock_list[i].priority,
290                  lock_list[i].file, lock_list[i].line);
291       } 
292    }
293
294    void dump(FILE *fp) {
295       lmgr_p(&mutex);
296       {
297          _dump(fp);
298       }
299       lmgr_v(&mutex);
300    }
301
302    /*
303     * Call before a lock operation (mark mutex as WANTED)
304     */
305    virtual void pre_P(void *m, int priority, 
306                       const char *f="*unknown*", int l=0) 
307    {
308       int max_prio = max_priority;
309       ASSERT_p(current < LMGR_MAX_LOCK, f, l);
310       ASSERT_p(current >= -1, f, l);
311       lmgr_p(&mutex);
312       {
313          current++;
314          lock_list[current].lock = m;
315          lock_list[current].state = LMGR_LOCK_WANTED;
316          lock_list[current].file = f;
317          lock_list[current].line = l;
318          lock_list[current].priority = priority;
319          lock_list[current].max_priority = MAX(priority, max_priority);
320          max = MAX(current, max);
321          max_priority = MAX(priority, max_priority);
322       }
323       lmgr_v(&mutex);
324       ASSERT_p(!priority || priority >= max_prio, f, l);
325    }
326
327    /*
328     * Call after the lock operation (mark mutex as GRANTED)
329     */
330    virtual void post_P() {
331       ASSERT(current >= 0);
332       ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
333       lock_list[current].state = LMGR_LOCK_GRANTED;
334    }
335    
336    /* Using this function is some sort of bug */
337    void shift_list(int i) {
338       for(int j=i+1; j<=current; j++) {
339          lock_list[i] = lock_list[j];
340       }
341       if (current >= 0) {
342          lock_list[current].lock = NULL;
343          lock_list[current].state = LMGR_LOCK_EMPTY;
344       }
345       /* rebuild the priority list */
346       max_priority = 0;
347       for(int j=0; j< current; j++) {
348          max_priority = MAX(lock_list[j].priority, max_priority);
349          lock_list[j].max_priority = max_priority;
350       }
351    }
352
353    /*
354     * Remove the mutex from the list
355     */
356    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
357       ASSERT_p(current >= 0, f, l);
358       lmgr_p(&mutex);
359       {
360          if (lock_list[current].lock == m) {
361             lock_list[current].lock = NULL;
362             lock_list[current].state = LMGR_LOCK_EMPTY;
363             current--;
364          } else {
365             ASSERT(current > 0);
366             Pmsg3(0, "ERROR: wrong P/V order search lock=%p %s:%i\n", m, f, l);
367             Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
368                     current, lock_list[current].lock, lock_list[current].file, 
369                     lock_list[current].line);
370             for (int i=current-1; i >= 0; i--) { /* already seen current */
371                Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
372                      i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
373                if (lock_list[i].lock == m) {
374                   Pmsg3(000, "ERROR: FOUND P pos=%i %s:%i\n", i, f, l);
375                   shift_list(i);
376                   current--;
377                   break;
378                }
379             }
380          }
381          /* reset max_priority to the last one */
382          if (current >= 0) {
383             max_priority = lock_list[current].max_priority; 
384          } else {
385             max_priority = 0;
386          }
387       }
388       lmgr_v(&mutex);
389    }
390
391    virtual ~lmgr_thread_t() {destroy();}
392
393    void destroy() {
394       pthread_mutex_destroy(&mutex);
395    }
396 } ;
397
398 class lmgr_dummy_thread_t: public lmgr_thread_t
399 {
400    void do_V(void *m, const char *file, int l)  {}
401    void post_P()                                {}
402    void pre_P(void *m, int priority, const char *file, int l) {}
403 };
404
405 /*
406  * LMGR - Lock Manager
407  *
408  *
409  *
410  */
411
412 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT; 
413 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
414
415 static dlist *global_mgr = NULL;  /* used to store all lgmr_thread_t objects */
416 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
417 static pthread_t undertaker;
418 static bool use_undertaker=true;
419
420 #define lmgr_is_active() (global_mgr != NULL)
421
422 /*
423  * Add a new lmgr_thread_t object to the global list
424  */
425 void lmgr_register_thread(lmgr_thread_t *item)
426 {
427    lmgr_p(&lmgr_global_mutex);
428    {
429       global_mgr->prepend(item);
430    }
431    lmgr_v(&lmgr_global_mutex);
432 }
433
434 /*
435  * Call this function to cleanup specific lock thread data
436  */
437 void lmgr_unregister_thread(lmgr_thread_t *item)
438 {
439    if (!lmgr_is_active()) {
440       return;
441    }
442    lmgr_p(&lmgr_global_mutex);
443    {
444       global_mgr->remove(item);
445    }
446    lmgr_v(&lmgr_global_mutex);
447 }
448
449 /*
450  * Search for a deadlock when it's secure to walk across
451  * locks list. (after lmgr_detect_deadlock or a fatal signal)
452  */
453 bool lmgr_detect_deadlock_unlocked()
454 {
455    bool ret=false;
456    lmgr_node_t *node=NULL;
457    lmgr_lock_t *lock;
458    lmgr_thread_t *item;
459    dlist *g = New(dlist(node, &node->link));
460
461    /* First, get a list of all node */
462    foreach_dlist(item, global_mgr) {
463       for(int i=0; i<=item->current; i++) {
464          node = NULL;
465          lock = &item->lock_list[i];
466          /* Depending if the lock is granted or not, it's a child or a root
467           *  Granted:  Mutex  -> Thread
468           *  Wanted:   Thread -> Mutex
469           *
470           * Note: a Mutex can be locked only once, a thread can request only
471           * one mutex.
472           *
473           */
474          if (lock->state == LMGR_LOCK_GRANTED) {
475             node = New(lmgr_node_t((void*)lock->lock, (void*)item->thread_id));
476          } else if (lock->state == LMGR_LOCK_WANTED) {
477             node = New(lmgr_node_t((void*)item->thread_id, (void*)lock->lock));
478          }
479          if (node) {
480             g->append(node);
481          }
482       }
483    }      
484    
485    //foreach_dlist(node, g) {
486    //   printf("g n=%p c=%p\n", node->node, node->child);
487    //}
488
489    ret = contains_cycle(g);
490    if (ret) {
491       printf("Found a deadlock !!!!\n");
492    }
493    
494    delete g;
495    return ret;
496 }
497
498 /*
499  * Search for a deadlock in during the runtime
500  * It will lock all thread specific lock manager, nothing
501  * can be locked during this check.
502  */
503 bool lmgr_detect_deadlock()
504 {
505    bool ret=false;
506    if (!lmgr_is_active()) {
507       return ret;
508    } 
509
510    lmgr_p(&lmgr_global_mutex);
511    {
512       lmgr_thread_t *item;
513       foreach_dlist(item, global_mgr) {
514          lmgr_p(&item->mutex);
515       }
516
517       ret = lmgr_detect_deadlock_unlocked();
518
519       foreach_dlist(item, global_mgr) {
520          lmgr_v(&item->mutex);
521       }
522    }
523    lmgr_v(&lmgr_global_mutex);
524
525    return ret;
526 }
527
528 /*
529  * !!! WARNING !!! 
530  * Use this function is used only after a fatal signal
531  * We don't use locking to display the information
532  */
533 void dbg_print_lock(FILE *fp)
534 {
535    fprintf(fp, "Attempt to dump locks\n");
536    if (!lmgr_is_active()) {
537       return ;
538    }
539    lmgr_thread_t *item;
540    foreach_dlist(item, global_mgr) {
541       item->_dump(fp);
542    }
543 }
544
545 /*
546  * Dump each lmgr_thread_t object
547  */
548 void lmgr_dump()
549 {
550    lmgr_p(&lmgr_global_mutex);
551    {
552       lmgr_thread_t *item;
553       foreach_dlist(item, global_mgr) {
554          item->dump(stderr);
555       }
556    }
557    lmgr_v(&lmgr_global_mutex);
558 }
559
560 void cln_hdl(void *a)
561 {
562    lmgr_cleanup_thread();
563 }
564
565 void *check_deadlock(void *)
566 {
567    int old;
568    lmgr_init_thread();
569    pthread_cleanup_push(cln_hdl, NULL);
570
571    while (!bmicrosleep(30, 0)) {
572       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
573       if (lmgr_detect_deadlock()) {
574          lmgr_dump();
575          ASSERT(0);
576       }
577       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
578       pthread_testcancel();
579    }
580    Pmsg0(000, "Undertaker is leaving...\n");
581    pthread_cleanup_pop(1);
582    return NULL;
583 }
584
585 /* This object is used when LMGR is not initialized */
586 static lmgr_dummy_thread_t dummy_lmgr;
587
588 /*
589  * Retrieve the lmgr_thread_t object from the stack
590  */
591 inline lmgr_thread_t *lmgr_get_thread_info()
592 {
593    if (lmgr_is_active()) {
594       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
595    } else {
596       return &dummy_lmgr;
597    }
598 }
599
600 /*
601  * launch once for all threads
602  */
603 void create_lmgr_key()
604 {
605    int status = pthread_key_create(&lmgr_key, NULL);
606    if (status != 0) {
607       berrno be;
608       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
609             be.bstrerror(status));
610       ASSERT(0);
611    }
612
613    lmgr_thread_t *n=NULL;
614    global_mgr = New(dlist(n, &n->link));
615
616    if (use_undertaker) {
617       status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
618       if (status != 0) {
619          berrno be;
620          Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
621                be.bstrerror(status));
622          ASSERT(0);
623       }
624    }
625 }
626
627 /*
628  * Each thread have to call this function to put a lmgr_thread_t object
629  * in the stack and be able to call mutex_lock/unlock
630  */
631 void lmgr_init_thread()
632 {
633    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
634    if (status != 0) {
635       berrno be;
636       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
637             be.bstrerror(status));
638       ASSERT(0);
639    }
640    lmgr_thread_t *l = New(lmgr_thread_t());
641    pthread_setspecific(lmgr_key, l);
642    lmgr_register_thread(l);
643 }
644
645 /*
646  * Call this function at the end of the thread
647  */
648 void lmgr_cleanup_thread()
649 {
650    if (!lmgr_is_active()) {
651       return ;
652    }
653    lmgr_thread_t *self = lmgr_get_thread_info();
654    lmgr_unregister_thread(self);
655    delete(self);
656 }
657
658 /*
659  * This function should be call at the end of the main thread
660  * Some thread like the watchdog are already present, so the global_mgr
661  * list is never empty. Should carefully clear the memory.
662  */
663 void lmgr_cleanup_main()
664 {
665    dlist *temp;
666    
667    if (!global_mgr) {
668       return;
669    }
670    if (use_undertaker) {
671       pthread_cancel(undertaker);
672    }
673    lmgr_cleanup_thread();
674    lmgr_p(&lmgr_global_mutex);
675    {
676       temp = global_mgr;
677       global_mgr = NULL;
678       delete temp;
679    }
680    lmgr_v(&lmgr_global_mutex);
681 }
682
683 /* 
684  * Set the priority of the lmgr mutex object
685  */
686 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
687 {
688 #ifdef USE_LOCKMGR_PRIORITY
689    m->priority = prio;
690 #endif
691 }
692
693 /*
694  * Replacement for pthread_mutex_init()
695  */
696 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
697 {
698    m->priority = 0;
699    return pthread_mutex_init(&m->mutex, attr);
700 }
701
702 /*
703  * Replacement for pthread_mutex_destroy()
704  */
705 int pthread_mutex_destroy(bthread_mutex_t *m)
706 {
707    return pthread_mutex_destroy(&m->mutex);
708 }
709
710 /*
711  * Replacement for pthread_mutex_lock()
712  * Returns always ok 
713  */
714 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
715 {
716    lmgr_thread_t *self = lmgr_get_thread_info();
717    self->pre_P(m, m->priority, file, line);
718    lmgr_p(&m->mutex);
719    self->post_P();   
720    return 0;
721 }
722
723 /*
724  * Replacement for pthread_mutex_unlock()
725  * Returns always ok
726  */
727 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
728 {
729    lmgr_thread_t *self = lmgr_get_thread_info();
730    self->do_V(m, file, line);
731    lmgr_v(&m->mutex);
732    return 0;
733 }
734
735 /*
736  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
737  * Returns always ok 
738  */
739 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
740 {
741    lmgr_thread_t *self = lmgr_get_thread_info();
742    self->pre_P(m, 0, file, line);
743    lmgr_p(m);
744    self->post_P();   
745    return 0;
746 }
747
748 /*
749  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
750  * Returns always ok
751  */
752 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
753 {
754    lmgr_thread_t *self = lmgr_get_thread_info();
755    self->do_V(m, file, line);
756    lmgr_v(m);
757    return 0;
758 }
759
760
761 /* TODO: check this
762  */
763 int bthread_cond_wait_p(pthread_cond_t *cond,
764                         pthread_mutex_t *m,
765                         const char *file, int line)
766 {
767    int ret;
768    lmgr_thread_t *self = lmgr_get_thread_info();
769    self->do_V(m, file, line);   
770    ret = pthread_cond_wait(cond, m);
771    self->pre_P(m, 0, file, line);
772    self->post_P();
773    return ret;
774 }
775
776 /* TODO: check this
777  */
778 int bthread_cond_timedwait_p(pthread_cond_t *cond,
779                              pthread_mutex_t *m,
780                              const struct timespec * abstime,
781                              const char *file, int line)
782 {
783    int ret;
784    lmgr_thread_t *self = lmgr_get_thread_info();
785    self->do_V(m, file, line);   
786    ret = pthread_cond_timedwait(cond, m, abstime);
787    self->pre_P(m, 0, file, line);
788    self->post_P();
789    return ret;
790 }
791
792 /* TODO: check this
793  */
794 int bthread_cond_wait_p(pthread_cond_t *cond,
795                         bthread_mutex_t *m,
796                         const char *file, int line)
797 {
798    int ret;
799    lmgr_thread_t *self = lmgr_get_thread_info();
800    self->do_V(m, file, line);   
801    ret = pthread_cond_wait(cond, &m->mutex);
802    self->pre_P(m, m->priority, file, line);
803    self->post_P();
804    return ret;
805 }
806
807 /* TODO: check this
808  */
809 int bthread_cond_timedwait_p(pthread_cond_t *cond,
810                              bthread_mutex_t *m,
811                              const struct timespec * abstime,
812                              const char *file, int line)
813 {
814    int ret;
815    lmgr_thread_t *self = lmgr_get_thread_info();
816    self->do_V(m, file, line);   
817    ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
818    self->pre_P(m, m->priority, file, line);
819    self->post_P();
820    return ret;
821 }
822
823 /*
824  * Use this function when the caller handle the mutex directly
825  *
826  * lmgr_pre_lock(m, 10);
827  * pthread_mutex_lock(m);
828  * lmgr_post_lock(m);
829  */
830 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
831 {
832    lmgr_thread_t *self = lmgr_get_thread_info();
833    self->pre_P(m, prio, file, line);
834 }
835
836 /*
837  * Use this function when the caller handle the mutex directly
838  */
839 void lmgr_post_lock()
840 {
841    lmgr_thread_t *self = lmgr_get_thread_info();
842    self->post_P();
843 }
844
845 /*
846  * Do directly pre_P and post_P (used by trylock)
847  */
848 void lmgr_do_lock(void *m, int prio, const char *file, int line)
849 {
850    lmgr_thread_t *self = lmgr_get_thread_info();
851    self->pre_P(m, prio, file, line);
852    self->post_P();
853 }
854
855 /*
856  * Use this function when the caller handle the mutex directly
857  */
858 void lmgr_do_unlock(void *m)
859 {
860    lmgr_thread_t *self = lmgr_get_thread_info();
861    self->do_V(m);
862 }
863
864 typedef struct {
865    void *(*start_routine)(void*);
866    void *arg;
867 } lmgr_thread_arg_t;
868
869 extern "C" 
870 void *lmgr_thread_launcher(void *x)
871 {
872    void *ret=NULL;
873    lmgr_init_thread();
874    pthread_cleanup_push(cln_hdl, NULL);
875
876    lmgr_thread_arg_t arg;
877    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
878    arg.start_routine = a->start_routine;
879    arg.arg = a->arg;
880    free(a);
881
882    ret = arg.start_routine(arg.arg);
883    pthread_cleanup_pop(1);
884    return ret;
885 }
886
887 int lmgr_thread_create(pthread_t *thread,
888                        const pthread_attr_t *attr,
889                        void *(*start_routine)(void*), void *arg)
890 {
891    /* lmgr should be active (lmgr_init_thread() call in main()) */
892    ASSERT(lmgr_is_active());
893    /* Will be freed by the child */
894    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
895    a->start_routine = start_routine;
896    a->arg = arg;
897    return pthread_create(thread, attr, lmgr_thread_launcher, a);
898 }
899
900 #else  /* _USE_LOCKMGR */
901
902 /*
903  * !!! WARNING !!! 
904  * Use this function is used only after a fatal signal
905  * We don't use locking to display information
906  */
907 void dbg_print_lock(FILE *fp)
908 {
909    Pmsg0(000, "lockmgr disabled\n");
910 }
911
912 #endif  /* _USE_LOCKMGR */
913
914 #ifdef _TEST_IT
915
916 #include "lockmgr.h"
917 #define BTHREAD_MUTEX_NO_PRIORITY      {PTHREAD_MUTEX_INITIALIZER, 0}
918 #define BTHREAD_MUTEX_PRIORITY(p)      {PTHREAD_MUTEX_INITIALIZER, p}
919 #undef P
920 #undef V
921 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
922 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
923 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
924
925 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
926 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
927 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
928 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
929 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
930 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
931 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
932 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
933 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
934 static const char *my_prog;
935
936 void *self_lock(void *temp)
937 {
938    P(mutex1);
939    P(mutex1);
940    V(mutex1);
941    
942    return NULL;
943 }
944
945 void *nolock(void *temp)
946 {
947    P(mutex2);
948    sleep(5);
949    V(mutex2);
950    return NULL;
951 }
952
953 void *locker(void *temp)
954 {
955    bthread_mutex_t *m = (bthread_mutex_t*) temp;
956    P(*m);
957    V(*m);
958    return NULL;
959 }
960
961 void *rwlocker(void *temp)
962 {
963    brwlock_t *m = (brwlock_t*) temp;
964    rwl_writelock(m);
965    rwl_writelock(m);
966
967    rwl_writeunlock(m);
968    rwl_writeunlock(m);
969    return NULL;
970 }
971
972 void *mix_rwl_mutex(void *temp)
973 {
974    brwlock_t *m = (brwlock_t*) temp;
975    P(mutex1);
976    rwl_writelock(m);
977    rwl_writeunlock(m);
978    V(mutex1);
979    return NULL;
980 }
981
982
983 void *th2(void *temp)
984 {
985    P(mutex2);
986    P(mutex1);
987    
988    lmgr_dump();
989
990    sleep(10);
991
992    V(mutex1);
993    V(mutex2);
994
995    lmgr_dump();
996    return NULL;
997 }
998 void *th1(void *temp)
999 {
1000    P(mutex1);
1001    sleep(2);
1002    P(mutex2);
1003    
1004    lmgr_dump();
1005
1006    sleep(10);
1007
1008    V(mutex2);
1009    V(mutex1);
1010
1011    lmgr_dump();
1012    return NULL;
1013 }
1014
1015 void *thx(void *temp)
1016 {
1017    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1018    P(mutex1);
1019    bmicrosleep(0,s);
1020    P(mutex2);
1021    bmicrosleep(0,s);
1022
1023    V(mutex2);
1024    V(mutex1);
1025    return NULL;
1026 }
1027
1028 void *th3(void *a) {
1029    while (1) {
1030       fprintf(stderr, "undertaker sleep()\n");
1031       sleep(10);
1032       lmgr_dump();
1033       if (lmgr_detect_deadlock()) {
1034          lmgr_dump();
1035          exit(1);
1036       }
1037    }
1038    return NULL;
1039 }
1040
1041 void *th_prio(void *a) {
1042    char buf[512];
1043    bstrncpy(buf, my_prog, sizeof(buf));
1044    bstrncat(buf, " priority", sizeof(buf));
1045    int ret = system(buf);
1046    return (void*) ret;
1047 }
1048
1049 int err=0;
1050 int nb=0;
1051 void _ok(const char *file, int l, const char *op, int value, const char *label)
1052 {
1053    nb++;
1054    if (!value) {
1055       err++;
1056       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1057    } else {
1058       printf("OK  %.30s\n", label);
1059    }
1060 }
1061
1062 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1063
1064 void _nok(const char *file, int l, const char *op, int value, const char *label)
1065 {
1066    nb++;
1067    if (value) {
1068       err++;
1069       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1070    } else {
1071       printf("OK  %.30s\n", label);
1072    }
1073 }
1074
1075 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1076
1077 int report()
1078 {
1079    printf("Result %i/%i OK\n", nb - err, nb);
1080    return err>0;
1081 }
1082
1083 /* 
1084  * TODO:
1085  *  - Must detect multiple lock
1086  *  - lock/unlock in wrong order
1087  *  - deadlock with 2 or 3 threads
1088  */
1089 int main(int argc, char **argv)
1090 {
1091    void *ret=NULL;
1092    lmgr_thread_t *self;
1093    pthread_t id1, id2, id3, tab[200];
1094    bthread_mutex_t bmutex1;
1095    pthread_mutex_t pmutex2;
1096    my_prog = argv[0];
1097
1098    use_undertaker = false;
1099    lmgr_init_thread();
1100    self = lmgr_get_thread_info();
1101
1102    if (argc == 2) {             /* do priority check */
1103       P(mutex_p2);                /* not permited */
1104       P(mutex_p1);
1105       V(mutex_p1);                /* never goes here */
1106       V(mutex_p2);
1107       return 0;
1108    }
1109
1110    pthread_mutex_init(&bmutex1, NULL);
1111    bthread_mutex_set_priority(&bmutex1, 10);
1112
1113    pthread_mutex_init(&pmutex2, NULL);
1114    P(bmutex1);
1115    ok(self->max_priority == 10, "Check self max_priority");
1116    P(pmutex2);
1117    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1118    V(pmutex2);
1119    V(bmutex1);
1120    ok(self->max_priority == 0, "Check self max_priority");
1121
1122    pthread_create(&id1, NULL, self_lock, NULL);
1123    sleep(2);
1124    ok(lmgr_detect_deadlock(), "Check self deadlock");
1125    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1126    pthread_join(id1, NULL);
1127
1128
1129    pthread_create(&id1, NULL, nolock, NULL);
1130    sleep(2);
1131    nok(lmgr_detect_deadlock(), "Check for nolock");
1132    pthread_join(id1, NULL);
1133
1134    P(mutex1);
1135    pthread_create(&id1, NULL, locker, &mutex1);
1136    pthread_create(&id2, NULL, locker, &mutex1);
1137    pthread_create(&id3, NULL, locker, &mutex1);
1138    sleep(2);
1139    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1140    V(mutex1);
1141    pthread_join(id1, NULL);
1142    pthread_join(id2, NULL);   
1143    pthread_join(id3, NULL);
1144
1145
1146    brwlock_t wr;
1147    rwl_init(&wr);
1148    rwl_writelock(&wr);
1149    rwl_writelock(&wr);
1150    pthread_create(&id1, NULL, rwlocker, &wr);
1151    pthread_create(&id2, NULL, rwlocker, &wr);
1152    pthread_create(&id3, NULL, rwlocker, &wr);
1153    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1154    rwl_writeunlock(&wr);
1155    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1156    rwl_writeunlock(&wr);
1157    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1158
1159    pthread_join(id1, NULL);
1160    pthread_join(id2, NULL);   
1161    pthread_join(id3, NULL);   
1162
1163    rwl_writelock(&wr);
1164    P(mutex1);
1165    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1166    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1167    V(mutex1);
1168    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1169    rwl_writeunlock(&wr);
1170    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1171    pthread_join(id1, NULL);
1172
1173    P(mutex5);
1174    P(mutex6);
1175    V(mutex5);
1176    V(mutex6);
1177
1178    nok(lmgr_detect_deadlock(), "Check for wrong order");
1179
1180    for(int j=0; j<200; j++) {
1181       pthread_create(&tab[j], NULL, thx, NULL);
1182    }
1183    for(int j=0; j<200; j++) {
1184       pthread_join(tab[j], NULL);
1185       if (j%3) { lmgr_detect_deadlock();}
1186    }
1187    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1188
1189    P(mutex4);
1190    P(mutex5);
1191    P(mutex6);
1192    V(mutex6);
1193    V(mutex5);
1194    V(mutex4);
1195
1196    pthread_create(&id1, NULL, th1, NULL);
1197    sleep(1);
1198    pthread_create(&id2, NULL, th2, NULL);
1199    sleep(1);
1200    ok(lmgr_detect_deadlock(), "Check for deadlock");
1201
1202    pthread_create(&id3, NULL, th_prio, NULL);
1203    pthread_join(id3, &ret);
1204    ok(ret != 0, "Check for priority segfault");
1205
1206    P(mutex_p1);
1207    ok(self->max_priority == 1, "Check max_priority 1/4");
1208    P(mutex_p2);
1209    ok(self->max_priority == 2, "Check max_priority 2/4");
1210    P(mutex_p3);
1211    ok(self->max_priority == 3, "Check max_priority 3/4");
1212    P(mutex6);
1213    ok(self->max_priority == 3, "Check max_priority 4/4");
1214    V(mutex6);
1215    ok(self->max_priority == 3, "Check max_priority 1/5");
1216    V(mutex_p3);
1217    ok(self->max_priority == 2, "Check max_priority 4/5");
1218    V(mutex_p2);
1219    ok(self->max_priority == 1, "Check max_priority 4/5");
1220    V(mutex_p1);
1221    ok(self->max_priority == 0, "Check max_priority 5/5");
1222
1223
1224    P(mutex_p1);
1225    P(mutex_p2);
1226    P(mutex_p3);
1227    P(mutex6);
1228    ok(self->max_priority == 3, "Check max_priority mixed");
1229    V(mutex_p2);
1230    ok(self->max_priority == 3, "Check max_priority mixed");
1231    V(mutex_p1);
1232    ok(self->max_priority == 3, "Check max_priority mixed");
1233    V(mutex_p3);
1234    ok(self->max_priority == 0, "Check max_priority mixed");
1235    V(mutex6);
1236    ok(self->max_priority == 0, "Check max_priority mixed");
1237
1238    P(mutex_p1);
1239    P(mutex_p2);
1240    V(mutex_p1);
1241    V(mutex_p2);
1242
1243 //   lmgr_dump();
1244 //
1245 //   pthread_create(&id3, NULL, th3, NULL);
1246 //
1247 //   pthread_join(id1, NULL);
1248 //   pthread_join(id2, NULL);
1249    lmgr_cleanup_main();
1250    sm_check(__FILE__, __LINE__, false);
1251    return report();
1252 }
1253
1254 #endif