]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lockmgr.c
Fix new killsafe code
[bacula/bacula] / bacula / src / lib / lockmgr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2010 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 /*
30   How to use mutex with bad order usage detection
31  ------------------------------------------------
32
33  Note: see file mutex_list.h for current mutexes with 
34        defined priorities.
35
36  Instead of using:
37     pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
38     P(mutex);
39     ..
40     V(mutex);
41
42  use:
43     bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
44     P(mutex);
45     ...
46     V(mutex);
47
48  Mutex that doesn't need this extra check can be declared as pthread_mutex_t.
49  You can use this object on pthread_mutex_lock/unlock/cond_wait/cond_timewait.
50  
51  With dynamic creation, you can use:
52     bthread_mutex_t mutex;
53     pthread_mutex_init(&mutex);
54     bthread_mutex_set_priority(&mutex, 10);
55     pthread_mutex_destroy(&mutex);
56  
57  */
58
59 #define _LOCKMGR_COMPLIANT
60 #include "bacula.h"
61
62 #undef ASSERT
63 #define ASSERT(x) if (!(x)) { \
64    char *jcr = NULL; \
65    Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
66    jcr[0] = 0; }
67
68 #define ASSERT_p(x,f,l) if (!(x)) {              \
69    char *jcr = NULL; \
70    Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
71    jcr[0] = 0; }
72
73 /*
74   Inspired from 
75   http://www.cs.berkeley.edu/~kamil/teaching/sp03/041403.pdf
76
77   This lock manager will replace some pthread calls. It can be
78   enabled with _USE_LOCKMGR
79
80   Some part of the code can't use this manager, for example the
81   rwlock object or the smartalloc lib. To disable LMGR, just add
82   _LOCKMGR_COMPLIANT before the inclusion of "bacula.h"
83
84   cd build/src/tools
85   g++ -g -c lockmgr.c -I.. -I../lib -D_USE_LOCKMGR -D_TEST_IT
86   g++ -o lockmgr lockmgr.o -lbac -L../lib/.libs -lssl -lpthread
87
88 */
89
90
91 /*
92  * pthread_mutex_lock for memory allocator and other
93  * parts that are _LOCKMGR_COMPLIANT
94  */
95 void lmgr_p(pthread_mutex_t *m)
96 {
97    int errstat;
98    if ((errstat=pthread_mutex_lock(m))) {
99       berrno be;
100       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
101             be.bstrerror(errstat));
102    }
103 }
104
105 void lmgr_v(pthread_mutex_t *m)
106 {
107    int errstat;
108    if ((errstat=pthread_mutex_unlock(m))) {
109       berrno be;
110       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
111             be.bstrerror(errstat));
112    }
113 }
114
115 #ifdef _USE_LOCKMGR
116
117 typedef enum
118 {
119    LMGR_WHITE,                  /* never seen */
120    LMGR_BLACK,                  /* no loop */
121    LMGR_GREY,                   /* seen before */
122 } lmgr_color_t;
123
124 /*
125  * Node used by the Lock Manager
126  * If the lock is GRANTED, we have mutex -> proc, else it's a proc -> mutex
127  * relation.
128  *
129  * Note, each mutex can be GRANTED once, and each proc can have only one WANTED
130  * mutex.
131  */
132 class lmgr_node_t: public SMARTALLOC
133 {
134 public:
135    dlink link;
136    void *node;
137    void *child;
138    lmgr_color_t seen;
139
140    lmgr_node_t() {
141       child = node = NULL;
142       seen = LMGR_WHITE;
143    }
144
145    lmgr_node_t(void *n, void *c) {
146       init(n,c);
147    }
148
149    void init(void *n, void *c) {
150       node = n;
151       child = c;
152       seen = LMGR_WHITE;      
153    }
154
155    void mark_as_seen(lmgr_color_t c) {
156       seen = c;
157    }
158
159    ~lmgr_node_t() {printf("delete node\n");}
160 };
161
162 typedef enum {
163    LMGR_LOCK_EMPTY   = 'E',      /* unused */
164    LMGR_LOCK_WANTED  = 'W',      /* before mutex_lock */
165    LMGR_LOCK_GRANTED = 'G'       /* after mutex_lock */
166 } lmgr_state_t;
167
168 /*
169  * Object associated with each mutex per thread
170  */
171 class lmgr_lock_t: public SMARTALLOC
172 {
173 public:
174    dlink link;
175    void *lock;
176    lmgr_state_t state;
177    int max_priority;
178    int priority;
179
180    const char *file;
181    int line;
182
183    lmgr_lock_t() {
184       lock = NULL;
185       state = LMGR_LOCK_EMPTY;
186       priority = max_priority = 0;
187    }
188
189    lmgr_lock_t(void *l) {
190       lock = l;
191       state = LMGR_LOCK_WANTED;
192    }
193
194    void set_granted() {
195       state = LMGR_LOCK_GRANTED;
196    }
197
198    ~lmgr_lock_t() {}
199
200 };
201
202 /* 
203  * Get the child list, ret must be already allocated
204  */
205 static void search_all_node(dlist *g, lmgr_node_t *v, alist *ret)
206 {
207    lmgr_node_t *n;
208    foreach_dlist(n, g) {
209       if (v->child == n->node) {
210          ret->append(n);
211       }
212    }
213 }
214
215 static bool visite(dlist *g, lmgr_node_t *v)
216 {
217    bool ret=false;
218    lmgr_node_t *n;
219    v->mark_as_seen(LMGR_GREY);
220
221    alist *d = New(alist(5, false)); /* use alist because own=false */
222    search_all_node(g, v, d);
223
224    //foreach_alist(n, d) {
225    //   printf("node n=%p c=%p s=%c\n", n->node, n->child, n->seen);
226    //}
227
228    foreach_alist(n, d) {
229       if (n->seen == LMGR_GREY) { /* already seen this node */
230          ret = true;
231          goto bail_out;
232       } else if (n->seen == LMGR_WHITE) {
233          if (visite(g, n)) {
234             ret = true;
235             goto bail_out;
236          }
237       }
238    }
239    v->mark_as_seen(LMGR_BLACK); /* no loop detected, node is clean */
240 bail_out:
241    delete d;
242    return ret;
243 }
244
245 static bool contains_cycle(dlist *g)
246 {
247    lmgr_node_t *n;
248    foreach_dlist(n, g) {
249       if (n->seen == LMGR_WHITE) {
250          if (visite(g, n)) {
251             return true;
252          }
253       }
254    }
255    return false;
256 }
257
258 /****************************************************************/
259
260 class lmgr_thread_t: public SMARTALLOC
261 {
262 public:
263    dlink link;
264    pthread_mutex_t mutex;
265    pthread_t       thread_id;
266    lmgr_lock_t     lock_list[LMGR_MAX_LOCK];
267    int current;
268    int max;
269    int max_priority;
270
271    lmgr_thread_t() {
272       int status;
273       if ((status = pthread_mutex_init(&mutex, NULL)) != 0) {
274          berrno be;
275          Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
276                  be.bstrerror(status));
277          ASSERT(0);
278       }
279       thread_id = pthread_self();
280       current = -1;
281       max = 0;
282       max_priority = 0;
283    }
284
285    void _dump(FILE *fp) {
286       fprintf(fp, "threadid=%p max=%i current=%i\n", 
287               (void *)thread_id, max, current);
288       for(int i=0; i<=current; i++) {
289          fprintf(fp, "   lock=%p state=%s priority=%i %s:%i\n", 
290                  lock_list[i].lock, 
291                  (lock_list[i].state=='W')?"Wanted ":"Granted",
292                  lock_list[i].priority,
293                  lock_list[i].file, lock_list[i].line);
294       } 
295    }
296
297    void dump(FILE *fp) {
298       lmgr_p(&mutex);
299       {
300          _dump(fp);
301       }
302       lmgr_v(&mutex);
303    }
304
305    /*
306     * Call before a lock operation (mark mutex as WANTED)
307     */
308    virtual void pre_P(void *m, int priority, 
309                       const char *f="*unknown*", int l=0) 
310    {
311       int max_prio = max_priority;
312       ASSERT_p(current < LMGR_MAX_LOCK, f, l);
313       ASSERT_p(current >= -1, f, l);
314       lmgr_p(&mutex);
315       {
316          current++;
317          lock_list[current].lock = m;
318          lock_list[current].state = LMGR_LOCK_WANTED;
319          lock_list[current].file = f;
320          lock_list[current].line = l;
321          lock_list[current].priority = priority;
322          lock_list[current].max_priority = MAX(priority, max_priority);
323          max = MAX(current, max);
324          max_priority = MAX(priority, max_priority);
325       }
326       lmgr_v(&mutex);
327       ASSERT_p(!priority || priority >= max_prio, f, l);
328    }
329
330    /*
331     * Call after the lock operation (mark mutex as GRANTED)
332     */
333    virtual void post_P() {
334       ASSERT(current >= 0);
335       ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
336       lock_list[current].state = LMGR_LOCK_GRANTED;
337    }
338    
339    /* Using this function is some sort of bug */
340    void shift_list(int i) {
341       for(int j=i+1; j<=current; j++) {
342          lock_list[i] = lock_list[j];
343       }
344       if (current >= 0) {
345          lock_list[current].lock = NULL;
346          lock_list[current].state = LMGR_LOCK_EMPTY;
347       }
348       /* rebuild the priority list */
349       max_priority = 0;
350       for(int j=0; j< current; j++) {
351          max_priority = MAX(lock_list[j].priority, max_priority);
352          lock_list[j].max_priority = max_priority;
353       }
354    }
355
356    /*
357     * Remove the mutex from the list
358     */
359    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
360       ASSERT_p(current >= 0, f, l);
361       lmgr_p(&mutex);
362       {
363          if (lock_list[current].lock == m) {
364             lock_list[current].lock = NULL;
365             lock_list[current].state = LMGR_LOCK_EMPTY;
366             current--;
367          } else {
368             ASSERT(current > 0);
369             Pmsg3(0, "ERROR: wrong P/V order search lock=%p %s:%i\n", m, f, l);
370             Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
371                     current, lock_list[current].lock, lock_list[current].file, 
372                     lock_list[current].line);
373             for (int i=current-1; i >= 0; i--) { /* already seen current */
374                Pmsg4(000, "ERROR: wrong P/V order pos=%i lock=%p %s:%i\n",
375                      i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
376                if (lock_list[i].lock == m) {
377                   Pmsg3(000, "ERROR: FOUND P pos=%i %s:%i\n", i, f, l);
378                   shift_list(i);
379                   current--;
380                   break;
381                }
382             }
383          }
384          /* reset max_priority to the last one */
385          if (current >= 0) {
386             max_priority = lock_list[current].max_priority; 
387          } else {
388             max_priority = 0;
389          }
390       }
391       lmgr_v(&mutex);
392    }
393
394    virtual ~lmgr_thread_t() {destroy();}
395
396    void destroy() {
397       pthread_mutex_destroy(&mutex);
398    }
399 } ;
400
401 class lmgr_dummy_thread_t: public lmgr_thread_t
402 {
403    void do_V(void *m, const char *file, int l)  {}
404    void post_P()                                {}
405    void pre_P(void *m, int priority, const char *file, int l) {}
406 };
407
408 /*
409  * LMGR - Lock Manager
410  *
411  *
412  *
413  */
414
415 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT; 
416 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
417
418 static dlist *global_mgr = NULL;  /* used to store all lgmr_thread_t objects */
419 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
420 static pthread_t undertaker;
421 static bool use_undertaker=true;
422
423 #define lmgr_is_active() (global_mgr != NULL)
424
425 /*
426  * Add a new lmgr_thread_t object to the global list
427  */
428 void lmgr_register_thread(lmgr_thread_t *item)
429 {
430    lmgr_p(&lmgr_global_mutex);
431    {
432       global_mgr->prepend(item);
433    }
434    lmgr_v(&lmgr_global_mutex);
435 }
436
437 /*
438  * Call this function to cleanup specific lock thread data
439  */
440 void lmgr_unregister_thread(lmgr_thread_t *item)
441 {
442    if (!lmgr_is_active()) {
443       return;
444    }
445    lmgr_p(&lmgr_global_mutex);
446    {
447       global_mgr->remove(item);
448    }
449    lmgr_v(&lmgr_global_mutex);
450 }
451
452 /*
453  * Search for a deadlock when it's secure to walk across
454  * locks list. (after lmgr_detect_deadlock or a fatal signal)
455  */
456 bool lmgr_detect_deadlock_unlocked()
457 {
458    bool ret=false;
459    lmgr_node_t *node=NULL;
460    lmgr_lock_t *lock;
461    lmgr_thread_t *item;
462    dlist *g = New(dlist(node, &node->link));
463
464    /* First, get a list of all node */
465    foreach_dlist(item, global_mgr) {
466       for(int i=0; i<=item->current; i++) {
467          node = NULL;
468          lock = &item->lock_list[i];
469          /* Depending if the lock is granted or not, it's a child or a root
470           *  Granted:  Mutex  -> Thread
471           *  Wanted:   Thread -> Mutex
472           *
473           * Note: a Mutex can be locked only once, a thread can request only
474           * one mutex.
475           *
476           */
477          if (lock->state == LMGR_LOCK_GRANTED) {
478             node = New(lmgr_node_t((void*)lock->lock, (void*)item->thread_id));
479          } else if (lock->state == LMGR_LOCK_WANTED) {
480             node = New(lmgr_node_t((void*)item->thread_id, (void*)lock->lock));
481          }
482          if (node) {
483             g->append(node);
484          }
485       }
486    }      
487    
488    //foreach_dlist(node, g) {
489    //   printf("g n=%p c=%p\n", node->node, node->child);
490    //}
491
492    ret = contains_cycle(g);
493    if (ret) {
494       printf("Found a deadlock !!!!\n");
495    }
496    
497    delete g;
498    return ret;
499 }
500
501 /*
502  * Search for a deadlock in during the runtime
503  * It will lock all thread specific lock manager, nothing
504  * can be locked during this check.
505  */
506 bool lmgr_detect_deadlock()
507 {
508    bool ret=false;
509    if (!lmgr_is_active()) {
510       return ret;
511    } 
512
513    lmgr_p(&lmgr_global_mutex);
514    {
515       lmgr_thread_t *item;
516       foreach_dlist(item, global_mgr) {
517          lmgr_p(&item->mutex);
518       }
519
520       ret = lmgr_detect_deadlock_unlocked();
521
522       foreach_dlist(item, global_mgr) {
523          lmgr_v(&item->mutex);
524       }
525    }
526    lmgr_v(&lmgr_global_mutex);
527
528    return ret;
529 }
530
531 /*
532  * !!! WARNING !!! 
533  * Use this function is used only after a fatal signal
534  * We don't use locking to display the information
535  */
536 void dbg_print_lock(FILE *fp)
537 {
538    fprintf(fp, "Attempt to dump locks\n");
539    if (!lmgr_is_active()) {
540       return ;
541    }
542    lmgr_thread_t *item;
543    foreach_dlist(item, global_mgr) {
544       item->_dump(fp);
545    }
546 }
547
548 /*
549  * Dump each lmgr_thread_t object
550  */
551 void lmgr_dump()
552 {
553    lmgr_p(&lmgr_global_mutex);
554    {
555       lmgr_thread_t *item;
556       foreach_dlist(item, global_mgr) {
557          item->dump(stderr);
558       }
559    }
560    lmgr_v(&lmgr_global_mutex);
561 }
562
563 void cln_hdl(void *a)
564 {
565    lmgr_cleanup_thread();
566 }
567
568 void *check_deadlock(void *)
569 {
570    int old;
571    lmgr_init_thread();
572    pthread_cleanup_push(cln_hdl, NULL);
573
574    while (!bmicrosleep(30, 0)) {
575       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
576       if (lmgr_detect_deadlock()) {
577          lmgr_dump();
578          ASSERT(0);
579       }
580       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
581       pthread_testcancel();
582    }
583    Dmsg0(100, "Exit check_deadlock.\n");
584    pthread_cleanup_pop(1);
585    return NULL;
586 }
587
588 /* This object is used when LMGR is not initialized */
589 static lmgr_dummy_thread_t dummy_lmgr;
590
591 /*
592  * Retrieve the lmgr_thread_t object from the stack
593  */
594 inline lmgr_thread_t *lmgr_get_thread_info()
595 {
596    if (lmgr_is_active()) {
597       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
598    } else {
599       return &dummy_lmgr;
600    }
601 }
602
603 /*
604  * launch once for all threads
605  */
606 void create_lmgr_key()
607 {
608    int status = pthread_key_create(&lmgr_key, NULL);
609    if (status != 0) {
610       berrno be;
611       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
612             be.bstrerror(status));
613       ASSERT(0);
614    }
615
616    lmgr_thread_t *n=NULL;
617    global_mgr = New(dlist(n, &n->link));
618
619    if (use_undertaker) {
620       status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
621       if (status != 0) {
622          berrno be;
623          Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
624                be.bstrerror(status));
625          ASSERT(0);
626       }
627    }
628 }
629
630 /*
631  * Each thread have to call this function to put a lmgr_thread_t object
632  * in the stack and be able to call mutex_lock/unlock
633  */
634 void lmgr_init_thread()
635 {
636    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
637    if (status != 0) {
638       berrno be;
639       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
640             be.bstrerror(status));
641       ASSERT(0);
642    }
643    lmgr_thread_t *l = New(lmgr_thread_t());
644    pthread_setspecific(lmgr_key, l);
645    lmgr_register_thread(l);
646 }
647
648 /*
649  * Call this function at the end of the thread
650  */
651 void lmgr_cleanup_thread()
652 {
653    if (!lmgr_is_active()) {
654       return ;
655    }
656    lmgr_thread_t *self = lmgr_get_thread_info();
657    lmgr_unregister_thread(self);
658    delete(self);
659 }
660
661 /*
662  * This function should be call at the end of the main thread
663  * Some thread like the watchdog are already present, so the global_mgr
664  * list is never empty. Should carefully clear the memory.
665  */
666 void lmgr_cleanup_main()
667 {
668    dlist *temp;
669    
670    if (!global_mgr) {
671       return;
672    }
673    if (use_undertaker) {
674       pthread_cancel(undertaker);
675    }
676    lmgr_cleanup_thread();
677    lmgr_p(&lmgr_global_mutex);
678    {
679       temp = global_mgr;
680       global_mgr = NULL;
681       delete temp;
682    }
683    lmgr_v(&lmgr_global_mutex);
684 }
685
686 /* 
687  * Set the priority of the lmgr mutex object
688  */
689 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
690 {
691 #ifdef USE_LOCKMGR_PRIORITY
692    m->priority = prio;
693 #endif
694 }
695
696 /*
697  * Replacement for pthread_mutex_init()
698  */
699 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
700 {
701    m->priority = 0;
702    return pthread_mutex_init(&m->mutex, attr);
703 }
704
705 /*
706  * Replacement for pthread_mutex_destroy()
707  */
708 int pthread_mutex_destroy(bthread_mutex_t *m)
709 {
710    return pthread_mutex_destroy(&m->mutex);
711 }
712
713 /* 
714  * Replacement for pthread_kill (only with USE_LOCKMGR_SAFEKILL)
715  */
716 int bthread_kill(pthread_t thread, int sig, 
717                  const char *file, int line)
718 {
719    bool thread_found_in_process=false;
720    
721    /* We doesn't allow to send signal to ourself */
722    ASSERT(!pthread_equal(thread, pthread_self()));
723
724    /* This loop isn't very efficient with dozens of threads but we don't use
725     * signal very much, and this feature is for testing only
726     */
727    lmgr_p(&lmgr_global_mutex);
728    {
729       lmgr_thread_t *item;
730       foreach_dlist(item, global_mgr) {
731          if (pthread_equal(thread, item->thread_id)) {
732             thread_found_in_process=true;
733             break;
734          }
735       }
736    }
737    lmgr_v(&lmgr_global_mutex);
738
739    /* Sending a signal to non existing thread can create problem
740     * so, we can stop here.
741     */
742    ASSERT(thread_found_in_process == true);
743
744    Dmsg3(100, "%s:%d send kill to existing thread %p\n", file, line, thread);
745    return pthread_kill(thread, sig);
746 }
747
748 /*
749  * Replacement for pthread_mutex_lock()
750  * Returns always ok 
751  */
752 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
753 {
754    lmgr_thread_t *self = lmgr_get_thread_info();
755    self->pre_P(m, m->priority, file, line);
756    lmgr_p(&m->mutex);
757    self->post_P();   
758    return 0;
759 }
760
761 /*
762  * Replacement for pthread_mutex_unlock()
763  * Returns always ok
764  */
765 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
766 {
767    lmgr_thread_t *self = lmgr_get_thread_info();
768    self->do_V(m, file, line);
769    lmgr_v(&m->mutex);
770    return 0;
771 }
772
773 /*
774  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
775  * Returns always ok 
776  */
777 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
778 {
779    lmgr_thread_t *self = lmgr_get_thread_info();
780    self->pre_P(m, 0, file, line);
781    lmgr_p(m);
782    self->post_P();   
783    return 0;
784 }
785
786 /*
787  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
788  * Returns always ok
789  */
790 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
791 {
792    lmgr_thread_t *self = lmgr_get_thread_info();
793    self->do_V(m, file, line);
794    lmgr_v(m);
795    return 0;
796 }
797
798
799 /* TODO: check this
800  */
801 int bthread_cond_wait_p(pthread_cond_t *cond,
802                         pthread_mutex_t *m,
803                         const char *file, int line)
804 {
805    int ret;
806    lmgr_thread_t *self = lmgr_get_thread_info();
807    self->do_V(m, file, line);   
808    ret = pthread_cond_wait(cond, m);
809    self->pre_P(m, 0, file, line);
810    self->post_P();
811    return ret;
812 }
813
814 /* TODO: check this
815  */
816 int bthread_cond_timedwait_p(pthread_cond_t *cond,
817                              pthread_mutex_t *m,
818                              const struct timespec * abstime,
819                              const char *file, int line)
820 {
821    int ret;
822    lmgr_thread_t *self = lmgr_get_thread_info();
823    self->do_V(m, file, line);   
824    ret = pthread_cond_timedwait(cond, m, abstime);
825    self->pre_P(m, 0, file, line);
826    self->post_P();
827    return ret;
828 }
829
830 /* TODO: check this
831  */
832 int bthread_cond_wait_p(pthread_cond_t *cond,
833                         bthread_mutex_t *m,
834                         const char *file, int line)
835 {
836    int ret;
837    lmgr_thread_t *self = lmgr_get_thread_info();
838    self->do_V(m, file, line);   
839    ret = pthread_cond_wait(cond, &m->mutex);
840    self->pre_P(m, m->priority, file, line);
841    self->post_P();
842    return ret;
843 }
844
845 /* TODO: check this
846  */
847 int bthread_cond_timedwait_p(pthread_cond_t *cond,
848                              bthread_mutex_t *m,
849                              const struct timespec * abstime,
850                              const char *file, int line)
851 {
852    int ret;
853    lmgr_thread_t *self = lmgr_get_thread_info();
854    self->do_V(m, file, line);   
855    ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
856    self->pre_P(m, m->priority, file, line);
857    self->post_P();
858    return ret;
859 }
860
861 /*  Test if this mutex is locked by the current thread 
862  *  returns:
863  *     0 - unlocked
864  *     1 - locked by the current thread
865  *     2 - locked by an other thread
866  */
867 int lmgr_mutex_is_locked(void *m)
868 {
869    lmgr_thread_t *self = lmgr_get_thread_info();
870
871    for(int i=0; i <= self->current; i++) {
872       if (self->lock_list[i].lock == m) {
873          return 1;              /* locked by us */
874       }
875    }
876
877    return 0;                    /* not locked by us */
878 }
879
880 /*
881  * Use this function when the caller handle the mutex directly
882  *
883  * lmgr_pre_lock(m, 10);
884  * pthread_mutex_lock(m);
885  * lmgr_post_lock(m);
886  */
887 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
888 {
889    lmgr_thread_t *self = lmgr_get_thread_info();
890    self->pre_P(m, prio, file, line);
891 }
892
893 /*
894  * Use this function when the caller handle the mutex directly
895  */
896 void lmgr_post_lock()
897 {
898    lmgr_thread_t *self = lmgr_get_thread_info();
899    self->post_P();
900 }
901
902 /*
903  * Do directly pre_P and post_P (used by trylock)
904  */
905 void lmgr_do_lock(void *m, int prio, const char *file, int line)
906 {
907    lmgr_thread_t *self = lmgr_get_thread_info();
908    self->pre_P(m, prio, file, line);
909    self->post_P();
910 }
911
912 /*
913  * Use this function when the caller handle the mutex directly
914  */
915 void lmgr_do_unlock(void *m)
916 {
917    lmgr_thread_t *self = lmgr_get_thread_info();
918    self->do_V(m);
919 }
920
921 typedef struct {
922    void *(*start_routine)(void*);
923    void *arg;
924 } lmgr_thread_arg_t;
925
926 extern "C" 
927 void *lmgr_thread_launcher(void *x)
928 {
929    void *ret=NULL;
930    lmgr_init_thread();
931    pthread_cleanup_push(cln_hdl, NULL);
932
933    lmgr_thread_arg_t arg;
934    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
935    arg.start_routine = a->start_routine;
936    arg.arg = a->arg;
937    free(a);
938
939    ret = arg.start_routine(arg.arg);
940    pthread_cleanup_pop(1);
941    return ret;
942 }
943
944 int lmgr_thread_create(pthread_t *thread,
945                        const pthread_attr_t *attr,
946                        void *(*start_routine)(void*), void *arg)
947 {
948    /* lmgr should be active (lmgr_init_thread() call in main()) */
949    ASSERT(lmgr_is_active());
950    /* Will be freed by the child */
951    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
952    a->start_routine = start_routine;
953    a->arg = arg;
954    return pthread_create(thread, attr, lmgr_thread_launcher, a);
955 }
956
957 #else  /* _USE_LOCKMGR */
958
959 /*
960  * !!! WARNING !!! 
961  * Use this function is used only after a fatal signal
962  * We don't use locking to display information
963  */
964 void dbg_print_lock(FILE *fp)
965 {
966    Pmsg0(000, "lockmgr disabled\n");
967 }
968
969 #endif  /* _USE_LOCKMGR */
970
971 #ifdef _TEST_IT
972
973 #include "lockmgr.h"
974 #define BTHREAD_MUTEX_NO_PRIORITY      {PTHREAD_MUTEX_INITIALIZER, 0}
975 #define BTHREAD_MUTEX_PRIORITY(p)      {PTHREAD_MUTEX_INITIALIZER, p}
976 #undef P
977 #undef V
978 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
979 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
980 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
981
982 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
983 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
984 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
985 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
986 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
987 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
988 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
989 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
990 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
991 static const char *my_prog;
992
993 void *self_lock(void *temp)
994 {
995    P(mutex1);
996    P(mutex1);
997    V(mutex1);
998    
999    return NULL;
1000 }
1001
1002 void *nolock(void *temp)
1003 {
1004    P(mutex2);
1005    sleep(5);
1006    V(mutex2);
1007    return NULL;
1008 }
1009
1010 void *locker(void *temp)
1011 {
1012    bthread_mutex_t *m = (bthread_mutex_t*) temp;
1013    P(*m);
1014    V(*m);
1015    return NULL;
1016 }
1017
1018 void *rwlocker(void *temp)
1019 {
1020    brwlock_t *m = (brwlock_t*) temp;
1021    rwl_writelock(m);
1022    rwl_writelock(m);
1023
1024    rwl_writeunlock(m);
1025    rwl_writeunlock(m);
1026    return NULL;
1027 }
1028
1029 void *mix_rwl_mutex(void *temp)
1030 {
1031    brwlock_t *m = (brwlock_t*) temp;
1032    P(mutex1);
1033    rwl_writelock(m);
1034    rwl_writeunlock(m);
1035    V(mutex1);
1036    return NULL;
1037 }
1038
1039
1040 void *th2(void *temp)
1041 {
1042    P(mutex2);
1043    P(mutex1);
1044    
1045    lmgr_dump();
1046
1047    sleep(10);
1048
1049    V(mutex1);
1050    V(mutex2);
1051
1052    lmgr_dump();
1053    return NULL;
1054 }
1055 void *th1(void *temp)
1056 {
1057    P(mutex1);
1058    sleep(2);
1059    P(mutex2);
1060    
1061    lmgr_dump();
1062
1063    sleep(10);
1064
1065    V(mutex2);
1066    V(mutex1);
1067
1068    lmgr_dump();
1069    return NULL;
1070 }
1071
1072 void *thx(void *temp)
1073 {
1074    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1075    P(mutex1);
1076    bmicrosleep(0,s);
1077    P(mutex2);
1078    bmicrosleep(0,s);
1079
1080    V(mutex2);
1081    V(mutex1);
1082    return NULL;
1083 }
1084
1085 void *th3(void *a) {
1086    while (1) {
1087       fprintf(stderr, "undertaker sleep()\n");
1088       sleep(10);
1089       lmgr_dump();
1090       if (lmgr_detect_deadlock()) {
1091          lmgr_dump();
1092          exit(1);
1093       }
1094    }
1095    return NULL;
1096 }
1097
1098 void *th_prio(void *a) {
1099    char buf[512];
1100    bstrncpy(buf, my_prog, sizeof(buf));
1101    bstrncat(buf, " priority", sizeof(buf));
1102    int ret = system(buf);
1103    return (void*) ret;
1104 }
1105
1106 int err=0;
1107 int nb=0;
1108 void _ok(const char *file, int l, const char *op, int value, const char *label)
1109 {
1110    nb++;
1111    if (!value) {
1112       err++;
1113       printf("ERR %.30s %s:%i on %s\n", label, file, l, op);
1114    } else {
1115       printf("OK  %.30s\n", label);
1116    }
1117 }
1118
1119 #define ok(x, label) _ok(__FILE__, __LINE__, #x, (x), label)
1120
1121 void _nok(const char *file, int l, const char *op, int value, const char *label)
1122 {
1123    nb++;
1124    if (value) {
1125       err++;
1126       printf("ERR %.30s %s:%i on !%s\n", label, file, l, op);
1127    } else {
1128       printf("OK  %.30s\n", label);
1129    }
1130 }
1131
1132 #define nok(x, label) _nok(__FILE__, __LINE__, #x, (x), label)
1133
1134 int report()
1135 {
1136    printf("Result %i/%i OK\n", nb - err, nb);
1137    return err>0;
1138 }
1139
1140 /* 
1141  * TODO:
1142  *  - Must detect multiple lock
1143  *  - lock/unlock in wrong order
1144  *  - deadlock with 2 or 3 threads
1145  */
1146 int main(int argc, char **argv)
1147 {
1148    void *ret=NULL;
1149    lmgr_thread_t *self;
1150    pthread_t id1, id2, id3, tab[200];
1151    bthread_mutex_t bmutex1;
1152    pthread_mutex_t pmutex2;
1153    my_prog = argv[0];
1154
1155    use_undertaker = false;
1156    lmgr_init_thread();
1157    self = lmgr_get_thread_info();
1158
1159    if (argc == 2) {             /* do priority check */
1160       P(mutex_p2);                /* not permited */
1161       P(mutex_p1);
1162       V(mutex_p1);                /* never goes here */
1163       V(mutex_p2);
1164       return 0;
1165    }
1166
1167    pthread_mutex_init(&bmutex1, NULL);
1168    bthread_mutex_set_priority(&bmutex1, 10);
1169
1170    pthread_mutex_init(&pmutex2, NULL);
1171    P(bmutex1);
1172    ok(self->max_priority == 10, "Check self max_priority");
1173    P(pmutex2);
1174    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1175    V(pmutex2);
1176    V(bmutex1);
1177    ok(self->max_priority == 0, "Check self max_priority");
1178
1179    pthread_create(&id1, NULL, self_lock, NULL);
1180    sleep(2);
1181    ok(lmgr_detect_deadlock(), "Check self deadlock");
1182    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1183    pthread_join(id1, NULL);
1184
1185
1186    pthread_create(&id1, NULL, nolock, NULL);
1187    sleep(2);
1188    nok(lmgr_detect_deadlock(), "Check for nolock");
1189    pthread_join(id1, NULL);
1190
1191    P(mutex1);
1192    pthread_create(&id1, NULL, locker, &mutex1);
1193    pthread_create(&id2, NULL, locker, &mutex1);
1194    pthread_create(&id3, NULL, locker, &mutex1);
1195    sleep(2);
1196    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1197    V(mutex1);
1198    pthread_join(id1, NULL);
1199    pthread_join(id2, NULL);   
1200    pthread_join(id3, NULL);
1201
1202
1203    brwlock_t wr;
1204    rwl_init(&wr);
1205    rwl_writelock(&wr);
1206    rwl_writelock(&wr);
1207    pthread_create(&id1, NULL, rwlocker, &wr);
1208    pthread_create(&id2, NULL, rwlocker, &wr);
1209    pthread_create(&id3, NULL, rwlocker, &wr);
1210    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1211    rwl_writeunlock(&wr);
1212    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1213    rwl_writeunlock(&wr);
1214    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1215
1216    pthread_join(id1, NULL);
1217    pthread_join(id2, NULL);   
1218    pthread_join(id3, NULL);   
1219
1220    rwl_writelock(&wr);
1221    P(mutex1);
1222    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1223    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1224    V(mutex1);
1225    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1226    rwl_writeunlock(&wr);
1227    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1228    pthread_join(id1, NULL);
1229
1230    P(mutex5);
1231    P(mutex6);
1232    V(mutex5);
1233    V(mutex6);
1234
1235    nok(lmgr_detect_deadlock(), "Check for wrong order");
1236
1237    for(int j=0; j<200; j++) {
1238       pthread_create(&tab[j], NULL, thx, NULL);
1239    }
1240    for(int j=0; j<200; j++) {
1241       pthread_join(tab[j], NULL);
1242       if (j%3) { lmgr_detect_deadlock();}
1243    }
1244    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1245
1246    P(mutex4);
1247    P(mutex5);
1248    P(mutex6);
1249    ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked"); 
1250    V(mutex6);
1251    ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is locked"); 
1252    V(mutex5);
1253    V(mutex4);
1254
1255    pthread_create(&id1, NULL, th1, NULL);
1256    sleep(1);
1257    pthread_create(&id2, NULL, th2, NULL);
1258    sleep(1);
1259    ok(lmgr_detect_deadlock(), "Check for deadlock");
1260
1261    pthread_create(&id3, NULL, th_prio, NULL);
1262    pthread_join(id3, &ret);
1263    ok(ret != 0, "Check for priority segfault");
1264
1265    P(mutex_p1);
1266    ok(self->max_priority == 1, "Check max_priority 1/4");
1267    P(mutex_p2);
1268    ok(self->max_priority == 2, "Check max_priority 2/4");
1269    P(mutex_p3);
1270    ok(self->max_priority == 3, "Check max_priority 3/4");
1271    P(mutex6);
1272    ok(self->max_priority == 3, "Check max_priority 4/4");
1273    V(mutex6);
1274    ok(self->max_priority == 3, "Check max_priority 1/5");
1275    V(mutex_p3);
1276    ok(self->max_priority == 2, "Check max_priority 4/5");
1277    V(mutex_p2);
1278    ok(self->max_priority == 1, "Check max_priority 4/5");
1279    V(mutex_p1);
1280    ok(self->max_priority == 0, "Check max_priority 5/5");
1281
1282
1283    P(mutex_p1);
1284    P(mutex_p2);
1285    P(mutex_p3);
1286    P(mutex6);
1287    ok(self->max_priority == 3, "Check max_priority mixed");
1288    V(mutex_p2);
1289    ok(self->max_priority == 3, "Check max_priority mixed");
1290    V(mutex_p1);
1291    ok(self->max_priority == 3, "Check max_priority mixed");
1292    V(mutex_p3);
1293    ok(self->max_priority == 0, "Check max_priority mixed");
1294    V(mutex6);
1295    ok(self->max_priority == 0, "Check max_priority mixed");
1296
1297    P(mutex_p1);
1298    P(mutex_p2);
1299    V(mutex_p1);
1300    V(mutex_p2);
1301
1302 //   lmgr_dump();
1303 //
1304 //   pthread_create(&id3, NULL, th3, NULL);
1305 //
1306 //   pthread_join(id1, NULL);
1307 //   pthread_join(id2, NULL);
1308    lmgr_cleanup_main();
1309    sm_check(__FILE__, __LINE__, false);
1310    return report();
1311 }
1312
1313 #endif