]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Add init/destroy function for both p/bthread_mutex_t object
[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);     // you can also use bthread_mutex_init()
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 %s:%i\n", 
287                  lock_list[i].lock, 
288                  (lock_list[i].state=='W')?"Wanted ":"Granted",
289                  lock_list[i].file, lock_list[i].line);
290       } 
291    }
292
293    void dump(FILE *fp) {
294       lmgr_p(&mutex);
295       {
296          _dump(fp);
297       }
298       lmgr_v(&mutex);
299    }
300
301    /*
302     * Call before a lock operation (mark mutex as WANTED)
303     */
304    virtual void pre_P(void *m, int priority, 
305                       const char *f="*unknown*", int l=0) {
306       ASSERT_p(current < LMGR_MAX_LOCK, f, l);
307       ASSERT_p(current >= -1, f, l);
308       ASSERT_p(!priority || priority >= max_priority, f, l);
309       lmgr_p(&mutex);
310       {
311          current++;
312          lock_list[current].lock = m;
313          lock_list[current].state = LMGR_LOCK_WANTED;
314          lock_list[current].file = f;
315          lock_list[current].line = l;
316          lock_list[current].priority = priority;
317          lock_list[current].max_priority = MAX(priority, max_priority);
318          max = MAX(current, max);
319          max_priority = MAX(priority, max_priority);
320       }
321       lmgr_v(&mutex);
322    }
323
324    /*
325     * Call after the lock operation (mark mutex as GRANTED)
326     */
327    virtual void post_P() {
328       ASSERT(current >= 0);
329       ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
330       lock_list[current].state = LMGR_LOCK_GRANTED;
331    }
332    
333    /* Using this function is some sort of bug */
334    void shift_list(int i) {
335       for(int j=i+1; j<=current; j++) {
336          lock_list[i] = lock_list[j];
337       }
338       if (current >= 0) {
339          lock_list[current].lock = NULL;
340          lock_list[current].state = LMGR_LOCK_EMPTY;
341       }
342       /* rebuild the priority list */
343       max_priority = 0;
344       for(int j=0; j< current; j++) {
345          max_priority = MAX(lock_list[j].priority, max_priority);
346          lock_list[j].max_priority = max_priority;
347       }
348    }
349
350    /*
351     * Remove the mutex from the list
352     */
353    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
354       ASSERT_p(current >= 0, f, l);
355       lmgr_p(&mutex);
356       {
357          if (lock_list[current].lock == m) {
358             lock_list[current].lock = NULL;
359             lock_list[current].state = LMGR_LOCK_EMPTY;
360             current--;
361          } else {
362             ASSERT(current > 0);
363             Pmsg3(0, "ERROR: wrong P/V order search lock=%p %s:%i\n", m, f, l);
364             Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
365                     current, lock_list[current].lock, lock_list[current].file, 
366                     lock_list[current].line);
367             for (int i=current-1; i >= 0; i--) { /* already seen current */
368                Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
369                      i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
370                if (lock_list[i].lock == m) {
371                   Pmsg3(000, "ERROR: FOUND P pos=%i %s:%i\n", i, f, l);
372                   shift_list(i);
373                   current--;
374                   break;
375                }
376             }
377          }
378          /* reset max_priority to the last one */
379          if (current >= 0) {
380             max_priority = lock_list[current].max_priority; 
381          } else {
382             max_priority = 0;
383          }
384       }
385       lmgr_v(&mutex);
386    }
387
388    virtual ~lmgr_thread_t() {destroy();}
389
390    void destroy() {
391       pthread_mutex_destroy(&mutex);
392    }
393 } ;
394
395 class lmgr_dummy_thread_t: public lmgr_thread_t
396 {
397    void do_V(void *m, const char *file, int l)  {}
398    void post_P()                                {}
399    void pre_P(void *m, int priority, const char *file, int l) {}
400 };
401
402 /*
403  * LMGR - Lock Manager
404  *
405  *
406  *
407  */
408
409 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT; 
410 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
411
412 static dlist *global_mgr = NULL;  /* used to store all lgmr_thread_t objects */
413 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
414 static pthread_t undertaker;
415 static bool use_undertaker=true;
416
417 #define lmgr_is_active() (global_mgr != NULL)
418
419 /*
420  * Add a new lmgr_thread_t object to the global list
421  */
422 void lmgr_register_thread(lmgr_thread_t *item)
423 {
424    lmgr_p(&lmgr_global_mutex);
425    {
426       global_mgr->prepend(item);
427    }
428    lmgr_v(&lmgr_global_mutex);
429 }
430
431 /*
432  * Call this function to cleanup specific lock thread data
433  */
434 void lmgr_unregister_thread(lmgr_thread_t *item)
435 {
436    if (!lmgr_is_active()) {
437       return;
438    }
439    lmgr_p(&lmgr_global_mutex);
440    {
441       global_mgr->remove(item);
442    }
443    lmgr_v(&lmgr_global_mutex);
444 }
445
446 /*
447  * Search for a deadlock when it's secure to walk across
448  * locks list. (after lmgr_detect_deadlock or a fatal signal)
449  */
450 bool lmgr_detect_deadlock_unlocked()
451 {
452    bool ret=false;
453    lmgr_node_t *node=NULL;
454    lmgr_lock_t *lock;
455    lmgr_thread_t *item;
456    dlist *g = New(dlist(node, &node->link));
457
458    /* First, get a list of all node */
459    foreach_dlist(item, global_mgr) {
460       for(int i=0; i<=item->current; i++) {
461          node = NULL;
462          lock = &item->lock_list[i];
463          /* Depending if the lock is granted or not, it's a child or a root
464           *  Granted:  Mutex  -> Thread
465           *  Wanted:   Thread -> Mutex
466           *
467           * Note: a Mutex can be locked only once, a thread can request only
468           * one mutex.
469           *
470           */
471          if (lock->state == LMGR_LOCK_GRANTED) {
472             node = New(lmgr_node_t((void*)lock->lock, (void*)item->thread_id));
473          } else if (lock->state == LMGR_LOCK_WANTED) {
474             node = New(lmgr_node_t((void*)item->thread_id, (void*)lock->lock));
475          }
476          if (node) {
477             g->append(node);
478          }
479       }
480    }      
481    
482    //foreach_dlist(node, g) {
483    //   printf("g n=%p c=%p\n", node->node, node->child);
484    //}
485
486    ret = contains_cycle(g);
487    if (ret) {
488       printf("Found a deadlock !!!!\n");
489    }
490    
491    delete g;
492    return ret;
493 }
494
495 /*
496  * Search for a deadlock in during the runtime
497  * It will lock all thread specific lock manager, nothing
498  * can be locked during this check.
499  */
500 bool lmgr_detect_deadlock()
501 {
502    bool ret=false;
503    if (!lmgr_is_active()) {
504       return ret;
505    } 
506
507    lmgr_p(&lmgr_global_mutex);
508    {
509       lmgr_thread_t *item;
510       foreach_dlist(item, global_mgr) {
511          lmgr_p(&item->mutex);
512       }
513
514       ret = lmgr_detect_deadlock_unlocked();
515
516       foreach_dlist(item, global_mgr) {
517          lmgr_v(&item->mutex);
518       }
519    }
520    lmgr_v(&lmgr_global_mutex);
521
522    return ret;
523 }
524
525 /*
526  * !!! WARNING !!! 
527  * Use this function is used only after a fatal signal
528  * We don't use locking to display the information
529  */
530 void dbg_print_lock(FILE *fp)
531 {
532    fprintf(fp, "Attempt to dump locks\n");
533    if (!lmgr_is_active()) {
534       return ;
535    }
536    lmgr_thread_t *item;
537    foreach_dlist(item, global_mgr) {
538       item->_dump(fp);
539    }
540 }
541
542 /*
543  * Dump each lmgr_thread_t object
544  */
545 void lmgr_dump()
546 {
547    lmgr_p(&lmgr_global_mutex);
548    {
549       lmgr_thread_t *item;
550       foreach_dlist(item, global_mgr) {
551          item->dump(stderr);
552       }
553    }
554    lmgr_v(&lmgr_global_mutex);
555 }
556
557 void cln_hdl(void *a)
558 {
559    lmgr_cleanup_thread();
560 }
561
562 void *check_deadlock(void *)
563 {
564    int old;
565    lmgr_init_thread();
566    pthread_cleanup_push(cln_hdl, NULL);
567
568    while (!bmicrosleep(30, 0)) {
569       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
570       if (lmgr_detect_deadlock()) {
571          lmgr_dump();
572          ASSERT(0);
573       }
574       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
575       pthread_testcancel();
576    }
577    Pmsg0(000, "Undertaker is leaving...\n");
578    pthread_cleanup_pop(1);
579    return NULL;
580 }
581
582 /* This object is used when LMGR is not initialized */
583 static lmgr_dummy_thread_t dummy_lmgr;
584
585 /*
586  * Retrieve the lmgr_thread_t object from the stack
587  */
588 inline lmgr_thread_t *lmgr_get_thread_info()
589 {
590    if (lmgr_is_active()) {
591       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
592    } else {
593       return &dummy_lmgr;
594    }
595 }
596
597 /*
598  * launch once for all threads
599  */
600 void create_lmgr_key()
601 {
602    int status = pthread_key_create(&lmgr_key, NULL);
603    if (status != 0) {
604       berrno be;
605       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
606             be.bstrerror(status));
607       ASSERT(0);
608    }
609
610    lmgr_thread_t *n=NULL;
611    global_mgr = New(dlist(n, &n->link));
612
613    if (use_undertaker) {
614       status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
615       if (status != 0) {
616          berrno be;
617          Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
618                be.bstrerror(status));
619          ASSERT(0);
620       }
621    }
622 }
623
624 /*
625  * Each thread have to call this function to put a lmgr_thread_t object
626  * in the stack and be able to call mutex_lock/unlock
627  */
628 void lmgr_init_thread()
629 {
630    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
631    if (status != 0) {
632       berrno be;
633       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
634             be.bstrerror(status));
635       ASSERT(0);
636    }
637    lmgr_thread_t *l = New(lmgr_thread_t());
638    pthread_setspecific(lmgr_key, l);
639    lmgr_register_thread(l);
640 }
641
642 /*
643  * Call this function at the end of the thread
644  */
645 void lmgr_cleanup_thread()
646 {
647    if (!lmgr_is_active()) {
648       return ;
649    }
650    lmgr_thread_t *self = lmgr_get_thread_info();
651    lmgr_unregister_thread(self);
652    delete(self);
653 }
654
655 /*
656  * This function should be call at the end of the main thread
657  * Some thread like the watchdog are already present, so the global_mgr
658  * list is never empty. Should carefully clear the memory.
659  */
660 void lmgr_cleanup_main()
661 {
662    dlist *temp;
663    
664    if (!global_mgr) {
665       return;
666    }
667    if (use_undertaker) {
668       pthread_cancel(undertaker);
669    }
670    lmgr_cleanup_thread();
671    lmgr_p(&lmgr_global_mutex);
672    {
673       temp = global_mgr;
674       global_mgr = NULL;
675       delete temp;
676    }
677    lmgr_v(&lmgr_global_mutex);
678 }
679
680 /* 
681  * Set the priority of the lmgr mutex object
682  */
683 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
684 {
685    m->priority = prio;
686 }
687
688 /*
689  * Replacement for pthread_mutex_init()
690  */
691 int bthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
692 {
693    m->priority = 0;
694    return pthread_mutex_init(&m->mutex, attr);
695 }
696
697 /*
698  * Replacement for pthread_mutex_destroy()
699  */
700 int bthread_mutex_destroy(bthread_mutex_t *m)
701 {
702    return pthread_mutex_destroy(&m->mutex);
703 }
704
705 /*
706  * Replacement for pthread_mutex_init() for pthread_mutex_t
707  */
708 int bthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *attr)
709 {
710    return pthread_mutex_init(m, attr);
711 }
712
713 /*
714  * Replacement for pthread_mutex_destroy() for pthread_mutex_t
715  */
716 int bthread_mutex_destroy(pthread_mutex_t *m)
717 {
718    return pthread_mutex_destroy(m);
719 }
720
721
722 /*
723  * Replacement for pthread_mutex_lock()
724  * Returns always ok 
725  */
726 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
727 {
728    lmgr_thread_t *self = lmgr_get_thread_info();
729    self->pre_P(m, m->priority, file, line);
730    lmgr_p(&m->mutex);
731    self->post_P();   
732    return 0;
733 }
734
735 /*
736  * Replacement for pthread_mutex_unlock()
737  * Returns always ok
738  */
739 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
740 {
741    lmgr_thread_t *self = lmgr_get_thread_info();
742    self->do_V(m, file, line);
743    lmgr_v(&m->mutex);
744    return 0;
745 }
746
747 /*
748  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
749  * Returns always ok 
750  */
751 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
752 {
753    lmgr_thread_t *self = lmgr_get_thread_info();
754    self->pre_P(m, 0, file, line);
755    lmgr_p(m);
756    self->post_P();   
757    return 0;
758 }
759
760 /*
761  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
762  * Returns always ok
763  */
764 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
765 {
766    lmgr_thread_t *self = lmgr_get_thread_info();
767    self->do_V(m, file, line);
768    lmgr_v(m);
769    return 0;
770 }
771
772
773 /* TODO: check this
774  */
775 int bthread_cond_wait_p(pthread_cond_t *cond,
776                         pthread_mutex_t *m,
777                         const char *file, int line)
778 {
779    int ret;
780    lmgr_thread_t *self = lmgr_get_thread_info();
781    self->do_V(m, file, line);   
782    ret = pthread_cond_wait(cond, m);
783    self->pre_P(m, 0, file, line);
784    self->post_P();
785    return ret;
786 }
787
788 /* TODO: check this
789  */
790 int bthread_cond_timedwait_p(pthread_cond_t *cond,
791                              pthread_mutex_t *m,
792                              const struct timespec * abstime,
793                              const char *file, int line)
794 {
795    int ret;
796    lmgr_thread_t *self = lmgr_get_thread_info();
797    self->do_V(m, file, line);   
798    ret = pthread_cond_timedwait(cond, m, abstime);
799    self->pre_P(m, 0, file, line);
800    self->post_P();
801    return ret;
802 }
803
804 /* TODO: check this
805  */
806 int bthread_cond_wait_p(pthread_cond_t *cond,
807                         bthread_mutex_t *m,
808                         const char *file, int line)
809 {
810    int ret;
811    lmgr_thread_t *self = lmgr_get_thread_info();
812    self->do_V(m, file, line);   
813    ret = pthread_cond_wait(cond, &m->mutex);
814    self->pre_P(m, m->priority, file, line);
815    self->post_P();
816    return ret;
817 }
818
819 /* TODO: check this
820  */
821 int bthread_cond_timedwait_p(pthread_cond_t *cond,
822                              bthread_mutex_t *m,
823                              const struct timespec * abstime,
824                              const char *file, int line)
825 {
826    int ret;
827    lmgr_thread_t *self = lmgr_get_thread_info();
828    self->do_V(m, file, line);   
829    ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
830    self->pre_P(m, m->priority, file, line);
831    self->post_P();
832    return ret;
833 }
834
835 /*
836  * Use this function when the caller handle the mutex directly
837  *
838  * lmgr_pre_lock(m, 10);
839  * pthread_mutex_lock(m);
840  * lmgr_post_lock(m);
841  */
842 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
843 {
844    lmgr_thread_t *self = lmgr_get_thread_info();
845    self->pre_P(m, prio, file, line);
846 }
847
848 /*
849  * Use this function when the caller handle the mutex directly
850  */
851 void lmgr_post_lock()
852 {
853    lmgr_thread_t *self = lmgr_get_thread_info();
854    self->post_P();
855 }
856
857 /*
858  * Do directly pre_P and post_P (used by trylock)
859  */
860 void lmgr_do_lock(void *m, int prio, const char *file, int line)
861 {
862    lmgr_thread_t *self = lmgr_get_thread_info();
863    self->pre_P(m, prio, file, line);
864    self->post_P();
865 }
866
867 /*
868  * Use this function when the caller handle the mutex directly
869  */
870 void lmgr_do_unlock(void *m)
871 {
872    lmgr_thread_t *self = lmgr_get_thread_info();
873    self->do_V(m);
874 }
875
876 typedef struct {
877    void *(*start_routine)(void*);
878    void *arg;
879 } lmgr_thread_arg_t;
880
881 extern "C" 
882 void *lmgr_thread_launcher(void *x)
883 {
884    void *ret=NULL;
885    lmgr_init_thread();
886    pthread_cleanup_push(cln_hdl, NULL);
887
888    lmgr_thread_arg_t arg;
889    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
890    arg.start_routine = a->start_routine;
891    arg.arg = a->arg;
892    free(a);
893
894    ret = arg.start_routine(arg.arg);
895    pthread_cleanup_pop(1);
896    return ret;
897 }
898
899 int lmgr_thread_create(pthread_t *thread,
900                        const pthread_attr_t *attr,
901                        void *(*start_routine)(void*), void *arg)
902 {
903    /* lmgr should be active (lmgr_init_thread() call in main()) */
904    ASSERT(lmgr_is_active());
905    /* Will be freed by the child */
906    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
907    a->start_routine = start_routine;
908    a->arg = arg;
909    return pthread_create(thread, attr, lmgr_thread_launcher, a);
910 }
911
912 #else  /* _USE_LOCKMGR */
913
914 /*
915  * !!! WARNING !!! 
916  * Use this function is used only after a fatal signal
917  * We don't use locking to display information
918  */
919 void dbg_print_lock(FILE *fp)
920 {
921    Pmsg0(000, "lockmgr disabled\n");
922 }
923
924 #endif  /* _USE_LOCKMGR */
925
926 #ifdef _TEST_IT
927
928 #include "lockmgr.h"
929 #define BTHREAD_MUTEX_NO_PRIORITY      {PTHREAD_MUTEX_INITIALIZER, 0}
930 #define BTHREAD_MUTEX_PRIORITY_1       {PTHREAD_MUTEX_INITIALIZER, 1}
931 #define BTHREAD_MUTEX_PRIORITY_2       {PTHREAD_MUTEX_INITIALIZER, 2}
932 #define BTHREAD_MUTEX_PRIORITY_3       {PTHREAD_MUTEX_INITIALIZER, 3}
933 #define BTHREAD_MUTEX_PRIORITY_4       {PTHREAD_MUTEX_INITIALIZER, 4}
934 #undef P
935 #undef V
936 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
937 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
938 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
939
940 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
941 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
942 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
943 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
944 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
945 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
946 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY_1;
947 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY_2;
948 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY_3;
949 static const char *my_prog;
950
951 void *self_lock(void *temp)
952 {
953    P(mutex1);
954    P(mutex1);
955    V(mutex1);
956    
957    return NULL;
958 }
959
960 void *nolock(void *temp)
961 {
962    P(mutex2);
963    sleep(5);
964    V(mutex2);
965    return NULL;
966 }
967
968 void *locker(void *temp)
969 {
970    bthread_mutex_t *m = (bthread_mutex_t*) temp;
971    P(*m);
972    V(*m);
973    return NULL;
974 }
975
976 void *rwlocker(void *temp)
977 {
978    brwlock_t *m = (brwlock_t*) temp;
979    rwl_writelock(m);
980    rwl_writelock(m);
981
982    rwl_writeunlock(m);
983    rwl_writeunlock(m);
984    return NULL;
985 }
986
987 void *mix_rwl_mutex(void *temp)
988 {
989    brwlock_t *m = (brwlock_t*) temp;
990    P(mutex1);
991    rwl_writelock(m);
992    rwl_writeunlock(m);
993    V(mutex1);
994    return NULL;
995 }
996
997
998 void *th2(void *temp)
999 {
1000    P(mutex2);
1001    P(mutex1);
1002    
1003    lmgr_dump();
1004
1005    sleep(10);
1006
1007    V(mutex1);
1008    V(mutex2);
1009
1010    lmgr_dump();
1011    return NULL;
1012 }
1013 void *th1(void *temp)
1014 {
1015    P(mutex1);
1016    sleep(2);
1017    P(mutex2);
1018    
1019    lmgr_dump();
1020
1021    sleep(10);
1022
1023    V(mutex2);
1024    V(mutex1);
1025
1026    lmgr_dump();
1027    return NULL;
1028 }
1029
1030 void *thx(void *temp)
1031 {
1032    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1033    P(mutex1);
1034    bmicrosleep(0,s);
1035    P(mutex2);
1036    bmicrosleep(0,s);
1037
1038    V(mutex2);
1039    V(mutex1);
1040    return NULL;
1041 }
1042
1043 void *th3(void *a) {
1044    while (1) {
1045       fprintf(stderr, "undertaker sleep()\n");
1046       sleep(10);
1047       lmgr_dump();
1048       if (lmgr_detect_deadlock()) {
1049          lmgr_dump();
1050          exit(1);
1051       }
1052    }
1053    return NULL;
1054 }
1055
1056 void *th_prio(void *a) {
1057    char buf[512];
1058    bstrncpy(buf, my_prog, sizeof(buf));
1059    bstrncat(buf, " priority", sizeof(buf));
1060    int ret = system(buf);
1061    return (void*) ret;
1062 }
1063
1064 int err=0;
1065 int nb=0;
1066 void _ok(const char *file, int l, const char *op, int value, const char *label)
1067 {
1068    nb++;
1069    if (!value) {
1070       err++;
1071       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1072    } else {
1073       printf("OK  %.30s\n", label);
1074    }
1075 }
1076
1077 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1078
1079 void _nok(const char *file, int l, const char *op, int value, const char *label)
1080 {
1081    nb++;
1082    if (value) {
1083       err++;
1084       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1085    } else {
1086       printf("OK  %.30s\n", label);
1087    }
1088 }
1089
1090 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1091
1092 int report()
1093 {
1094    printf("Result %i/%i OK\n", nb - err, nb);
1095    return err>0;
1096 }
1097
1098 /* 
1099  * TODO:
1100  *  - Must detect multiple lock
1101  *  - lock/unlock in wrong order
1102  *  - deadlock with 2 or 3 threads
1103  */
1104 int main(int argc, char **argv)
1105 {
1106    void *ret=NULL;
1107    lmgr_thread_t *self;
1108    pthread_t id1, id2, id3, tab[200];
1109    my_prog = argv[0];
1110
1111    use_undertaker = false;
1112    lmgr_init_thread();
1113
1114    if (argc == 2) {             /* do priority check */
1115       P(mutex_p2);                /* not permited */
1116       P(mutex_p1);
1117       V(mutex_p1);                /* never goes here */
1118       V(mutex_p2);
1119       return 0;
1120    }
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    self = lmgr_get_thread_info();
1207    P(mutex_p1);
1208    ok(self->max_priority == 1, "Check max_priority 1/4");
1209    P(mutex_p2);
1210    ok(self->max_priority == 2, "Check max_priority 2/4");
1211    P(mutex_p3);
1212    ok(self->max_priority == 3, "Check max_priority 3/4");
1213    P(mutex6);
1214    ok(self->max_priority == 3, "Check max_priority 4/4");
1215    V(mutex6);
1216    ok(self->max_priority == 3, "Check max_priority 1/5");
1217    V(mutex_p3);
1218    ok(self->max_priority == 2, "Check max_priority 4/5");
1219    V(mutex_p2);
1220    ok(self->max_priority == 1, "Check max_priority 4/5");
1221    V(mutex_p1);
1222    ok(self->max_priority == 0, "Check max_priority 5/5");
1223
1224
1225    P(mutex_p1);
1226    P(mutex_p2);
1227    P(mutex_p3);
1228    P(mutex6);
1229    ok(self->max_priority == 3, "Check max_priority mixed");
1230    V(mutex_p2);
1231    ok(self->max_priority == 3, "Check max_priority mixed");
1232    V(mutex_p1);
1233    ok(self->max_priority == 3, "Check max_priority mixed");
1234    V(mutex_p3);
1235    ok(self->max_priority == 0, "Check max_priority mixed");
1236    V(mutex6);
1237    ok(self->max_priority == 0, "Check max_priority mixed");
1238
1239    P(mutex_p1);
1240    P(mutex_p2);
1241    V(mutex_p1);
1242    V(mutex_p2);
1243
1244 //   lmgr_dump();
1245 //
1246 //   pthread_create(&id3, NULL, th3, NULL);
1247 //
1248 //   pthread_join(id1, NULL);
1249 //   pthread_join(id2, NULL);
1250    lmgr_cleanup_main();
1251    sm_check(__FILE__, __LINE__, false);
1252    return report();
1253 }
1254
1255 #endif