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