]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
add lmgr to bconsole
[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 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    /* Will be freed by the child */
725    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
726    a->start_routine = start_routine;
727    a->arg = arg;
728    return pthread_create(thread, attr, lmgr_thread_launcher, a);   
729 }
730
731 #else  /* _USE_LOCKMGR */
732
733 /*
734  * !!! WARNING !!! 
735  * Use this function is used only after a fatal signal
736  * We don't use locking to display information
737  */
738 void dbg_print_lock(FILE *fp)
739 {
740    Pmsg0(000, "lockmgr disabled\n");
741 }
742
743 #endif  /* _USE_LOCKMGR */
744
745 #ifdef _TEST_IT
746
747 #include "lockmgr.h"
748 #define pthread_mutex_lock(x)   lmgr_mutex_lock(x)
749 #define pthread_mutex_unlock(x) lmgr_mutex_unlock(x)
750 #define pthread_cond_wait(x,y)  lmgr_cond_wait(x,y)
751 #define pthread_create(a, b, c, d)  lmgr_thread_create(a,b,c,d)
752 #undef P
753 #undef V
754 #define P(x) lmgr_mutex_lock(&(x), __FILE__, __LINE__)
755 #define V(x) lmgr_mutex_unlock(&(x), __FILE__, __LINE__)
756
757 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
758 pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
759 pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
760 pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
761 pthread_mutex_t mutex5 = PTHREAD_MUTEX_INITIALIZER;
762 pthread_mutex_t mutex6 = PTHREAD_MUTEX_INITIALIZER;
763
764 void *self_lock(void *temp)
765 {
766    P(mutex1);
767    P(mutex1);
768    V(mutex1);
769    
770    return NULL;
771 }
772
773 void *nolock(void *temp)
774 {
775    P(mutex2);
776    sleep(5);
777    V(mutex2);
778    return NULL;
779 }
780
781 void *locker(void *temp)
782 {
783    pthread_mutex_t *m = (pthread_mutex_t*) temp;
784    pthread_mutex_lock(m);
785    pthread_mutex_unlock(m);
786    return NULL;
787 }
788
789 void *rwlocker(void *temp)
790 {
791    brwlock_t *m = (brwlock_t*) temp;
792    rwl_writelock(m);
793    rwl_writelock(m);
794
795    rwl_writeunlock(m);
796    rwl_writeunlock(m);
797    return NULL;
798 }
799
800 void *mix_rwl_mutex(void *temp)
801 {
802    brwlock_t *m = (brwlock_t*) temp;
803    P(mutex1);
804    rwl_writelock(m);
805    rwl_writeunlock(m);
806    V(mutex1);
807    return NULL;
808 }
809
810
811 void *th2(void *temp)
812 {
813    P(mutex2);
814    P(mutex1);
815    
816    lmgr_dump();
817
818    sleep(10);
819
820    V(mutex1);
821    V(mutex2);
822
823    lmgr_dump();
824    return NULL;
825 }
826 void *th1(void *temp)
827 {
828    P(mutex1);
829    sleep(2);
830    P(mutex2);
831    
832    lmgr_dump();
833
834    sleep(10);
835
836    V(mutex2);
837    V(mutex1);
838
839    lmgr_dump();
840    return NULL;
841 }
842
843 void *thx(void *temp)
844 {
845    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
846    P(mutex1);
847    bmicrosleep(0,s);
848    P(mutex2);
849    bmicrosleep(0,s);
850
851    V(mutex2);
852    V(mutex1);
853    return NULL;
854 }
855
856 void *th3(void *a) {
857    while (1) {
858       fprintf(stderr, "undertaker sleep()\n");
859       sleep(10);
860       lmgr_dump();
861       if (lmgr_detect_deadlock()) {
862          lmgr_dump();
863          exit(1);
864       }
865    }
866    return NULL;
867 }
868
869 int err=0;
870 int nb=0;
871 void _ok(const char *file, int l, const char *op, int value, const char *label)
872 {
873    nb++;
874    if (!value) {
875       err++;
876       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
877    } else {
878       printf("OK  %.30s\n", label);
879    }
880 }
881
882 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
883
884 void _nok(const char *file, int l, const char *op, int value, const char *label)
885 {
886    nb++;
887    if (value) {
888       err++;
889       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
890    } else {
891       printf("OK  %.30s\n", label);
892    }
893 }
894
895 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
896
897 int report()
898 {
899    printf("Result %i/%i OK\n", nb - err, nb);
900    return err>0;
901 }
902
903 /* 
904  * TODO:
905  *  - Must detect multiple lock
906  *  - lock/unlock in wrong order
907  *  - deadlock with 2 or 3 threads
908  */
909 int main()
910 {
911    pthread_t id1, id2, id3, tab[200];
912    lmgr_init_thread();
913
914    pthread_create(&id1, NULL, self_lock, NULL);
915    sleep(2);
916    ok(lmgr_detect_deadlock(), "Check self deadlock");
917    lmgr_v(&mutex1);             /* a bit dirty */
918    pthread_join(id1, NULL);
919
920
921    pthread_create(&id1, NULL, nolock, NULL);
922    sleep(2);
923    nok(lmgr_detect_deadlock(), "Check for nolock");
924    pthread_join(id1, NULL);
925
926    P(mutex1);
927    pthread_create(&id1, NULL, locker, &mutex1);
928    pthread_create(&id2, NULL, locker, &mutex1);
929    pthread_create(&id3, NULL, locker, &mutex1);
930    sleep(2);
931    nok(lmgr_detect_deadlock(), "Check for multiple lock");
932    V(mutex1);
933    pthread_join(id1, NULL);
934    pthread_join(id2, NULL);   
935    pthread_join(id3, NULL);
936
937
938    brwlock_t wr;
939    rwl_init(&wr);
940    rwl_writelock(&wr);
941    rwl_writelock(&wr);
942    pthread_create(&id1, NULL, rwlocker, &wr);
943    pthread_create(&id2, NULL, rwlocker, &wr);
944    pthread_create(&id3, NULL, rwlocker, &wr);
945    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
946    rwl_writeunlock(&wr);
947    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
948    rwl_writeunlock(&wr);
949    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
950
951    pthread_join(id1, NULL);
952    pthread_join(id2, NULL);   
953    pthread_join(id3, NULL);   
954
955    rwl_writelock(&wr);
956    P(mutex1);
957    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
958    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
959    V(mutex1);
960    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
961    rwl_writeunlock(&wr);
962    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
963    pthread_join(id1, NULL);
964
965    P(mutex5);
966    P(mutex6);
967    V(mutex5);
968    V(mutex6);
969
970    nok(lmgr_detect_deadlock(), "Check for wrong order");
971
972    for(int j=0; j<200; j++) {
973       pthread_create(&tab[j], NULL, thx, NULL);
974    }
975    for(int j=0; j<200; j++) {
976       pthread_join(tab[j], NULL);
977       if (j%3) { lmgr_detect_deadlock();}
978    }
979    nok(lmgr_detect_deadlock(), "Check 200 lockers");
980
981    P(mutex4);
982    P(mutex5);
983    P(mutex6);
984    V(mutex6);
985    V(mutex5);
986    V(mutex4);
987
988    pthread_create(&id1, NULL, th1, NULL);
989    sleep(1);
990    pthread_create(&id2, NULL, th2, NULL);
991    sleep(1);
992    ok(lmgr_detect_deadlock(), "Check for deadlock");
993
994 //   lmgr_dump();
995 //
996 //   pthread_create(&id3, NULL, th3, NULL);
997 //
998 //   pthread_join(id1, NULL);
999 //   pthread_join(id2, NULL);
1000    lmgr_cleanup_main();
1001    sm_check(__FILE__, __LINE__, false);
1002    return report();
1003 }
1004
1005 #endif