]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Merge branch 'master' of ssh://bacula.git.sourceforge.net/gitroot/bacula/bacula
[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 is used only after a fatal signal
470  * We don't use locking to display the 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    if (!global_mgr) {
604       return;
605    }
606    pthread_cancel(undertaker);
607    lmgr_cleanup_thread();
608    pthread_mutex_lock(&lmgr_global_mutex);
609    {
610       temp = global_mgr;
611       global_mgr=NULL;
612       delete temp;
613    }
614    pthread_mutex_unlock(&lmgr_global_mutex);
615 }
616
617 /*
618  * Replacement for pthread_mutex_lock()
619  */
620 int lmgr_mutex_lock(pthread_mutex_t *m, const char *file, int line)
621 {
622    int ret;
623    lmgr_thread_t *self = lmgr_get_thread_info();
624    self->pre_P(m, file, line);
625    ret = pthread_mutex_lock(m);
626    self->post_P();   
627    return ret;
628 }
629
630 /*
631  * Replacement for pthread_mutex_unlock()
632  */
633 int lmgr_mutex_unlock(pthread_mutex_t *m, const char *file, int line)
634 {
635    lmgr_thread_t *self = lmgr_get_thread_info();
636    self->do_V(m, file, line);
637    return pthread_mutex_unlock(m);
638 }
639
640 /* TODO: check this
641  */
642 int lmgr_cond_wait(pthread_cond_t *cond,
643                    pthread_mutex_t *mutex,
644                    const char *file, int line)
645 {
646    int ret;
647    lmgr_thread_t *self = lmgr_get_thread_info();
648    self->do_V(mutex, file, line);   
649    ret = pthread_cond_wait(cond, mutex);
650    self->pre_P(mutex, file, line);
651    self->post_P();
652    return ret;
653 }
654
655 /*
656  * Use this function when the caller handle the mutex directly
657  *
658  * lmgr_pre_lock(m);
659  * pthread_mutex_lock(m);
660  * lmgr_post_lock(m);
661  */
662 void lmgr_pre_lock(void *m, const char *file, int line)
663 {
664    lmgr_thread_t *self = lmgr_get_thread_info();
665    self->pre_P(m, file, line);
666 }
667
668 /*
669  * Use this function when the caller handle the mutex directly
670  */
671 void lmgr_post_lock()
672 {
673    lmgr_thread_t *self = lmgr_get_thread_info();
674    self->post_P();
675 }
676
677 /*
678  * Do directly pre_P and post_P (used by trylock)
679  */
680 void lmgr_do_lock(void *m, const char *file, int line)
681 {
682    lmgr_thread_t *self = lmgr_get_thread_info();
683    self->pre_P(m, file, line);
684    self->post_P();
685 }
686
687 /*
688  * Use this function when the caller handle the mutex directly
689  */
690 void lmgr_do_unlock(void *m)
691 {
692    lmgr_thread_t *self = lmgr_get_thread_info();
693    self->do_V(m);
694 }
695
696 typedef struct {
697    void *(*start_routine)(void*);
698    void *arg;
699 } lmgr_thread_arg_t;
700
701 extern "C" 
702 void *lmgr_thread_launcher(void *x)
703 {
704    void *ret=NULL;
705    lmgr_init_thread();
706    pthread_cleanup_push(cln_hdl, NULL);
707
708    lmgr_thread_arg_t arg;
709    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
710    arg.start_routine = a->start_routine;
711    arg.arg = a->arg;
712    free(a);
713
714    ret = arg.start_routine(arg.arg);
715    pthread_cleanup_pop(1);
716    return ret;
717 }
718
719 int lmgr_thread_create(pthread_t *thread,
720                        const pthread_attr_t *attr,
721                        void *(*start_routine)(void*), void *arg)
722 {
723    /* Will be freed by the child */
724    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
725    a->start_routine = start_routine;
726    a->arg = arg;
727    return pthread_create(thread, attr, lmgr_thread_launcher, a);   
728 }
729
730 #else  /* _USE_LOCKMGR */
731
732 /*
733  * !!! WARNING !!! 
734  * Use this function is used only after a fatal signal
735  * We don't use locking to display information
736  */
737 void dbg_print_lock(FILE *fp)
738 {
739    Pmsg0(000, "lockmgr disabled\n");
740 }
741
742 #endif  /* _USE_LOCKMGR */
743
744 #ifdef _TEST_IT
745
746 #include "lockmgr.h"
747 #define pthread_mutex_lock(x)   lmgr_mutex_lock(x)
748 #define pthread_mutex_unlock(x) lmgr_mutex_unlock(x)
749 #define pthread_cond_wait(x,y)  lmgr_cond_wait(x,y)
750 #define pthread_create(a, b, c, d)  lmgr_thread_create(a,b,c,d)
751 #undef P
752 #undef V
753 #define P(x) lmgr_mutex_lock(&(x), __FILE__, __LINE__)
754 #define V(x) lmgr_mutex_unlock(&(x), __FILE__, __LINE__)
755
756 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
757 pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
758 pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
759 pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
760 pthread_mutex_t mutex5 = PTHREAD_MUTEX_INITIALIZER;
761 pthread_mutex_t mutex6 = PTHREAD_MUTEX_INITIALIZER;
762
763 void *self_lock(void *temp)
764 {
765    P(mutex1);
766    P(mutex1);
767    V(mutex1);
768    
769    return NULL;
770 }
771
772 void *nolock(void *temp)
773 {
774    P(mutex2);
775    sleep(5);
776    V(mutex2);
777    return NULL;
778 }
779
780 void *locker(void *temp)
781 {
782    pthread_mutex_t *m = (pthread_mutex_t*) temp;
783    pthread_mutex_lock(m);
784    pthread_mutex_unlock(m);
785    return NULL;
786 }
787
788 void *rwlocker(void *temp)
789 {
790    brwlock_t *m = (brwlock_t*) temp;
791    rwl_writelock(m);
792    rwl_writelock(m);
793
794    rwl_writeunlock(m);
795    rwl_writeunlock(m);
796    return NULL;
797 }
798
799 void *mix_rwl_mutex(void *temp)
800 {
801    brwlock_t *m = (brwlock_t*) temp;
802    P(mutex1);
803    rwl_writelock(m);
804    rwl_writeunlock(m);
805    V(mutex1);
806    return NULL;
807 }
808
809
810 void *th2(void *temp)
811 {
812    P(mutex2);
813    P(mutex1);
814    
815    lmgr_dump();
816
817    sleep(10);
818
819    V(mutex1);
820    V(mutex2);
821
822    lmgr_dump();
823    return NULL;
824 }
825 void *th1(void *temp)
826 {
827    P(mutex1);
828    sleep(2);
829    P(mutex2);
830    
831    lmgr_dump();
832
833    sleep(10);
834
835    V(mutex2);
836    V(mutex1);
837
838    lmgr_dump();
839    return NULL;
840 }
841
842 void *thx(void *temp)
843 {
844    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
845    P(mutex1);
846    bmicrosleep(0,s);
847    P(mutex2);
848    bmicrosleep(0,s);
849
850    V(mutex2);
851    V(mutex1);
852    return NULL;
853 }
854
855 void *th3(void *a) {
856    while (1) {
857       fprintf(stderr, "undertaker sleep()\n");
858       sleep(10);
859       lmgr_dump();
860       if (lmgr_detect_deadlock()) {
861          lmgr_dump();
862          exit(1);
863       }
864    }
865    return NULL;
866 }
867
868 int err=0;
869 int nb=0;
870 void _ok(const char *file, int l, const char *op, int value, const char *label)
871 {
872    nb++;
873    if (!value) {
874       err++;
875       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
876    } else {
877       printf("OK  %.30s\n", label);
878    }
879 }
880
881 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
882
883 void _nok(const char *file, int l, const char *op, int value, const char *label)
884 {
885    nb++;
886    if (value) {
887       err++;
888       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
889    } else {
890       printf("OK  %.30s\n", label);
891    }
892 }
893
894 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
895
896 int report()
897 {
898    printf("Result %i/%i OK\n", nb - err, nb);
899    return err>0;
900 }
901
902 /* 
903  * TODO:
904  *  - Must detect multiple lock
905  *  - lock/unlock in wrong order
906  *  - deadlock with 2 or 3 threads
907  */
908 int main()
909 {
910    pthread_t id1, id2, id3, tab[200];
911    lmgr_init_thread();
912
913    pthread_create(&id1, NULL, self_lock, NULL);
914    sleep(2);
915    ok(lmgr_detect_deadlock(), "Check self deadlock");
916    lmgr_v(&mutex1);             /* a bit dirty */
917    pthread_join(id1, NULL);
918
919
920    pthread_create(&id1, NULL, nolock, NULL);
921    sleep(2);
922    nok(lmgr_detect_deadlock(), "Check for nolock");
923    pthread_join(id1, NULL);
924
925    P(mutex1);
926    pthread_create(&id1, NULL, locker, &mutex1);
927    pthread_create(&id2, NULL, locker, &mutex1);
928    pthread_create(&id3, NULL, locker, &mutex1);
929    sleep(2);
930    nok(lmgr_detect_deadlock(), "Check for multiple lock");
931    V(mutex1);
932    pthread_join(id1, NULL);
933    pthread_join(id2, NULL);   
934    pthread_join(id3, NULL);
935
936
937    brwlock_t wr;
938    rwl_init(&wr);
939    rwl_writelock(&wr);
940    rwl_writelock(&wr);
941    pthread_create(&id1, NULL, rwlocker, &wr);
942    pthread_create(&id2, NULL, rwlocker, &wr);
943    pthread_create(&id3, NULL, rwlocker, &wr);
944    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
945    rwl_writeunlock(&wr);
946    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
947    rwl_writeunlock(&wr);
948    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
949
950    pthread_join(id1, NULL);
951    pthread_join(id2, NULL);   
952    pthread_join(id3, NULL);   
953
954    rwl_writelock(&wr);
955    P(mutex1);
956    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
957    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
958    V(mutex1);
959    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
960    rwl_writeunlock(&wr);
961    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
962    pthread_join(id1, NULL);
963
964    P(mutex5);
965    P(mutex6);
966    V(mutex5);
967    V(mutex6);
968
969    nok(lmgr_detect_deadlock(), "Check for wrong order");
970
971    for(int j=0; j<200; j++) {
972       pthread_create(&tab[j], NULL, thx, NULL);
973    }
974    for(int j=0; j<200; j++) {
975       pthread_join(tab[j], NULL);
976       if (j%3) { lmgr_detect_deadlock();}
977    }
978    nok(lmgr_detect_deadlock(), "Check 200 lockers");
979
980    P(mutex4);
981    P(mutex5);
982    P(mutex6);
983    V(mutex6);
984    V(mutex5);
985    V(mutex4);
986
987    pthread_create(&id1, NULL, th1, NULL);
988    sleep(1);
989    pthread_create(&id2, NULL, th2, NULL);
990    sleep(1);
991    ok(lmgr_detect_deadlock(), "Check for deadlock");
992
993 //   lmgr_dump();
994 //
995 //   pthread_create(&id3, NULL, th3, NULL);
996 //
997 //   pthread_join(id1, NULL);
998 //   pthread_join(id2, NULL);
999    lmgr_cleanup_main();
1000    sm_check(__FILE__, __LINE__, false);
1001    return report();
1002 }
1003
1004 #endif