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