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