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