]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Tweak mutex order for SD
[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, _("Failed ASSERT: %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, _("from %s:%i Failed ASSERT: %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    m->priority = prio;
689 }
690
691 /*
692  * Replacement for pthread_mutex_init()
693  */
694 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
695 {
696    m->priority = 0;
697    return pthread_mutex_init(&m->mutex, attr);
698 }
699
700 /*
701  * Replacement for pthread_mutex_destroy()
702  */
703 int pthread_mutex_destroy(bthread_mutex_t *m)
704 {
705    return pthread_mutex_destroy(&m->mutex);
706 }
707
708 /*
709  * Replacement for pthread_mutex_lock()
710  * Returns always ok 
711  */
712 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
713 {
714    lmgr_thread_t *self = lmgr_get_thread_info();
715    self->pre_P(m, m->priority, file, line);
716    lmgr_p(&m->mutex);
717    self->post_P();   
718    return 0;
719 }
720
721 /*
722  * Replacement for pthread_mutex_unlock()
723  * Returns always ok
724  */
725 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
726 {
727    lmgr_thread_t *self = lmgr_get_thread_info();
728    self->do_V(m, file, line);
729    lmgr_v(&m->mutex);
730    return 0;
731 }
732
733 /*
734  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
735  * Returns always ok 
736  */
737 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
738 {
739    lmgr_thread_t *self = lmgr_get_thread_info();
740    self->pre_P(m, 0, file, line);
741    lmgr_p(m);
742    self->post_P();   
743    return 0;
744 }
745
746 /*
747  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
748  * Returns always ok
749  */
750 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
751 {
752    lmgr_thread_t *self = lmgr_get_thread_info();
753    self->do_V(m, file, line);
754    lmgr_v(m);
755    return 0;
756 }
757
758
759 /* TODO: check this
760  */
761 int bthread_cond_wait_p(pthread_cond_t *cond,
762                         pthread_mutex_t *m,
763                         const char *file, int line)
764 {
765    int ret;
766    lmgr_thread_t *self = lmgr_get_thread_info();
767    self->do_V(m, file, line);   
768    ret = pthread_cond_wait(cond, m);
769    self->pre_P(m, 0, file, line);
770    self->post_P();
771    return ret;
772 }
773
774 /* TODO: check this
775  */
776 int bthread_cond_timedwait_p(pthread_cond_t *cond,
777                              pthread_mutex_t *m,
778                              const struct timespec * abstime,
779                              const char *file, int line)
780 {
781    int ret;
782    lmgr_thread_t *self = lmgr_get_thread_info();
783    self->do_V(m, file, line);   
784    ret = pthread_cond_timedwait(cond, m, abstime);
785    self->pre_P(m, 0, file, line);
786    self->post_P();
787    return ret;
788 }
789
790 /* TODO: check this
791  */
792 int bthread_cond_wait_p(pthread_cond_t *cond,
793                         bthread_mutex_t *m,
794                         const char *file, int line)
795 {
796    int ret;
797    lmgr_thread_t *self = lmgr_get_thread_info();
798    self->do_V(m, file, line);   
799    ret = pthread_cond_wait(cond, &m->mutex);
800    self->pre_P(m, m->priority, file, line);
801    self->post_P();
802    return ret;
803 }
804
805 /* TODO: check this
806  */
807 int bthread_cond_timedwait_p(pthread_cond_t *cond,
808                              bthread_mutex_t *m,
809                              const struct timespec * abstime,
810                              const char *file, int line)
811 {
812    int ret;
813    lmgr_thread_t *self = lmgr_get_thread_info();
814    self->do_V(m, file, line);   
815    ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
816    self->pre_P(m, m->priority, file, line);
817    self->post_P();
818    return ret;
819 }
820
821 /*
822  * Use this function when the caller handle the mutex directly
823  *
824  * lmgr_pre_lock(m, 10);
825  * pthread_mutex_lock(m);
826  * lmgr_post_lock(m);
827  */
828 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
829 {
830    lmgr_thread_t *self = lmgr_get_thread_info();
831    self->pre_P(m, prio, file, line);
832 }
833
834 /*
835  * Use this function when the caller handle the mutex directly
836  */
837 void lmgr_post_lock()
838 {
839    lmgr_thread_t *self = lmgr_get_thread_info();
840    self->post_P();
841 }
842
843 /*
844  * Do directly pre_P and post_P (used by trylock)
845  */
846 void lmgr_do_lock(void *m, int prio, const char *file, int line)
847 {
848    lmgr_thread_t *self = lmgr_get_thread_info();
849    self->pre_P(m, prio, file, line);
850    self->post_P();
851 }
852
853 /*
854  * Use this function when the caller handle the mutex directly
855  */
856 void lmgr_do_unlock(void *m)
857 {
858    lmgr_thread_t *self = lmgr_get_thread_info();
859    self->do_V(m);
860 }
861
862 typedef struct {
863    void *(*start_routine)(void*);
864    void *arg;
865 } lmgr_thread_arg_t;
866
867 extern "C" 
868 void *lmgr_thread_launcher(void *x)
869 {
870    void *ret=NULL;
871    lmgr_init_thread();
872    pthread_cleanup_push(cln_hdl, NULL);
873
874    lmgr_thread_arg_t arg;
875    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
876    arg.start_routine = a->start_routine;
877    arg.arg = a->arg;
878    free(a);
879
880    ret = arg.start_routine(arg.arg);
881    pthread_cleanup_pop(1);
882    return ret;
883 }
884
885 int lmgr_thread_create(pthread_t *thread,
886                        const pthread_attr_t *attr,
887                        void *(*start_routine)(void*), void *arg)
888 {
889    /* lmgr should be active (lmgr_init_thread() call in main()) */
890    ASSERT(lmgr_is_active());
891    /* Will be freed by the child */
892    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
893    a->start_routine = start_routine;
894    a->arg = arg;
895    return pthread_create(thread, attr, lmgr_thread_launcher, a);
896 }
897
898 #else  /* _USE_LOCKMGR */
899
900 /*
901  * !!! WARNING !!! 
902  * Use this function is used only after a fatal signal
903  * We don't use locking to display information
904  */
905 void dbg_print_lock(FILE *fp)
906 {
907    Pmsg0(000, "lockmgr disabled\n");
908 }
909
910 #endif  /* _USE_LOCKMGR */
911
912 #ifdef _TEST_IT
913
914 #include "lockmgr.h"
915 #define BTHREAD_MUTEX_NO_PRIORITY      {PTHREAD_MUTEX_INITIALIZER, 0}
916 #define BTHREAD_MUTEX_PRIORITY(p)      {PTHREAD_MUTEX_INITIALIZER, p}
917 #undef P
918 #undef V
919 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
920 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
921 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
922
923 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
924 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
925 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
926 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
927 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
928 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
929 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
930 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
931 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
932 static const char *my_prog;
933
934 void *self_lock(void *temp)
935 {
936    P(mutex1);
937    P(mutex1);
938    V(mutex1);
939    
940    return NULL;
941 }
942
943 void *nolock(void *temp)
944 {
945    P(mutex2);
946    sleep(5);
947    V(mutex2);
948    return NULL;
949 }
950
951 void *locker(void *temp)
952 {
953    bthread_mutex_t *m = (bthread_mutex_t*) temp;
954    P(*m);
955    V(*m);
956    return NULL;
957 }
958
959 void *rwlocker(void *temp)
960 {
961    brwlock_t *m = (brwlock_t*) temp;
962    rwl_writelock(m);
963    rwl_writelock(m);
964
965    rwl_writeunlock(m);
966    rwl_writeunlock(m);
967    return NULL;
968 }
969
970 void *mix_rwl_mutex(void *temp)
971 {
972    brwlock_t *m = (brwlock_t*) temp;
973    P(mutex1);
974    rwl_writelock(m);
975    rwl_writeunlock(m);
976    V(mutex1);
977    return NULL;
978 }
979
980
981 void *th2(void *temp)
982 {
983    P(mutex2);
984    P(mutex1);
985    
986    lmgr_dump();
987
988    sleep(10);
989
990    V(mutex1);
991    V(mutex2);
992
993    lmgr_dump();
994    return NULL;
995 }
996 void *th1(void *temp)
997 {
998    P(mutex1);
999    sleep(2);
1000    P(mutex2);
1001    
1002    lmgr_dump();
1003
1004    sleep(10);
1005
1006    V(mutex2);
1007    V(mutex1);
1008
1009    lmgr_dump();
1010    return NULL;
1011 }
1012
1013 void *thx(void *temp)
1014 {
1015    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1016    P(mutex1);
1017    bmicrosleep(0,s);
1018    P(mutex2);
1019    bmicrosleep(0,s);
1020
1021    V(mutex2);
1022    V(mutex1);
1023    return NULL;
1024 }
1025
1026 void *th3(void *a) {
1027    while (1) {
1028       fprintf(stderr, "undertaker sleep()\n");
1029       sleep(10);
1030       lmgr_dump();
1031       if (lmgr_detect_deadlock()) {
1032          lmgr_dump();
1033          exit(1);
1034       }
1035    }
1036    return NULL;
1037 }
1038
1039 void *th_prio(void *a) {
1040    char buf[512];
1041    bstrncpy(buf, my_prog, sizeof(buf));
1042    bstrncat(buf, " priority", sizeof(buf));
1043    int ret = system(buf);
1044    return (void*) ret;
1045 }
1046
1047 int err=0;
1048 int nb=0;
1049 void _ok(const char *file, int l, const char *op, int value, const char *label)
1050 {
1051    nb++;
1052    if (!value) {
1053       err++;
1054       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1055    } else {
1056       printf("OK  %.30s\n", label);
1057    }
1058 }
1059
1060 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1061
1062 void _nok(const char *file, int l, const char *op, int value, const char *label)
1063 {
1064    nb++;
1065    if (value) {
1066       err++;
1067       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1068    } else {
1069       printf("OK  %.30s\n", label);
1070    }
1071 }
1072
1073 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1074
1075 int report()
1076 {
1077    printf("Result %i/%i OK\n", nb - err, nb);
1078    return err>0;
1079 }
1080
1081 /* 
1082  * TODO:
1083  *  - Must detect multiple lock
1084  *  - lock/unlock in wrong order
1085  *  - deadlock with 2 or 3 threads
1086  */
1087 int main(int argc, char **argv)
1088 {
1089    void *ret=NULL;
1090    lmgr_thread_t *self;
1091    pthread_t id1, id2, id3, tab[200];
1092    bthread_mutex_t bmutex1;
1093    pthread_mutex_t pmutex2;
1094    my_prog = argv[0];
1095
1096    use_undertaker = false;
1097    lmgr_init_thread();
1098    self = lmgr_get_thread_info();
1099
1100    if (argc == 2) {             /* do priority check */
1101       P(mutex_p2);                /* not permited */
1102       P(mutex_p1);
1103       V(mutex_p1);                /* never goes here */
1104       V(mutex_p2);
1105       return 0;
1106    }
1107
1108    pthread_mutex_init(&bmutex1, NULL);
1109    bthread_mutex_set_priority(&bmutex1, 10);
1110
1111    pthread_mutex_init(&pmutex2, NULL);
1112    P(bmutex1);
1113    ok(self->max_priority == 10, "Check self max_priority");
1114    P(pmutex2);
1115    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1116    V(pmutex2);
1117    V(bmutex1);
1118    ok(self->max_priority == 0, "Check self max_priority");
1119
1120    pthread_create(&id1, NULL, self_lock, NULL);
1121    sleep(2);
1122    ok(lmgr_detect_deadlock(), "Check self deadlock");
1123    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1124    pthread_join(id1, NULL);
1125
1126
1127    pthread_create(&id1, NULL, nolock, NULL);
1128    sleep(2);
1129    nok(lmgr_detect_deadlock(), "Check for nolock");
1130    pthread_join(id1, NULL);
1131
1132    P(mutex1);
1133    pthread_create(&id1, NULL, locker, &mutex1);
1134    pthread_create(&id2, NULL, locker, &mutex1);
1135    pthread_create(&id3, NULL, locker, &mutex1);
1136    sleep(2);
1137    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1138    V(mutex1);
1139    pthread_join(id1, NULL);
1140    pthread_join(id2, NULL);   
1141    pthread_join(id3, NULL);
1142
1143
1144    brwlock_t wr;
1145    rwl_init(&wr);
1146    rwl_writelock(&wr);
1147    rwl_writelock(&wr);
1148    pthread_create(&id1, NULL, rwlocker, &wr);
1149    pthread_create(&id2, NULL, rwlocker, &wr);
1150    pthread_create(&id3, NULL, rwlocker, &wr);
1151    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1152    rwl_writeunlock(&wr);
1153    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1154    rwl_writeunlock(&wr);
1155    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1156
1157    pthread_join(id1, NULL);
1158    pthread_join(id2, NULL);   
1159    pthread_join(id3, NULL);   
1160
1161    rwl_writelock(&wr);
1162    P(mutex1);
1163    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1164    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1165    V(mutex1);
1166    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1167    rwl_writeunlock(&wr);
1168    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1169    pthread_join(id1, NULL);
1170
1171    P(mutex5);
1172    P(mutex6);
1173    V(mutex5);
1174    V(mutex6);
1175
1176    nok(lmgr_detect_deadlock(), "Check for wrong order");
1177
1178    for(int j=0; j<200; j++) {
1179       pthread_create(&tab[j], NULL, thx, NULL);
1180    }
1181    for(int j=0; j<200; j++) {
1182       pthread_join(tab[j], NULL);
1183       if (j%3) { lmgr_detect_deadlock();}
1184    }
1185    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1186
1187    P(mutex4);
1188    P(mutex5);
1189    P(mutex6);
1190    V(mutex6);
1191    V(mutex5);
1192    V(mutex4);
1193
1194    pthread_create(&id1, NULL, th1, NULL);
1195    sleep(1);
1196    pthread_create(&id2, NULL, th2, NULL);
1197    sleep(1);
1198    ok(lmgr_detect_deadlock(), "Check for deadlock");
1199
1200    pthread_create(&id3, NULL, th_prio, NULL);
1201    pthread_join(id3, &ret);
1202    ok(ret != 0, "Check for priority segfault");
1203
1204    P(mutex_p1);
1205    ok(self->max_priority == 1, "Check max_priority 1/4");
1206    P(mutex_p2);
1207    ok(self->max_priority == 2, "Check max_priority 2/4");
1208    P(mutex_p3);
1209    ok(self->max_priority == 3, "Check max_priority 3/4");
1210    P(mutex6);
1211    ok(self->max_priority == 3, "Check max_priority 4/4");
1212    V(mutex6);
1213    ok(self->max_priority == 3, "Check max_priority 1/5");
1214    V(mutex_p3);
1215    ok(self->max_priority == 2, "Check max_priority 4/5");
1216    V(mutex_p2);
1217    ok(self->max_priority == 1, "Check max_priority 4/5");
1218    V(mutex_p1);
1219    ok(self->max_priority == 0, "Check max_priority 5/5");
1220
1221
1222    P(mutex_p1);
1223    P(mutex_p2);
1224    P(mutex_p3);
1225    P(mutex6);
1226    ok(self->max_priority == 3, "Check max_priority mixed");
1227    V(mutex_p2);
1228    ok(self->max_priority == 3, "Check max_priority mixed");
1229    V(mutex_p1);
1230    ok(self->max_priority == 3, "Check max_priority mixed");
1231    V(mutex_p3);
1232    ok(self->max_priority == 0, "Check max_priority mixed");
1233    V(mutex6);
1234    ok(self->max_priority == 0, "Check max_priority mixed");
1235
1236    P(mutex_p1);
1237    P(mutex_p2);
1238    V(mutex_p1);
1239    V(mutex_p2);
1240
1241 //   lmgr_dump();
1242 //
1243 //   pthread_create(&id3, NULL, th3, NULL);
1244 //
1245 //   pthread_join(id1, NULL);
1246 //   pthread_join(id2, NULL);
1247    lmgr_cleanup_main();
1248    sm_check(__FILE__, __LINE__, false);
1249    return report();
1250 }
1251
1252 #endif