]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
update lock manager to get better traces
[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=0x%x max=%i current=%i\n", (int)thread_id, max, current);
247       for(int i=0; i<=current; i++) {
248          fprintf(fp, "   lock=%p state=%c %s:%i\n", 
249                lock_list[i].lock, lock_list[i].state,
250                lock_list[i].file, lock_list[i].line);
251       }
252    }
253
254    void dump(FILE *fp) {
255       pthread_mutex_lock(&mutex);
256       {
257          _dump(fp);
258       }
259       pthread_mutex_unlock(&mutex);
260    }
261
262    /*
263     * Call before a lock operation (mark mutex as WANTED)
264     */
265    virtual void pre_P(void *m, const char *f="*unknown*", int l=0) {
266       ASSERT(current < LMGR_MAX_LOCK);
267       ASSERT(current >= -1);
268       pthread_mutex_lock(&mutex);
269       {
270          current++;
271          lock_list[current].lock = m;
272          lock_list[current].state = LMGR_LOCK_WANTED;
273          lock_list[current].file = f;
274          lock_list[current].line = l;
275          max = MAX(current, max);
276       }
277       pthread_mutex_unlock(&mutex);
278    }
279
280    /*
281     * Call after the lock operation (mark mutex as GRANTED)
282     */
283    virtual void post_P() {
284       ASSERT(current >= 0);
285       ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
286       lock_list[current].state = LMGR_LOCK_GRANTED;
287    }
288    
289    void shift_list(int i) {
290       for(int j=i+1; j<=current; j++) {
291          lock_list[i] = lock_list[j];
292       }
293       if (current >= 0) {
294          lock_list[current].lock = NULL;
295          lock_list[current].state = LMGR_LOCK_EMPTY;
296       }
297    }
298
299    /*
300     * Remove the mutex from the list
301     */
302    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
303       ASSERT(current >= 0);
304       pthread_mutex_lock(&mutex);
305       {
306          if (lock_list[current].lock == m) {
307             lock_list[current].lock = NULL;
308             lock_list[current].state = LMGR_LOCK_EMPTY;
309             current--;
310          } else {
311             ASSERT(current > 0);
312             Pmsg3(0, "ERROR: wrong P/V order search lock=%p %s:%i\n", m, f, l);
313             Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
314                     current, lock_list[current].lock, lock_list[current].file, 
315                     lock_list[current].line);
316             for (int i=current-1; i >= 0; i--) { /* already seen current */
317                Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
318                      i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
319                if (lock_list[i].lock == m) {
320                   Pmsg3(000, "ERROR: FOUND P pos=%i %s:%i\n", i, f, l);
321                   shift_list(i);
322                   current--;
323                   break;
324                }
325             }
326          }
327       }
328       pthread_mutex_unlock(&mutex);
329    }
330
331    virtual ~lmgr_thread_t() {destroy();}
332
333    void destroy() {
334       pthread_mutex_destroy(&mutex);
335    }
336 } ;
337
338 class lmgr_dummy_thread_t: public lmgr_thread_t
339 {
340    void do_V(void *m, const char *file, int l)  {}
341    void post_P()                                {}
342    void pre_P(void *m, const char *file, int l) {}
343 };
344
345 /*
346  * LMGR - Lock Manager
347  *
348  *
349  *
350  */
351
352 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT; 
353 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
354
355 static dlist *global_mgr=NULL;  /* used to store all lgmr_thread_t objects */
356 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
357 static pthread_t undertaker;
358
359 #define lmgr_is_active() (global_mgr != NULL)
360
361 /*
362  * Add a new lmgr_thread_t object to the global list
363  */
364 void lmgr_register_thread(lmgr_thread_t *item)
365 {
366    pthread_mutex_lock(&lmgr_global_mutex);
367    {
368       global_mgr->prepend(item);
369    }
370    pthread_mutex_unlock(&lmgr_global_mutex);
371 }
372
373 /*
374  * Call this function to cleanup specific lock thread data
375  */
376 void lmgr_unregister_thread(lmgr_thread_t *item)
377 {
378    if (!lmgr_is_active()) {
379       return;
380    }
381    pthread_mutex_lock(&lmgr_global_mutex);
382    {
383       global_mgr->remove(item);
384    }
385    pthread_mutex_unlock(&lmgr_global_mutex);
386 }
387
388 /*
389  * Search for a deadlock when it's secure to walk across
390  * locks list. (after lmgr_detect_deadlock or a fatal signal)
391  */
392 bool lmgr_detect_deadlock_unlocked()
393 {
394    bool ret=false;
395    lmgr_node_t *node=NULL;
396    lmgr_lock_t *lock;
397    lmgr_thread_t *item;
398    dlist *g = New(dlist(node, &node->link));
399
400    /* First, get a list of all node */
401    foreach_dlist(item, global_mgr) {
402       for(int i=0; i<=item->current; i++) {
403          node = NULL;
404          lock = &item->lock_list[i];
405          /* Depending if the lock is granted or not, it's a child or a root
406           *  Granted:  Mutex  -> Thread
407           *  Wanted:   Thread -> Mutex
408           *
409           * Note: a Mutex can be locked only once, a thread can request only
410           * one mutex.
411           *
412           */
413          if (lock->state == LMGR_LOCK_GRANTED) {
414             node = New(lmgr_node_t((void*)lock->lock, (void*)item->thread_id));
415          } else if (lock->state == LMGR_LOCK_WANTED) {
416             node = New(lmgr_node_t((void*)item->thread_id, (void*)lock->lock));
417          }
418          if (node) {
419             g->append(node);
420          }
421       }
422    }      
423    
424    //foreach_dlist(node, g) {
425    //   printf("g n=%p c=%p\n", node->node, node->child);
426    //}
427
428    ret = contains_cycle(g);
429    if (ret) {
430       printf("Found a deadlock !!!!\n");
431    }
432    
433    delete g;
434    return ret;
435 }
436
437 /*
438  * Search for a deadlock in during the runtime
439  * It will lock all thread specific lock manager, nothing
440  * can be locked during this check.
441  */
442 bool lmgr_detect_deadlock()
443 {
444    bool ret=false;
445    if (!lmgr_is_active()) {
446       return ret;
447    } 
448
449    pthread_mutex_lock(&lmgr_global_mutex);
450    {
451       lmgr_thread_t *item;
452       foreach_dlist(item, global_mgr) {
453          pthread_mutex_lock(&item->mutex);
454       }
455
456       ret = lmgr_detect_deadlock_unlocked();
457
458       foreach_dlist(item, global_mgr) {
459          pthread_mutex_unlock(&item->mutex);
460       }
461    }
462    pthread_mutex_unlock(&lmgr_global_mutex);
463
464    return ret;
465 }
466
467 /*
468  * !!! WARNING !!! 
469  * Use this function only after a fatal signal
470  * We don't use any lock to display information
471  */
472 void dbg_print_lock(FILE *fp)
473 {
474    fprintf(fp, "Attempt to dump locks\n");
475    if (!lmgr_is_active()) {
476       return ;
477    }
478    lmgr_thread_t *item;
479    foreach_dlist(item, global_mgr) {
480       item->_dump(fp);
481    }
482 }
483
484 /*
485  * Dump each lmgr_thread_t object
486  */
487 void lmgr_dump()
488 {
489    pthread_mutex_lock(&lmgr_global_mutex);
490    {
491       lmgr_thread_t *item;
492       foreach_dlist(item, global_mgr) {
493          item->dump(stderr);
494       }
495    }
496    pthread_mutex_unlock(&lmgr_global_mutex);
497 }
498
499 void cln_hdl(void *a)
500 {
501    lmgr_cleanup_thread();
502 }
503
504 void *check_deadlock(void *)
505 {
506    int old;
507    lmgr_init_thread();
508    pthread_cleanup_push(cln_hdl, NULL);
509
510    while (!bmicrosleep(30, 0)) {
511       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
512       if (lmgr_detect_deadlock()) {
513          lmgr_dump();
514          ASSERT(0);
515       }
516       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
517       pthread_testcancel();
518    }
519    Pmsg0(000, "Undertaker is leaving...\n");
520    pthread_cleanup_pop(1);
521    return NULL;
522 }
523
524 /* This object is used when LMGR is not initialized */
525 lmgr_dummy_thread_t dummy_lmgr;
526
527 /*
528  * Retrieve the lmgr_thread_t object from the stack
529  */
530 inline lmgr_thread_t *lmgr_get_thread_info()
531 {
532    if (lmgr_is_active()) {
533       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
534    } else {
535       return &dummy_lmgr;
536    }
537 }
538
539 /*
540  * launch once for all threads
541  */
542 void create_lmgr_key()
543 {
544    int status = pthread_key_create(&lmgr_key, NULL);
545    if (status != 0) {
546       berrno be;
547       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
548             be.bstrerror(status));
549       ASSERT(0);
550    }
551
552    lmgr_thread_t *n=NULL;
553    global_mgr = New(dlist(n, &n->link));
554
555    if (pthread_create(&undertaker, NULL, check_deadlock, NULL) != 0) {
556       berrno be;
557       Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
558             be.bstrerror(status));
559       ASSERT(0);
560    }
561 }
562
563 /*
564  * Each thread have to call this function to put a lmgr_thread_t object
565  * in the stack and be able to call mutex_lock/unlock
566  */
567 void lmgr_init_thread()
568 {
569    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
570    if (status != 0) {
571       berrno be;
572       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
573             be.bstrerror(status));
574       ASSERT(0);
575    }
576    lmgr_thread_t *l = New(lmgr_thread_t());
577    pthread_setspecific(lmgr_key, l);
578    lmgr_register_thread(l);
579 }
580
581 /*
582  * Call this function at the end of the thread
583  */
584 void lmgr_cleanup_thread()
585 {
586    if (!lmgr_is_active()) {
587       return ;
588    }
589    lmgr_thread_t *self = lmgr_get_thread_info();
590    lmgr_unregister_thread(self);
591    delete(self);
592 }
593
594 /*
595  * This function should be call at the end of the main thread
596  * Some thread like the watchdog are already present, so the global_mgr
597  * list is never empty. Should carefully clear the memory.
598  */
599 void lmgr_cleanup_main()
600 {
601    dlist *temp;
602    
603    pthread_cancel(undertaker);
604    lmgr_cleanup_thread();
605    pthread_mutex_lock(&lmgr_global_mutex);
606    {
607       temp = global_mgr;
608       global_mgr=NULL;
609       delete temp;
610    }
611    pthread_mutex_unlock(&lmgr_global_mutex);
612 }
613
614 /*
615  * Replacement for pthread_mutex_lock()
616  */
617 int lmgr_mutex_lock(pthread_mutex_t *m, const char *file, int line)
618 {
619    int ret;
620    lmgr_thread_t *self = lmgr_get_thread_info();
621    self->pre_P(m, file, line);
622    ret = pthread_mutex_lock(m);
623    self->post_P();   
624    return ret;
625 }
626
627 /*
628  * Replacement for pthread_mutex_unlock()
629  */
630 int lmgr_mutex_unlock(pthread_mutex_t *m, const char *file, int line)
631 {
632    lmgr_thread_t *self = lmgr_get_thread_info();
633    self->do_V(m, file, line);
634    return pthread_mutex_unlock(m);
635 }
636
637 /* TODO: check this
638  */
639 int lmgr_cond_wait(pthread_cond_t *cond,
640                    pthread_mutex_t *mutex,
641                    const char *file, int line)
642 {
643    int ret;
644    lmgr_thread_t *self = lmgr_get_thread_info();
645    self->do_V(mutex, file, line);   
646    ret = pthread_cond_wait(cond, mutex);
647    self->pre_P(mutex, file, line);
648    self->post_P();
649    return ret;
650 }
651
652 /*
653  * Use this function when the caller handle the mutex directly
654  *
655  * lmgr_pre_lock(m);
656  * pthread_mutex_lock(m);
657  * lmgr_post_lock(m);
658  */
659 void lmgr_pre_lock(void *m, const char *file, int line)
660 {
661    lmgr_thread_t *self = lmgr_get_thread_info();
662    self->pre_P(m, file, line);
663 }
664
665 /*
666  * Use this function when the caller handle the mutex directly
667  */
668 void lmgr_post_lock()
669 {
670    lmgr_thread_t *self = lmgr_get_thread_info();
671    self->post_P();
672 }
673
674 /*
675  * Do directly pre_P and post_P (used by trylock)
676  */
677 void lmgr_do_lock(void *m, const char *file, int line)
678 {
679    lmgr_thread_t *self = lmgr_get_thread_info();
680    self->pre_P(m, file, line);
681    self->post_P();
682 }
683
684 /*
685  * Use this function when the caller handle the mutex directly
686  */
687 void lmgr_do_unlock(void *m)
688 {
689    lmgr_thread_t *self = lmgr_get_thread_info();
690    self->do_V(m);
691 }
692
693 typedef struct {
694    void *(*start_routine)(void*);
695    void *arg;
696 } lmgr_thread_arg_t;
697
698 extern "C" 
699 void *lmgr_thread_launcher(void *x)
700 {
701    void *ret=NULL;
702    lmgr_init_thread();
703    pthread_cleanup_push(cln_hdl, NULL);
704
705    lmgr_thread_arg_t arg;
706    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
707    arg.start_routine = a->start_routine;
708    arg.arg = a->arg;
709    free(a);
710
711    ret = arg.start_routine(arg.arg);
712    pthread_cleanup_pop(1);
713    return ret;
714 }
715
716 int lmgr_thread_create(pthread_t *thread,
717                        const pthread_attr_t *attr,
718                        void *(*start_routine)(void*), void *arg)
719 {
720    /* Will be freed by the child */
721    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
722    a->start_routine = start_routine;
723    a->arg = arg;
724    return pthread_create(thread, attr, lmgr_thread_launcher, a);   
725 }
726
727 #else  /* _USE_LOCKMGR */
728
729 /*
730  * !!! WARNING !!! 
731  * Use this function only after a fatal signal
732  * We don't use any lock to display information
733  */
734 void dbg_print_lock(FILE *fp)
735 {
736    Pmsg0(000, "lockmgr disabled\n");
737 }
738
739 #endif  /* _USE_LOCKMGR */
740
741 #ifdef _TEST_IT
742
743 #include "lockmgr.h"
744 #define pthread_mutex_lock(x)   lmgr_mutex_lock(x)
745 #define pthread_mutex_unlock(x) lmgr_mutex_unlock(x)
746 #define pthread_cond_wait(x,y)  lmgr_cond_wait(x,y)
747 #define pthread_create(a, b, c, d)  lmgr_thread_create(a,b,c,d)
748 #undef P
749 #undef V
750 #define P(x) lmgr_mutex_lock(&(x), __FILE__, __LINE__)
751 #define V(x) lmgr_mutex_unlock(&(x), __FILE__, __LINE__)
752
753 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
754 pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
755 pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
756 pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
757 pthread_mutex_t mutex5 = PTHREAD_MUTEX_INITIALIZER;
758 pthread_mutex_t mutex6 = PTHREAD_MUTEX_INITIALIZER;
759
760 void *self_lock(void *temp)
761 {
762    P(mutex1);
763    P(mutex1);
764    V(mutex1);
765    
766    return NULL;
767 }
768
769 void *nolock(void *temp)
770 {
771    P(mutex2);
772    sleep(5);
773    V(mutex2);
774    return NULL;
775 }
776
777 void *locker(void *temp)
778 {
779    pthread_mutex_t *m = (pthread_mutex_t*) temp;
780    pthread_mutex_lock(m);
781    pthread_mutex_unlock(m);
782    return NULL;
783 }
784
785 void *rwlocker(void *temp)
786 {
787    brwlock_t *m = (brwlock_t*) temp;
788    rwl_writelock(m);
789    rwl_writelock(m);
790
791    rwl_writeunlock(m);
792    rwl_writeunlock(m);
793    return NULL;
794 }
795
796 void *mix_rwl_mutex(void *temp)
797 {
798    brwlock_t *m = (brwlock_t*) temp;
799    P(mutex1);
800    rwl_writelock(m);
801    rwl_writeunlock(m);
802    V(mutex1);
803    return NULL;
804 }
805
806
807 void *th2(void *temp)
808 {
809    P(mutex2);
810    P(mutex1);
811    
812    lmgr_dump();
813
814    sleep(10);
815
816    V(mutex1);
817    V(mutex2);
818
819    lmgr_dump();
820    return NULL;
821 }
822 void *th1(void *temp)
823 {
824    P(mutex1);
825    sleep(2);
826    P(mutex2);
827    
828    lmgr_dump();
829
830    sleep(10);
831
832    V(mutex2);
833    V(mutex1);
834
835    lmgr_dump();
836    return NULL;
837 }
838
839 void *thx(void *temp)
840 {
841    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
842    P(mutex1);
843    bmicrosleep(0,s);
844    P(mutex2);
845    bmicrosleep(0,s);
846
847    V(mutex2);
848    V(mutex1);
849    return NULL;
850 }
851
852 void *th3(void *a) {
853    while (1) {
854       fprintf(stderr, "undertaker sleep()\n");
855       sleep(10);
856       lmgr_dump();
857       if (lmgr_detect_deadlock()) {
858          lmgr_dump();
859          exit(1);
860       }
861    }
862    return NULL;
863 }
864
865 int err=0;
866 int nb=0;
867 void _ok(const char *file, int l, const char *op, int value, const char *label)
868 {
869    nb++;
870    if (!value) {
871       err++;
872       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
873    } else {
874       printf("OK  %.30s\n", label);
875    }
876 }
877
878 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
879
880 void _nok(const char *file, int l, const char *op, int value, const char *label)
881 {
882    nb++;
883    if (value) {
884       err++;
885       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
886    } else {
887       printf("OK  %.30s\n", label);
888    }
889 }
890
891 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
892
893 int report()
894 {
895    printf("Result %i/%i OK\n", nb - err, nb);
896    return err>0;
897 }
898
899 /* 
900  * TODO:
901  *  - Must detect multiple lock
902  *  - lock/unlock in wrong order
903  *  - deadlock with 2 or 3 threads
904  */
905 int main()
906 {
907    pthread_t id1, id2, id3, tab[200];
908    lmgr_init_thread();
909
910    pthread_create(&id1, NULL, self_lock, NULL);
911    sleep(2);
912    ok(lmgr_detect_deadlock(), "Check self deadlock");
913    lmgr_v(&mutex1);             /* a bit dirty */
914    pthread_join(id1, NULL);
915
916
917    pthread_create(&id1, NULL, nolock, NULL);
918    sleep(2);
919    nok(lmgr_detect_deadlock(), "Check for nolock");
920    pthread_join(id1, NULL);
921
922    P(mutex1);
923    pthread_create(&id1, NULL, locker, &mutex1);
924    pthread_create(&id2, NULL, locker, &mutex1);
925    pthread_create(&id3, NULL, locker, &mutex1);
926    sleep(2);
927    nok(lmgr_detect_deadlock(), "Check for multiple lock");
928    V(mutex1);
929    pthread_join(id1, NULL);
930    pthread_join(id2, NULL);   
931    pthread_join(id3, NULL);
932
933
934    brwlock_t wr;
935    rwl_init(&wr);
936    rwl_writelock(&wr);
937    rwl_writelock(&wr);
938    pthread_create(&id1, NULL, rwlocker, &wr);
939    pthread_create(&id2, NULL, rwlocker, &wr);
940    pthread_create(&id3, NULL, rwlocker, &wr);
941    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
942    rwl_writeunlock(&wr);
943    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
944    rwl_writeunlock(&wr);
945    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
946
947    pthread_join(id1, NULL);
948    pthread_join(id2, NULL);   
949    pthread_join(id3, NULL);   
950
951    rwl_writelock(&wr);
952    P(mutex1);
953    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
954    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
955    V(mutex1);
956    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
957    rwl_writeunlock(&wr);
958    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
959    pthread_join(id1, NULL);
960
961    P(mutex5);
962    P(mutex6);
963    V(mutex5);
964    V(mutex6);
965
966    nok(lmgr_detect_deadlock(), "Check for wrong order");
967
968    for(int j=0; j<200; j++) {
969       pthread_create(&tab[j], NULL, thx, NULL);
970    }
971    for(int j=0; j<200; j++) {
972       pthread_join(tab[j], NULL);
973       if (j%3) { lmgr_detect_deadlock();}
974    }
975    nok(lmgr_detect_deadlock(), "Check 200 lockers");
976
977    P(mutex4);
978    P(mutex5);
979    P(mutex6);
980    V(mutex6);
981    V(mutex5);
982    V(mutex4);
983
984    pthread_create(&id1, NULL, th1, NULL);
985    sleep(1);
986    pthread_create(&id2, NULL, th2, NULL);
987    sleep(1);
988    ok(lmgr_detect_deadlock(), "Check for deadlock");
989
990 //   lmgr_dump();
991 //
992 //   pthread_create(&id3, NULL, th3, NULL);
993 //
994 //   pthread_join(id1, NULL);
995 //   pthread_join(id2, NULL);
996    lmgr_cleanup_main();
997    sm_check(__FILE__, __LINE__, false);
998    return report();
999 }
1000
1001 #endif