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