]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Make pthread_mutex_init/destroy compatible with bthread_mutex_t
[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_1       {PTHREAD_MUTEX_INITIALIZER, 1}
914 #define BTHREAD_MUTEX_PRIORITY_2       {PTHREAD_MUTEX_INITIALIZER, 2}
915 #define BTHREAD_MUTEX_PRIORITY_3       {PTHREAD_MUTEX_INITIALIZER, 3}
916 #define BTHREAD_MUTEX_PRIORITY_4       {PTHREAD_MUTEX_INITIALIZER, 4}
917 #undef P
918 #undef V
919 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
920 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
921 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
922
923 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
924 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
925 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
926 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
927 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
928 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
929 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY_1;
930 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY_2;
931 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY_3;
932 static const char *my_prog;
933
934 void *self_lock(void *temp)
935 {
936    P(mutex1);
937    P(mutex1);
938    V(mutex1);
939    
940    return NULL;
941 }
942
943 void *nolock(void *temp)
944 {
945    P(mutex2);
946    sleep(5);
947    V(mutex2);
948    return NULL;
949 }
950
951 void *locker(void *temp)
952 {
953    bthread_mutex_t *m = (bthread_mutex_t*) temp;
954    P(*m);
955    V(*m);
956    return NULL;
957 }
958
959 void *rwlocker(void *temp)
960 {
961    brwlock_t *m = (brwlock_t*) temp;
962    rwl_writelock(m);
963    rwl_writelock(m);
964
965    rwl_writeunlock(m);
966    rwl_writeunlock(m);
967    return NULL;
968 }
969
970 void *mix_rwl_mutex(void *temp)
971 {
972    brwlock_t *m = (brwlock_t*) temp;
973    P(mutex1);
974    rwl_writelock(m);
975    rwl_writeunlock(m);
976    V(mutex1);
977    return NULL;
978 }
979
980
981 void *th2(void *temp)
982 {
983    P(mutex2);
984    P(mutex1);
985    
986    lmgr_dump();
987
988    sleep(10);
989
990    V(mutex1);
991    V(mutex2);
992
993    lmgr_dump();
994    return NULL;
995 }
996 void *th1(void *temp)
997 {
998    P(mutex1);
999    sleep(2);
1000    P(mutex2);
1001    
1002    lmgr_dump();
1003
1004    sleep(10);
1005
1006    V(mutex2);
1007    V(mutex1);
1008
1009    lmgr_dump();
1010    return NULL;
1011 }
1012
1013 void *thx(void *temp)
1014 {
1015    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1016    P(mutex1);
1017    bmicrosleep(0,s);
1018    P(mutex2);
1019    bmicrosleep(0,s);
1020
1021    V(mutex2);
1022    V(mutex1);
1023    return NULL;
1024 }
1025
1026 void *th3(void *a) {
1027    while (1) {
1028       fprintf(stderr, "undertaker sleep()\n");
1029       sleep(10);
1030       lmgr_dump();
1031       if (lmgr_detect_deadlock()) {
1032          lmgr_dump();
1033          exit(1);
1034       }
1035    }
1036    return NULL;
1037 }
1038
1039 void *th_prio(void *a) {
1040    char buf[512];
1041    bstrncpy(buf, my_prog, sizeof(buf));
1042    bstrncat(buf, " priority", sizeof(buf));
1043    int ret = system(buf);
1044    return (void*) ret;
1045 }
1046
1047 int err=0;
1048 int nb=0;
1049 void _ok(const char *file, int l, const char *op, int value, const char *label)
1050 {
1051    nb++;
1052    if (!value) {
1053       err++;
1054       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1055    } else {
1056       printf("OK  %.30s\n", label);
1057    }
1058 }
1059
1060 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1061
1062 void _nok(const char *file, int l, const char *op, int value, const char *label)
1063 {
1064    nb++;
1065    if (value) {
1066       err++;
1067       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1068    } else {
1069       printf("OK  %.30s\n", label);
1070    }
1071 }
1072
1073 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1074
1075 int report()
1076 {
1077    printf("Result %i/%i OK\n", nb - err, nb);
1078    return err>0;
1079 }
1080
1081 /* 
1082  * TODO:
1083  *  - Must detect multiple lock
1084  *  - lock/unlock in wrong order
1085  *  - deadlock with 2 or 3 threads
1086  */
1087 int main(int argc, char **argv)
1088 {
1089    void *ret=NULL;
1090    lmgr_thread_t *self;
1091    pthread_t id1, id2, id3, tab[200];
1092    bthread_mutex_t bmutex1;
1093    pthread_mutex_t pmutex2;
1094    my_prog = argv[0];
1095
1096    use_undertaker = false;
1097    lmgr_init_thread();
1098    self = lmgr_get_thread_info();
1099
1100    if (argc == 2) {             /* do priority check */
1101       P(mutex_p2);                /* not permited */
1102       P(mutex_p1);
1103       V(mutex_p1);                /* never goes here */
1104       V(mutex_p2);
1105       return 0;
1106    }
1107
1108    pthread_mutex_init(&bmutex1, NULL);
1109    bthread_mutex_set_priority(&bmutex1, 10);
1110
1111    pthread_mutex_init(&pmutex2, NULL);
1112    P(bmutex1);
1113    ok(self->max_priority == 10, "Check self max_priority");
1114    P(pmutex2);
1115    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1116    V(pmutex2);
1117    V(bmutex1);
1118    ok(self->max_priority == 0, "Check self max_priority");
1119
1120    pthread_create(&id1, NULL, self_lock, NULL);
1121    sleep(2);
1122    ok(lmgr_detect_deadlock(), "Check self deadlock");
1123    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1124    pthread_join(id1, NULL);
1125
1126
1127    pthread_create(&id1, NULL, nolock, NULL);
1128    sleep(2);
1129    nok(lmgr_detect_deadlock(), "Check for nolock");
1130    pthread_join(id1, NULL);
1131
1132    P(mutex1);
1133    pthread_create(&id1, NULL, locker, &mutex1);
1134    pthread_create(&id2, NULL, locker, &mutex1);
1135    pthread_create(&id3, NULL, locker, &mutex1);
1136    sleep(2);
1137    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1138    V(mutex1);
1139    pthread_join(id1, NULL);
1140    pthread_join(id2, NULL);   
1141    pthread_join(id3, NULL);
1142
1143
1144    brwlock_t wr;
1145    rwl_init(&wr);
1146    rwl_writelock(&wr);
1147    rwl_writelock(&wr);
1148    pthread_create(&id1, NULL, rwlocker, &wr);
1149    pthread_create(&id2, NULL, rwlocker, &wr);
1150    pthread_create(&id3, NULL, rwlocker, &wr);
1151    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1152    rwl_writeunlock(&wr);
1153    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1154    rwl_writeunlock(&wr);
1155    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1156
1157    pthread_join(id1, NULL);
1158    pthread_join(id2, NULL);   
1159    pthread_join(id3, NULL);   
1160
1161    rwl_writelock(&wr);
1162    P(mutex1);
1163    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1164    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1165    V(mutex1);
1166    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1167    rwl_writeunlock(&wr);
1168    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1169    pthread_join(id1, NULL);
1170
1171    P(mutex5);
1172    P(mutex6);
1173    V(mutex5);
1174    V(mutex6);
1175
1176    nok(lmgr_detect_deadlock(), "Check for wrong order");
1177
1178    for(int j=0; j<200; j++) {
1179       pthread_create(&tab[j], NULL, thx, NULL);
1180    }
1181    for(int j=0; j<200; j++) {
1182       pthread_join(tab[j], NULL);
1183       if (j%3) { lmgr_detect_deadlock();}
1184    }
1185    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1186
1187    P(mutex4);
1188    P(mutex5);
1189    P(mutex6);
1190    V(mutex6);
1191    V(mutex5);
1192    V(mutex4);
1193
1194    pthread_create(&id1, NULL, th1, NULL);
1195    sleep(1);
1196    pthread_create(&id2, NULL, th2, NULL);
1197    sleep(1);
1198    ok(lmgr_detect_deadlock(), "Check for deadlock");
1199
1200    pthread_create(&id3, NULL, th_prio, NULL);
1201    pthread_join(id3, &ret);
1202    ok(ret != 0, "Check for priority segfault");
1203
1204    P(mutex_p1);
1205    ok(self->max_priority == 1, "Check max_priority 1/4");
1206    P(mutex_p2);
1207    ok(self->max_priority == 2, "Check max_priority 2/4");
1208    P(mutex_p3);
1209    ok(self->max_priority == 3, "Check max_priority 3/4");
1210    P(mutex6);
1211    ok(self->max_priority == 3, "Check max_priority 4/4");
1212    V(mutex6);
1213    ok(self->max_priority == 3, "Check max_priority 1/5");
1214    V(mutex_p3);
1215    ok(self->max_priority == 2, "Check max_priority 4/5");
1216    V(mutex_p2);
1217    ok(self->max_priority == 1, "Check max_priority 4/5");
1218    V(mutex_p1);
1219    ok(self->max_priority == 0, "Check max_priority 5/5");
1220
1221
1222    P(mutex_p1);
1223    P(mutex_p2);
1224    P(mutex_p3);
1225    P(mutex6);
1226    ok(self->max_priority == 3, "Check max_priority mixed");
1227    V(mutex_p2);
1228    ok(self->max_priority == 3, "Check max_priority mixed");
1229    V(mutex_p1);
1230    ok(self->max_priority == 3, "Check max_priority mixed");
1231    V(mutex_p3);
1232    ok(self->max_priority == 0, "Check max_priority mixed");
1233    V(mutex6);
1234    ok(self->max_priority == 0, "Check max_priority mixed");
1235
1236    P(mutex_p1);
1237    P(mutex_p2);
1238    V(mutex_p1);
1239    V(mutex_p2);
1240
1241 //   lmgr_dump();
1242 //
1243 //   pthread_create(&id3, NULL, th3, NULL);
1244 //
1245 //   pthread_join(id1, NULL);
1246 //   pthread_join(id2, NULL);
1247    lmgr_cleanup_main();
1248    sm_check(__FILE__, __LINE__, false);
1249    return report();
1250 }
1251
1252 #endif