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