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