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