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