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