1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 
20 /* Written by Eric Bollengier December 2008 */
21 
22 /*
23   How to use mutex with bad order usage detection
24  ------------------------------------------------
25 
26  Note: see file mutex_list.h for current mutexes with
27        defined priorities.
28 
29  Instead of using:
30     pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
31     P(mutex);
32     ..
33     V(mutex);
34 
35  use:
36     bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
37     P(mutex);
38     ...
39     V(mutex);
40 
41  Mutex that doesn't need this extra check can be declared as pthread_mutex_t.
42  You can use this object on pthread_mutex_lock/unlock/cond_wait/cond_timewait.
43 
44  With dynamic creation, you can use:
45     bthread_mutex_t mutex;
46     pthread_mutex_init(&mutex);
47     bthread_mutex_set_priority(&mutex, 10);
48     pthread_mutex_destroy(&mutex);
49 
50  */
51 
52 #define LOCKMGR_COMPLIANT
53 #include "bacula.h"
54 
55 #undef ASSERT
56 #define ASSERT(x) if (!(x)) { \
57    char *jcr = NULL; \
58    Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
59    jcr[0] = 0; }
60 
61 #define ASSERT_p(x,f,l) if (!(x)) {              \
62    char *jcr = NULL; \
63    Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
64    jcr[0] = 0; }
65 
66 #define ASSERT2_p(x,m,f,l) if (!(x)) {          \
67    char *jcr = NULL; \
68    set_assert_msg(f, l, m); \
69    Pmsg4(000, _("ASSERT failed at %s:%i: %s (%s)\n"), f, l, #x, m);        \
70    jcr[0] = 0; }
71 
72 /* for lockmgr unit tests we have to clean up developer flags and asserts which breaks our tests */
73 #ifdef TEST_PROGRAM
74 #ifdef DEVELOPER
75 #undef DEVELOPER
76 #endif
77 #ifdef ASSERTD
78 #undef ASSERTD
79 #define ASSERTD(x, y)
80 #endif
81 #endif
82 
83 /*
84   Inspired from
85   http://www.cs.berkeley.edu/~kamil/teaching/sp03/041403.pdf
86 
87   This lock manager will replace some pthread calls. It can be
88   enabled with USE_LOCKMGR
89 
90   Some part of the code can't use this manager, for example the
91   rwlock object or the smartalloc lib. To disable LMGR, just add
92   LOCKMGR_COMPLIANT before the inclusion of "bacula.h"
93 
94   cd build/src/lib
95   g++ -g -c lockmgr.c -I.. -I../lib -DUSE_LOCKMGR -DTEST_PROGRAM
96   g++ -o lockmgr lockmgr.o -lbac -L../lib/.libs -lssl -lpthread
97 
98 */
99 
100 #define DBGLEVEL_EVENT 50
101 
102 /*
103  * pthread_mutex_lock for memory allocator and other
104  * parts that are LOCKMGR_COMPLIANT
105  */
lmgr_p(pthread_mutex_t * m)106 void lmgr_p(pthread_mutex_t *m)
107 {
108    int errstat;
109    if ((errstat=pthread_mutex_lock(m))) {
110       berrno be;
111       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex lock failure. ERR=%s\n"),
112             be.bstrerror(errstat));
113    }
114 }
115 
lmgr_v(pthread_mutex_t * m)116 void lmgr_v(pthread_mutex_t *m)
117 {
118    int errstat;
119    if ((errstat=pthread_mutex_unlock(m))) {
120       berrno be;
121       e_msg(__FILE__, __LINE__, M_ABORT, 0, _("Mutex unlock failure. ERR=%s\n"),
122             be.bstrerror(errstat));
123    }
124 }
125 
126 #ifdef USE_LOCKMGR
127 
128 typedef enum
129 {
130    LMGR_WHITE,                  /* never seen */
131    LMGR_BLACK,                  /* no loop */
132    LMGR_GRAY                    /* already seen */
133 } lmgr_color_t;
134 
135 /*
136  * Node used by the Lock Manager
137  * If the lock is GRANTED, we have mutex -> proc, else it's a proc -> mutex
138  * relation.
139  *
140  * Note, each mutex can be GRANTED once, and each proc can have only one WANTED
141  * mutex.
142  */
143 class lmgr_node_t: public SMARTALLOC
144 {
145 public:
146    dlink link;
147    void *node;
148    void *child;
149    lmgr_color_t seen;
150 
lmgr_node_t()151    lmgr_node_t() {
152       child = node = NULL;
153       seen = LMGR_WHITE;
154    }
155 
lmgr_node_t(void * n,void * c)156    lmgr_node_t(void *n, void *c) {
157       init(n,c);
158    }
159 
init(void * n,void * c)160    void init(void *n, void *c) {
161       node = n;
162       child = c;
163       seen = LMGR_WHITE;
164    }
165 
mark_as_seen(lmgr_color_t c)166    void mark_as_seen(lmgr_color_t c) {
167       seen = c;
168    }
169 
~lmgr_node_t()170    ~lmgr_node_t() {printf("delete node\n");}
171 };
172 
173 typedef enum {
174    LMGR_LOCK_EMPTY   = 'E',      /* unused */
175    LMGR_LOCK_WANTED  = 'W',      /* before mutex_lock */
176    LMGR_LOCK_GRANTED = 'G'       /* after mutex_lock */
177 } lmgr_state_t;
178 
179 /*
180  * Object associated with each mutex per thread
181  */
182 class lmgr_lock_t: public SMARTALLOC
183 {
184 public:
185    dlink link;
186    void *lock;                  /* Link to the mutex (or any value) */
187    lmgr_state_t state;
188    int max_priority;
189    int priority;                /* Current node priority */
190 
191    const char *file;
192    int line;
193 
lmgr_lock_t()194    lmgr_lock_t() {
195       lock = NULL;
196       state = LMGR_LOCK_EMPTY;
197       priority = max_priority = 0;
198    }
199 
lmgr_lock_t(void * l)200    lmgr_lock_t(void *l) {
201       lock = l;
202       state = LMGR_LOCK_WANTED;
203    }
204 
set_granted()205    void set_granted() {
206       state = LMGR_LOCK_GRANTED;
207    }
208 
~lmgr_lock_t()209    ~lmgr_lock_t() {}
210 
211 };
212 
213 /*
214  * Get the child list, ret must be already allocated
215  */
search_all_node(dlist * g,lmgr_node_t * v,alist * ret)216 static void search_all_node(dlist *g, lmgr_node_t *v, alist *ret)
217 {
218    lmgr_node_t *n;
219    foreach_dlist(n, g) {
220       if (v->child == n->node) {
221          ret->append(n);
222       }
223    }
224 }
225 
visit(dlist * g,lmgr_node_t * v)226 static bool visit(dlist *g, lmgr_node_t *v)
227 {
228    bool ret=false;
229    lmgr_node_t *n;
230    v->mark_as_seen(LMGR_GRAY);
231 
232    alist *d = New(alist(5, false)); /* use alist because own=false */
233    search_all_node(g, v, d);
234 
235    //foreach_alist(n, d) {
236    //   printf("node n=%p c=%p s=%c\n", n->node, n->child, n->seen);
237    //}
238 
239    foreach_alist(n, d) {
240       if (n->seen == LMGR_GRAY) { /* already seen this node */
241          ret = true;
242          goto bail_out;
243       } else if (n->seen == LMGR_WHITE) {
244          if (visit(g, n)) {
245             ret = true;
246             goto bail_out;
247          }
248       }
249    }
250    v->mark_as_seen(LMGR_BLACK); /* no loop detected, node is clean */
251 bail_out:
252    delete d;
253    return ret;
254 }
255 
contains_cycle(dlist * g)256 static bool contains_cycle(dlist *g)
257 {
258    lmgr_node_t *n;
259    foreach_dlist(n, g) {
260       if (n->seen == LMGR_WHITE) {
261          if (visit(g, n)) {
262             return true;
263          }
264       }
265    }
266    return false;
267 }
268 
269 /****************************************************************/
270 
271 /* lmgr_thread_event struct, some call can add events, and they will
272  * be dumped during a lockdump
273  */
274 typedef struct
275 {
276    int32_t     id;              /* Id of the event */
277    int32_t     global_id;       /* Current global id */
278    int32_t     flags;           /* Flags for this event */
279 
280    int32_t     line;            /* from which line in filename */
281    const char *from;            /* From where in the code (filename) */
282 
283    char       *comment;         /* Comment */
284    intptr_t    user_data;       /* Optionnal user data (will print address) */
285 
286 }  lmgr_thread_event;
287 
288 static int32_t global_event_id=0;
289 
290 static int global_int_thread_id=0; /* Keep an integer for each thread */
291 
292 /* Keep this number of event per thread */
293 #ifdef TEST_PROGRAM
294 # define LMGR_THREAD_EVENT_MAX  15
295 #else
296 # define LMGR_THREAD_EVENT_MAX  1024
297 #endif
298 
299 #define lmgr_thread_event_get_pos(x)   ((x) % LMGR_THREAD_EVENT_MAX)
300 
301 class lmgr_thread_t: public SMARTALLOC
302 {
303 public:
304    dlink link;
305    pthread_mutex_t mutex;
306    pthread_t       thread_id;
307    intptr_t        int_thread_id;
308    lmgr_lock_t     lock_list[LMGR_MAX_LOCK];
309    int current;
310    int max;
311    int max_priority;
312 
313    lmgr_thread_event events[LMGR_THREAD_EVENT_MAX];
314    int event_id;
315 
lmgr_thread_t()316    lmgr_thread_t() {
317       int status;
318       if ((status = pthread_mutex_init(&mutex, NULL)) != 0) {
319          berrno be;
320          Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
321                  be.bstrerror(status));
322          ASSERT2(0, "pthread_mutex_init failed");
323       }
324       event_id = 0;
325       thread_id = pthread_self();
326       current = -1;
327       max = 0;
328       max_priority = 0;
329    }
330 
331    /* Add event to the event list of the thread */
add_event(const char * comment,intptr_t user_data,int32_t flags,const char * from,int32_t line)332    void add_event(const char *comment, intptr_t user_data, int32_t flags,
333                   const char *from, int32_t line)
334    {
335       char *p;
336       int32_t oldflags;
337       int   i = lmgr_thread_event_get_pos(event_id);
338 
339       oldflags = events[i].flags;
340       p = events[i].comment;
341       events[i].flags = LMGR_EVENT_INVALID;
342       events[i].comment = (char *)"*Freed*";
343 
344       /* Shared between thread, just an indication about timing */
345       events[i].global_id = global_event_id++;
346       events[i].id = event_id;
347       events[i].line = line;
348       events[i].from = from;
349 
350       /* It means we are looping over the ring, so we need
351        * to check if the memory need to be freed
352        */
353       if (event_id >= LMGR_THREAD_EVENT_MAX) {
354          if (oldflags & LMGR_EVENT_FREE) {
355             free(p);
356          }
357       }
358 
359       /* We need to copy the memory */
360       if (flags & LMGR_EVENT_DUP) {
361          events[i].comment = bstrdup(comment);
362          flags |= LMGR_EVENT_FREE; /* force the free */
363 
364       } else {
365          events[i].comment = (char *)comment;
366       }
367       events[i].user_data = user_data;
368       events[i].flags = flags;  /* mark it valid */
369       event_id++;
370    }
371 
free_event_list()372    void free_event_list() {
373       /* We first check how far we go in the event list */
374       int max = MIN(event_id, LMGR_THREAD_EVENT_MAX);
375       char *p;
376 
377       for (int i = 0; i < max ; i++) {
378          if (events[i].flags & LMGR_EVENT_FREE) {
379             p = events[i].comment;
380             events[i].flags = LMGR_EVENT_INVALID;
381             events[i].comment = (char *)"*Freed*";
382             free(p);
383          }
384       }
385    }
386 
print_event(lmgr_thread_event * ev,FILE * fp)387    void print_event(lmgr_thread_event *ev, FILE *fp) {
388       if (ev->flags & LMGR_EVENT_INVALID) {
389          return;
390       }
391       fprintf(fp, "    %010d id=%010d %s data=%p at %s:%d\n",
392               ev->global_id,
393               ev->id,
394               NPRT(ev->comment),
395               (void *)ev->user_data,
396               ev->from,
397               ev->line);
398    }
399 
_dump(FILE * fp)400    void _dump(FILE *fp) {
401 #ifdef HAVE_WIN32
402       fprintf(fp, "thread_id=%p int_threadid=%p max=%i current=%i\n",
403               (void *)(intptr_t)GetCurrentThreadId(), (void *)int_thread_id, max, current);
404 #else
405       fprintf(fp, "threadid=%p max=%i current=%i\n",
406               (void *)thread_id, max, current);
407 #endif
408       for(int i=0; i<=current; i++) {
409          fprintf(fp, "   lock=%p state=%s priority=%i %s:%i\n",
410                  lock_list[i].lock,
411                  (lock_list[i].state=='W')?"Wanted ":"Granted",
412                  lock_list[i].priority,
413                  lock_list[i].file, lock_list[i].line);
414       }
415 
416       if (debug_flags & DEBUG_PRINT_EVENT) {
417          /* Debug events */
418          fprintf(fp, "   events:\n");
419 
420          /* Display events between (event_id % LMGR_THREAD_EVENT_MAX) and LMGR_THREAD_EVENT_MAX */
421          if (event_id > LMGR_THREAD_EVENT_MAX) {
422             for (int i = event_id % LMGR_THREAD_EVENT_MAX ; i < LMGR_THREAD_EVENT_MAX ; i++)
423             {
424                print_event(&events[i], fp);
425             }
426          }
427 
428          /* Display events between 0 and event_id % LMGR_THREAD_EVENT_MAX*/
429          for (int i = 0 ;  i < (event_id % LMGR_THREAD_EVENT_MAX) ; i++)
430          {
431             print_event(&events[i], fp);
432          }
433       }
434    }
435 
dump(FILE * fp)436    void dump(FILE *fp) {
437       lmgr_p(&mutex);
438       {
439          _dump(fp);
440       }
441       lmgr_v(&mutex);
442    }
443 
444    /*
445     * Call before a lock operation (mark mutex as WANTED)
446     */
447    virtual void pre_P(void *m, int priority,
448                       const char *f="*unknown*", int l=0)
449    {
450       int max_prio = max_priority;
451 
452       if (chk_dbglvl(DBGLEVEL_EVENT) && debug_flags & DEBUG_MUTEX_EVENT) {
453          /* Keep track of this event */
454          add_event("P()", (intptr_t)m, 0, f, l);
455       }
456 
457       /* Fail if too many locks in use */
458       ASSERT2_p(current < LMGR_MAX_LOCK, "Too many locks in use", f, l);
459       /* Fail if the "current" value is out of bounds */
460       ASSERT2_p(current >= -1, "current lock value is out of bounds", f, l);
461       lmgr_p(&mutex);
462       {
463          current++;
464          lock_list[current].lock = m;
465          lock_list[current].state = LMGR_LOCK_WANTED;
466          lock_list[current].file = f;
467          lock_list[current].line = l;
468          lock_list[current].priority = priority;
469          lock_list[current].max_priority = MAX(priority, max_priority);
470          max = MAX(current, max);
471          max_priority = MAX(priority, max_priority);
472       }
473       lmgr_v(&mutex);
474 
475       /* Fail if we tried to lock a mutex with a lower priority than
476        * the current value. It means that you need to lock mutex in a
477        * different order to ensure that the priority field is always
478        * increasing. The mutex priority list is defined in mutex_list.h.
479        *
480        * Look the *.lockdump generated to get the list of all mutexes,
481        * and where they were granted to find the priority problem.
482        */
483       ASSERT2_p(!priority || priority >= max_prio,
484                 "Mutex priority problem found, locking done in wrong order",
485                 f, l);
486    }
487 
488    /*
489     * Call after the lock operation (mark mutex as GRANTED)
490     */
post_P()491    virtual void post_P() {
492       ASSERT2(current >= 0, "Lock stack when negative");
493       ASSERT(lock_list[current].state == LMGR_LOCK_WANTED);
494       lock_list[current].state = LMGR_LOCK_GRANTED;
495    }
496 
497    /* Using this function is some sort of bug */
shift_list(int i)498    void shift_list(int i) {
499       for(int j=i+1; j<=current; j++) {
500          lock_list[i] = lock_list[j];
501       }
502       if (current >= 0) {
503          lock_list[current].lock = NULL;
504          lock_list[current].state = LMGR_LOCK_EMPTY;
505       }
506       /* rebuild the priority list */
507       max_priority = 0;
508       for(int j=0; j< current; j++) {
509          max_priority = MAX(lock_list[j].priority, max_priority);
510          lock_list[j].max_priority = max_priority;
511       }
512    }
513 
514    /*
515     * Remove the mutex from the list
516     */
517    virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
518       int old_current = current;
519 
520       /* Keep track of this event */
521       if (chk_dbglvl(DBGLEVEL_EVENT) && debug_flags & DEBUG_MUTEX_EVENT) {
522          add_event("V()", (intptr_t)m, 0, f, l);
523       }
524 
525       ASSERT2_p(current >= 0, "No previous P found, the mutex list is empty", f, l);
526       lmgr_p(&mutex);
527       {
528          if (lock_list[current].lock == m) {
529             lock_list[current].lock = NULL;
530             lock_list[current].state = LMGR_LOCK_EMPTY;
531             current--;
532          } else {
533             Pmsg3(0, "ERROR: V out of order lock=%p %s:%i dumping locks...\n", m, f, l);
534             Pmsg4(000, "  wrong P/V order pos=%i lock=%p %s:%i\n",
535                     current, lock_list[current].lock, lock_list[current].file,
536                     lock_list[current].line);
537             for (int i=current-1; i >= 0; i--) { /* already seen current */
538                Pmsg4(000, "  wrong P/V order pos=%i lock=%p %s:%i\n",
539                      i, lock_list[i].lock, lock_list[i].file, lock_list[i].line);
540                if (lock_list[i].lock == m) {
541                   Pmsg3(000, "ERROR: FOUND P for out of order V at pos=%i %s:%i\n", i, f, l);
542                   shift_list(i);
543                   current--;
544                   break;
545                }
546             }
547          }
548          /* reset max_priority to the last one */
549          if (current >= 0) {
550             max_priority = lock_list[current].max_priority;
551          } else {
552             max_priority = 0;
553          }
554       }
555       lmgr_v(&mutex);
556       /* ASSERT2 should be called outside from the mutex lock */
557       ASSERT2_p(current != old_current, "V() called without a previous P()", f, l);
558    }
559 
~lmgr_thread_t()560    virtual ~lmgr_thread_t() {destroy();}
561 
destroy()562    void destroy() {
563       free_event_list();
564       pthread_mutex_destroy(&mutex);
565    }
566 } ;
567 
568 class lmgr_dummy_thread_t: public lmgr_thread_t
569 {
do_V(void * m,const char * file,int l)570    void do_V(void *m, const char *file, int l)  {}
post_P()571    void post_P()                                {}
pre_P(void * m,int priority,const char * file,int l)572    void pre_P(void *m, int priority, const char *file, int l) {}
573 };
574 
575 /*
576  * LMGR - Lock Manager
577  *
578  *
579  *
580  */
581 
582 pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT;
583 static pthread_key_t lmgr_key;  /* used to get lgmr_thread_t object */
584 
585 static dlist *global_mgr = NULL;  /* used to store all lgmr_thread_t objects */
586 static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
587 static pthread_t undertaker;
588 static pthread_cond_t undertaker_cond;
589 static pthread_mutex_t undertaker_mutex = PTHREAD_MUTEX_INITIALIZER;
590 static bool use_undertaker = true;
591 static bool do_quit = false;
592 
593 
594 #define lmgr_is_active() (global_mgr != NULL)
595 
596 /*
597  * Add a new lmgr_thread_t object to the global list
598  */
lmgr_register_thread(lmgr_thread_t * item)599 void lmgr_register_thread(lmgr_thread_t *item)
600 {
601    lmgr_p(&lmgr_global_mutex);
602    {
603       item->int_thread_id = ++global_int_thread_id;
604       global_mgr->prepend(item);
605    }
606    lmgr_v(&lmgr_global_mutex);
607 }
608 
609 /*
610  * Call this function to cleanup specific lock thread data
611  */
lmgr_unregister_thread(lmgr_thread_t * item)612 void lmgr_unregister_thread(lmgr_thread_t *item)
613 {
614    if (!lmgr_is_active()) {
615       return;
616    }
617    lmgr_p(&lmgr_global_mutex);
618    {
619       global_mgr->remove(item);
620 #ifdef DEVELOPER
621       for(int i=0; i<=item->current; i++) {
622          lmgr_lock_t *lock = &item->lock_list[i];
623          if (lock->state == LMGR_LOCK_GRANTED) {
624             ASSERT2(0, "Thread is exiting holding locks!!!!");
625          }
626       }
627 #endif
628    }
629    lmgr_v(&lmgr_global_mutex);
630 }
631 
632 #ifdef HAVE_WIN32
633 # define TID int_thread_id
634 #else
635 # define TID thread_id
636 #endif
637 /*
638  * Search for a deadlock when it's secure to walk across
639  * locks list. (after lmgr_detect_deadlock or a fatal signal)
640  */
lmgr_detect_deadlock_unlocked()641 bool lmgr_detect_deadlock_unlocked()
642 {
643    bool ret=false;
644    lmgr_node_t *node=NULL;
645    lmgr_lock_t *lock;
646    lmgr_thread_t *item;
647    dlist *g = New(dlist(node, &node->link));
648 
649    /* First, get a list of all node */
650    foreach_dlist(item, global_mgr) {
651       for(int i=0; i<=item->current; i++) {
652          node = NULL;
653          lock = &item->lock_list[i];
654          /* Depending if the lock is granted or not, it's a child or a root
655           *  Granted:  Mutex  -> Thread
656           *  Wanted:   Thread -> Mutex
657           *
658           * Note: a Mutex can be locked only once, a thread can request only
659           * one mutex.
660           *
661           */
662          if (lock->state == LMGR_LOCK_GRANTED) {
663             node = New(lmgr_node_t((void*)lock->lock, (void*)item->TID));
664          } else if (lock->state == LMGR_LOCK_WANTED) {
665             node = New(lmgr_node_t((void*)item->TID, (void*)lock->lock));
666          }
667          if (node) {
668             g->append(node);
669          }
670       }
671    }
672 
673    //foreach_dlist(node, g) {
674    //   printf("g n=%p c=%p\n", node->node, node->child);
675    //}
676 
677    ret = contains_cycle(g);
678    if (ret) {
679       printf("Found a deadlock !!!!\n");
680    }
681 
682    delete g;
683    return ret;
684 }
685 
686 /*
687  * Search for a deadlock in during the runtime
688  * It will lock all thread specific lock manager, nothing
689  * can be locked during this check.
690  */
lmgr_detect_deadlock()691 bool lmgr_detect_deadlock()
692 {
693    bool ret=false;
694    if (!lmgr_is_active()) {
695       return ret;
696    }
697 
698    lmgr_p(&lmgr_global_mutex);
699    {
700       lmgr_thread_t *item;
701       foreach_dlist(item, global_mgr) {
702          lmgr_p(&item->mutex);
703       }
704 
705       ret = lmgr_detect_deadlock_unlocked();
706 
707       foreach_dlist(item, global_mgr) {
708          lmgr_v(&item->mutex);
709       }
710    }
711    lmgr_v(&lmgr_global_mutex);
712 
713    return ret;
714 }
715 
716 /*
717  * !!! WARNING !!!
718  * Use this function is used only after a fatal signal
719  * We don't use locking to display the information
720  */
dbg_print_lock(FILE * fp)721 void dbg_print_lock(FILE *fp)
722 {
723    fprintf(fp, "Attempt to dump locks\n");
724    if (!lmgr_is_active()) {
725       return ;
726    }
727    lmgr_thread_t *item;
728    foreach_dlist(item, global_mgr) {
729       item->_dump(fp);
730    }
731 }
732 
733 /*
734  * Dump each lmgr_thread_t object
735  */
lmgr_dump()736 void lmgr_dump()
737 {
738    lmgr_p(&lmgr_global_mutex);
739    {
740       lmgr_thread_t *item;
741       foreach_dlist(item, global_mgr) {
742          item->dump(stderr);
743       }
744    }
745    lmgr_v(&lmgr_global_mutex);
746 }
747 
cln_hdl(void * a)748 void cln_hdl(void *a)
749 {
750    lmgr_cleanup_thread();
751 }
752 
check_deadlock(void *)753 void *check_deadlock(void *)
754 {
755    lmgr_init_thread();
756    pthread_cleanup_push(cln_hdl, NULL);
757 
758    while (!do_quit) {
759       struct timeval tv;
760       struct timezone tz;
761       struct timespec timeout;
762 
763       gettimeofday(&tv, &tz);
764       timeout.tv_nsec = 0;
765       timeout.tv_sec = tv.tv_sec + 30;
766 
767       pthread_mutex_lock(&undertaker_mutex);
768       pthread_cond_timedwait(&undertaker_cond, &undertaker_mutex, &timeout);
769       pthread_mutex_unlock(&undertaker_mutex);
770 
771       if(do_quit) {
772          goto bail_out;
773       }
774 
775       if (lmgr_detect_deadlock()) {
776          /* If we have information about P()/V(), display them */
777          if (debug_flags & DEBUG_MUTEX_EVENT && chk_dbglvl(DBGLEVEL_EVENT)) {
778             debug_flags |= DEBUG_PRINT_EVENT;
779          }
780          lmgr_dump();
781          ASSERT2(0, "Lock deadlock");   /* Abort if we found a deadlock */
782       }
783    }
784 
785 bail_out:
786    Dmsg0(100, "Exit check_deadlock.\n");
787    pthread_cleanup_pop(1);
788    return NULL;
789 }
790 
791 /* This object is used when LMGR is not initialized */
792 static lmgr_dummy_thread_t dummy_lmgr;
793 
794 /*
795  * Retrieve the lmgr_thread_t object from the stack
796  */
lmgr_get_thread_info()797 inline lmgr_thread_t *lmgr_get_thread_info()
798 {
799    if (lmgr_is_active()) {
800       return (lmgr_thread_t *)pthread_getspecific(lmgr_key);
801    } else {
802       return &dummy_lmgr;
803    }
804 }
805 
806 /*
807  * Know if the current thread is registred (used when we
808  * do not control thread creation)
809  */
lmgr_thread_is_initialized()810 bool lmgr_thread_is_initialized()
811 {
812    return pthread_getspecific(lmgr_key) != NULL;
813 }
814 
815 /* On windows, the thread id is a struct, and sometime (for debug or openssl),
816  * we need a int
817  */
bthread_get_thread_id()818 intptr_t bthread_get_thread_id()
819 {
820    lmgr_thread_t *self = lmgr_get_thread_info();
821    if (self) {
822       return self->int_thread_id;
823    } else {
824       return 0;
825    }
826 }
827 
828 /*
829  * launch once for all threads
830  */
create_lmgr_key()831 void create_lmgr_key()
832 {
833    int status = pthread_key_create(&lmgr_key, NULL);
834    if (status != 0) {
835       berrno be;
836       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
837             be.bstrerror(status));
838       ASSERT2(0, "pthread_key_create failed");
839    }
840 
841    lmgr_thread_t *n=NULL;
842    global_mgr = New(dlist(n, &n->link));
843 
844    if (use_undertaker) {
845       /* Create condwait */
846       status = pthread_cond_init(&undertaker_cond, NULL);
847       if (status != 0) {
848          berrno be;
849          Pmsg1(000, _("pthread_cond_init failed: ERR=%s\n"),
850                be.bstrerror(status));
851          ASSERT2(0, "pthread_cond_init failed");
852       }
853       status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
854       if (status != 0) {
855          berrno be;
856          Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
857                be.bstrerror(status));
858          ASSERT2(0, "pthread_create failed");
859       }
860    }
861 }
862 
863 /*
864  * Each thread have to call this function to put a lmgr_thread_t object
865  * in the stack and be able to call mutex_lock/unlock
866  */
lmgr_init_thread()867 void lmgr_init_thread()
868 {
869    int status = pthread_once(&key_lmgr_once, create_lmgr_key);
870    if (status != 0) {
871       berrno be;
872       Pmsg1(000, _("pthread key create failed: ERR=%s\n"),
873             be.bstrerror(status));
874       ASSERT2(0, "pthread_once failed");
875    }
876    lmgr_thread_t *l = New(lmgr_thread_t());
877    pthread_setspecific(lmgr_key, l);
878    lmgr_register_thread(l);
879 }
880 
881 /*
882  * Call this function at the end of the thread
883  */
lmgr_cleanup_thread()884 void lmgr_cleanup_thread()
885 {
886    if (!lmgr_is_active()) {
887       return ;
888    }
889    lmgr_thread_t *self = lmgr_get_thread_info();
890    lmgr_unregister_thread(self);
891    delete(self);
892 }
893 
894 /*
895  * This function should be call at the end of the main thread
896  * Some thread like the watchdog are already present, so the global_mgr
897  * list is never empty. Should carefully clear the memory.
898  */
lmgr_cleanup_main()899 void lmgr_cleanup_main()
900 {
901    dlist *temp;
902 
903    if (!global_mgr) {
904       return;
905    }
906    if (use_undertaker) {
907       /* Signal to the check_deadlock thread to stop itself */
908       pthread_mutex_lock(&undertaker_mutex);
909       do_quit = true;
910       pthread_cond_signal(&undertaker_cond);
911       pthread_mutex_unlock(&undertaker_mutex);
912       /* Should avoid memory leak reporting */
913       pthread_join(undertaker, NULL);
914       pthread_cond_destroy(&undertaker_cond);
915    }
916    lmgr_cleanup_thread();
917    lmgr_p(&lmgr_global_mutex);
918    {
919       temp = global_mgr;
920       global_mgr = NULL;
921       delete temp;
922    }
923    lmgr_v(&lmgr_global_mutex);
924 }
925 
lmgr_add_event_p(const char * comment,intptr_t user_data,int32_t flags,const char * file,int32_t line)926 void lmgr_add_event_p(const char *comment, intptr_t user_data, int32_t flags,
927                       const char *file, int32_t line)
928 {
929    lmgr_thread_t *self = lmgr_get_thread_info();
930    self->add_event(comment, user_data, flags, file, line);
931 }
932 
933 /*
934  * Set the priority of the lmgr mutex object
935  */
bthread_mutex_set_priority(bthread_mutex_t * m,int prio)936 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
937 {
938 #ifdef USE_LOCKMGR_PRIORITY
939    m->priority = prio;
940 #endif
941 }
942 
943 /*
944  * Replacement for pthread_mutex_init()
945  */
pthread_mutex_init(bthread_mutex_t * m,const pthread_mutexattr_t * attr)946 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
947 {
948    m->priority = 0;
949    return pthread_mutex_init(&m->mutex, attr);
950 }
951 
952 /*
953  * Replacement for pthread_mutex_destroy()
954  */
pthread_mutex_destroy(bthread_mutex_t * m)955 int pthread_mutex_destroy(bthread_mutex_t *m)
956 {
957    return pthread_mutex_destroy(&m->mutex);
958 }
959 
960 /*
961  * Replacement for pthread_kill (only with USE_LOCKMGR_SAFEKILL)
962  */
bthread_kill(pthread_t thread,int sig,const char * file,int line)963 int bthread_kill(pthread_t thread, int sig,
964                  const char *file, int line)
965 {
966    bool thread_found_in_process=false;
967    int ret=-1;
968    /* We dont allow to send signal to ourself */
969    if (pthread_equal(thread, pthread_self())) {
970       ASSERTD(!pthread_equal(thread, pthread_self()), "Wanted to pthread_kill ourself");
971       Dmsg3(10, "%s:%d send kill to self thread %p\n", file, line, thread);
972       errno = EINVAL;
973       return -1;
974    }
975 
976    /* This loop isn't very efficient with dozens of threads but we don't use
977     * signal very much
978     */
979    lmgr_p(&lmgr_global_mutex);
980    {
981       lmgr_thread_t *item;
982       foreach_dlist(item, global_mgr) {
983          if (pthread_equal(thread, item->thread_id)) {
984             ret = pthread_kill(thread, sig);
985             thread_found_in_process=true;
986             break;
987          }
988       }
989    }
990    lmgr_v(&lmgr_global_mutex);
991 
992    /* Sending a signal to non existing thread can create problem */
993    if (!thread_found_in_process) {
994       ASSERTD(thread_found_in_process, "Wanted to pthread_kill non-existant thread");
995       Dmsg3(10, "%s:%d send kill to non-existant thread %p\n", file, line, thread);
996       errno=ECHILD;
997    }
998    return ret;
999 }
1000 
1001 /*
1002  * Replacement for pthread_mutex_lock()
1003  * Returns always ok
1004  */
bthread_mutex_lock_p(bthread_mutex_t * m,const char * file,int line)1005 int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
1006 {
1007    lmgr_thread_t *self = lmgr_get_thread_info();
1008    self->pre_P(m, m->priority, file, line);
1009    lmgr_p(&m->mutex);
1010    self->post_P();
1011    return 0;
1012 }
1013 
1014 /*
1015  * Replacement for pthread_mutex_unlock()
1016  * Returns always ok
1017  */
bthread_mutex_unlock_p(bthread_mutex_t * m,const char * file,int line)1018 int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
1019 {
1020    lmgr_thread_t *self = lmgr_get_thread_info();
1021    self->do_V(m, file, line);
1022    lmgr_v(&m->mutex);
1023    return 0;
1024 }
1025 
1026 /*
1027  * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
1028  * Returns always ok
1029  */
bthread_mutex_lock_p(pthread_mutex_t * m,const char * file,int line)1030 int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
1031 {
1032    lmgr_thread_t *self = lmgr_get_thread_info();
1033    self->pre_P(m, 0, file, line);
1034    lmgr_p(m);
1035    self->post_P();
1036    return 0;
1037 }
1038 
1039 /*
1040  * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
1041  * Returns always ok
1042  */
bthread_mutex_unlock_p(pthread_mutex_t * m,const char * file,int line)1043 int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
1044 {
1045    lmgr_thread_t *self = lmgr_get_thread_info();
1046    self->do_V(m, file, line);
1047    lmgr_v(m);
1048    return 0;
1049 }
1050 
1051 
1052 /* TODO: check this
1053  */
bthread_cond_wait_p(pthread_cond_t * cond,pthread_mutex_t * m,const char * file,int line)1054 int bthread_cond_wait_p(pthread_cond_t *cond,
1055                         pthread_mutex_t *m,
1056                         const char *file, int line)
1057 {
1058    int ret;
1059    lmgr_thread_t *self = lmgr_get_thread_info();
1060    self->do_V(m, file, line);
1061    ret = pthread_cond_wait(cond, m);
1062    self->pre_P(m, 0, file, line);
1063    self->post_P();
1064    return ret;
1065 }
1066 
1067 /* TODO: check this
1068  */
bthread_cond_timedwait_p(pthread_cond_t * cond,pthread_mutex_t * m,const struct timespec * abstime,const char * file,int line)1069 int bthread_cond_timedwait_p(pthread_cond_t *cond,
1070                              pthread_mutex_t *m,
1071                              const struct timespec * abstime,
1072                              const char *file, int line)
1073 {
1074    int ret;
1075    lmgr_thread_t *self = lmgr_get_thread_info();
1076    self->do_V(m, file, line);
1077    ret = pthread_cond_timedwait(cond, m, abstime);
1078    self->pre_P(m, 0, file, line);
1079    self->post_P();
1080    return ret;
1081 }
1082 
1083 /* TODO: check this
1084  */
bthread_cond_wait_p(pthread_cond_t * cond,bthread_mutex_t * m,const char * file,int line)1085 int bthread_cond_wait_p(pthread_cond_t *cond,
1086                         bthread_mutex_t *m,
1087                         const char *file, int line)
1088 {
1089    int ret;
1090    lmgr_thread_t *self = lmgr_get_thread_info();
1091    self->do_V(m, file, line);
1092    ret = pthread_cond_wait(cond, &m->mutex);
1093    self->pre_P(m, m->priority, file, line);
1094    self->post_P();
1095    return ret;
1096 }
1097 
1098 /* TODO: check this
1099  */
bthread_cond_timedwait_p(pthread_cond_t * cond,bthread_mutex_t * m,const struct timespec * abstime,const char * file,int line)1100 int bthread_cond_timedwait_p(pthread_cond_t *cond,
1101                              bthread_mutex_t *m,
1102                              const struct timespec * abstime,
1103                              const char *file, int line)
1104 {
1105    int ret;
1106    lmgr_thread_t *self = lmgr_get_thread_info();
1107    self->do_V(m, file, line);
1108    ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
1109    self->pre_P(m, m->priority, file, line);
1110    self->post_P();
1111    return ret;
1112 }
1113 
1114 /*  Test if this mutex is locked by the current thread
1115  *  returns:
1116  *     0 - unlocked
1117  *     1 - locked by the current thread
1118  *     2 - locked by an other thread
1119  */
lmgr_mutex_is_locked(void * m)1120 int lmgr_mutex_is_locked(void *m)
1121 {
1122    lmgr_thread_t *self = lmgr_get_thread_info();
1123 
1124    for(int i=0; i <= self->current; i++) {
1125       if (self->lock_list[i].lock == m) {
1126          return 1;              /* locked by us */
1127       }
1128    }
1129 
1130    return 0;                    /* not locked by us */
1131 }
1132 
1133 /*
1134  * Use this function when the caller handle the mutex directly
1135  *
1136  * lmgr_pre_lock(m, 10);
1137  * pthread_mutex_lock(m);
1138  * lmgr_post_lock(m);
1139  */
lmgr_pre_lock(void * m,int prio,const char * file,int line)1140 void lmgr_pre_lock(void *m, int prio, const char *file, int line)
1141 {
1142    lmgr_thread_t *self = lmgr_get_thread_info();
1143    self->pre_P(m, prio, file, line);
1144 }
1145 
1146 /*
1147  * Use this function when the caller handle the mutex directly
1148  */
lmgr_post_lock()1149 void lmgr_post_lock()
1150 {
1151    lmgr_thread_t *self = lmgr_get_thread_info();
1152    self->post_P();
1153 }
1154 
1155 /*
1156  * Do directly pre_P and post_P (used by trylock)
1157  */
lmgr_do_lock(void * m,int prio,const char * file,int line)1158 void lmgr_do_lock(void *m, int prio, const char *file, int line)
1159 {
1160    lmgr_thread_t *self = lmgr_get_thread_info();
1161    self->pre_P(m, prio, file, line);
1162    self->post_P();
1163 }
1164 
1165 /*
1166  * Use this function when the caller handle the mutex directly
1167  */
lmgr_do_unlock(void * m)1168 void lmgr_do_unlock(void *m)
1169 {
1170    lmgr_thread_t *self = lmgr_get_thread_info();
1171    self->do_V(m);
1172 }
1173 
1174 typedef struct {
1175    void *(*start_routine)(void*);
1176    void *arg;
1177 } lmgr_thread_arg_t;
1178 
1179 extern "C"
lmgr_thread_launcher(void * x)1180 void *lmgr_thread_launcher(void *x)
1181 {
1182    void *ret=NULL;
1183    lmgr_init_thread();
1184    pthread_cleanup_push(cln_hdl, NULL);
1185 
1186    lmgr_thread_arg_t arg;
1187    lmgr_thread_arg_t *a = (lmgr_thread_arg_t *)x;
1188    arg.start_routine = a->start_routine;
1189    arg.arg = a->arg;
1190    free(a);
1191 
1192    ret = arg.start_routine(arg.arg);
1193    pthread_cleanup_pop(1);
1194    return ret;
1195 }
1196 
lmgr_thread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)1197 int lmgr_thread_create(pthread_t *thread,
1198                        const pthread_attr_t *attr,
1199                        void *(*start_routine)(void*), void *arg)
1200 {
1201    /* lmgr should be active (lmgr_init_thread() call in main()) */
1202    ASSERT2(lmgr_is_active(), "Lock manager not active");
1203    /* Will be freed by the child */
1204    lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
1205    a->start_routine = start_routine;
1206    a->arg = arg;
1207    return pthread_create(thread, attr, lmgr_thread_launcher, a);
1208 }
1209 
1210 #else  /* USE_LOCKMGR */
1211 
bthread_get_thread_id()1212 intptr_t bthread_get_thread_id()
1213 {
1214 # ifdef HAVE_WIN32
1215    return (intptr_t)GetCurrentThreadId();
1216 # else
1217    return (intptr_t)pthread_self();
1218 # endif
1219 }
1220 
1221 /*
1222  * !!! WARNING !!!
1223  * Use this function is used only after a fatal signal
1224  * We don't use locking to display information
1225  */
dbg_print_lock(FILE * fp)1226 void dbg_print_lock(FILE *fp)
1227 {
1228    Pmsg0(000, "lockmgr disabled\n");
1229 }
1230 
1231 #endif  /* USE_LOCKMGR */
1232 
1233 #ifdef HAVE_LINUX_OS
1234 #ifndef _GNU_SOURCE
1235 #define _GNU_SOURCE
1236 #endif
1237 #include <sys/syscall.h>
1238 #endif
1239 
1240 /*
1241  * Set the Thread Id of the current thread to limit I/O operations
1242  */
bthread_change_uid(uid_t uid,gid_t gid)1243 int bthread_change_uid(uid_t uid, gid_t gid)
1244 {
1245 #if defined(HAVE_WIN32) || defined(HAVE_WIN64)
1246    /* TODO: Check the cygwin code for the implementation of setuid() */
1247    errno = ENOSYS;
1248    return -1;
1249 
1250 #elif defined(HAVE_LINUX_OS)
1251    /* It can be also implemented with setfsuid() and setfsgid() */
1252    int ret=0;
1253    ret = syscall(SYS_setregid, getgid(), gid);
1254    if (ret == -1) {
1255       return -1;
1256    }
1257    return syscall(SYS_setreuid, getuid(), uid);
1258 
1259 #elif defined(HAVE_PTHREAD_SETUGID_NP)
1260    return pthread_setugid_np(uid, gid);
1261 
1262 #endif
1263    errno = ENOSYS;
1264    return -1;
1265 }
1266 
1267 #ifndef TEST_PROGRAM
1268 #define TEST_PROGRAM_A
1269 #endif
1270 
1271 #ifdef TEST_PROGRAM
1272 #include "bacula.h"
1273 #include "unittests.h"
1274 #include "lockmgr.h"
1275 
1276 /* TODO: Detect the need of this object in the Makefile */
1277 #if BEEF
1278 #include "bee_lib_uid.h"
1279 #endif
1280 
1281 #undef P
1282 #undef V
1283 #define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
1284 #define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
1285 #define pthread_create(a, b, c, d)    lmgr_thread_create(a,b,c,d)
1286 
1287 bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
1288 bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
1289 bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
1290 bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
1291 bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
1292 bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
1293 bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
1294 bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
1295 bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
1296 static const char *my_prog;
1297 static bool thevent1ok = false;
1298 static bool thevent2ok = false;
1299 
self_lock(void * temp)1300 void *self_lock(void *temp)
1301 {
1302    P(mutex1);
1303    P(mutex1);
1304    V(mutex1);
1305 
1306    return NULL;
1307 }
1308 
nolock(void * temp)1309 void *nolock(void *temp)
1310 {
1311    P(mutex2);
1312    sleep(5);
1313    V(mutex2);
1314    return NULL;
1315 }
1316 
locker(void * temp)1317 void *locker(void *temp)
1318 {
1319    bthread_mutex_t *m = (bthread_mutex_t*) temp;
1320    P(*m);
1321    V(*m);
1322    return NULL;
1323 }
1324 
rwlocker(void * temp)1325 void *rwlocker(void *temp)
1326 {
1327    brwlock_t *m = (brwlock_t*) temp;
1328    rwl_writelock(m);
1329    rwl_writelock(m);
1330 
1331    rwl_writeunlock(m);
1332    rwl_writeunlock(m);
1333    return NULL;
1334 }
1335 
mix_rwl_mutex(void * temp)1336 void *mix_rwl_mutex(void *temp)
1337 {
1338    brwlock_t *m = (brwlock_t*) temp;
1339    P(mutex1);
1340    rwl_writelock(m);
1341    rwl_writeunlock(m);
1342    V(mutex1);
1343    return NULL;
1344 }
1345 
thuid(void * temp)1346 void *thuid(void *temp)
1347 {
1348 //   char buf[512];
1349 //   if (restrict_job_permissions("eric", "users", buf, sizeof(buf)) < 0) {
1350    if (bthread_change_uid(2, 100) == -1) {
1351       berrno be;
1352       fprintf(stderr, "Unable to change the uid err=%s\n", be.bstrerror());
1353    } else {
1354       fprintf(stderr, "UID set! %d:%d\n", (int)getuid(), (int)getgid());
1355       mkdir("/tmp/adirectory", 0755);
1356       system("touch /tmp/afile");
1357       system("id");
1358       fclose(fopen("/tmp/aaa", "a"));
1359    }
1360    if (bthread_change_uid(0, 0) == -1) {
1361       berrno be;
1362       fprintf(stderr, "Unable to change the uid err=%s\n", be.bstrerror());
1363    } else {
1364       fprintf(stderr, "UID set! %d:%d\n", (int)getuid(), (int)getgid());
1365       sleep(5);
1366       mkdir("/tmp/adirectory2", 0755);
1367       system("touch /tmp/afile2");
1368       system("id");
1369       fclose(fopen("/tmp/aaa2", "a"));
1370    }
1371 
1372    return NULL;
1373 }
1374 
th2(void * temp)1375 void *th2(void *temp)
1376 {
1377    P(mutex2);
1378    P(mutex1);
1379 
1380    lmgr_dump();
1381 
1382    sleep(10);
1383 
1384    V(mutex1);
1385    V(mutex2);
1386 
1387    lmgr_dump();
1388    return NULL;
1389 }
th1(void * temp)1390 void *th1(void *temp)
1391 {
1392    P(mutex1);
1393    sleep(2);
1394    P(mutex2);
1395 
1396    lmgr_dump();
1397 
1398    sleep(10);
1399 
1400    V(mutex2);
1401    V(mutex1);
1402 
1403    lmgr_dump();
1404    return NULL;
1405 }
1406 
thx(void * temp)1407 void *thx(void *temp)
1408 {
1409    int s= 1 + (int) (500.0 * (rand() / (RAND_MAX + 1.0))) + 200;
1410    P(mutex1);
1411    bmicrosleep(0,s);
1412    P(mutex2);
1413    bmicrosleep(0,s);
1414 
1415    V(mutex2);
1416    V(mutex1);
1417    return NULL;
1418 }
1419 
th3(void * a)1420 void *th3(void *a) {
1421    while (1) {
1422       fprintf(stderr, "undertaker sleep()\n");
1423       sleep(10);
1424       lmgr_dump();
1425       if (lmgr_detect_deadlock()) {
1426          lmgr_dump();
1427          exit(1);
1428       }
1429    }
1430    return NULL;
1431 }
1432 
th_prio(void * a)1433 void *th_prio(void *a) {
1434    char buf[512];
1435    bstrncpy(buf, my_prog, sizeof(buf));
1436    bstrncat(buf, " priority", sizeof(buf));
1437    intptr_t ret = system(buf);
1438    return (void*) ret;
1439 }
1440 
th_event1(void * a)1441 void *th_event1(void *a) {
1442    lmgr_thread_t *self = lmgr_get_thread_info();
1443    for (int i=0; i < 10000; i++) {
1444       if ((i % 7) == 0) {
1445          lmgr_add_event_flag("strdup test", i, LMGR_EVENT_DUP);
1446       } else {
1447          lmgr_add_event("My comment", i);
1448       }
1449    }
1450    thevent1ok = self->event_id == 10000;
1451    sleep(5);
1452    return NULL;
1453 }
1454 
th_event2(void * a)1455 void *th_event2(void *a) {
1456    lmgr_thread_t *self = lmgr_get_thread_info();
1457    for (int i=0; i < 10000; i++) {
1458       if ((i % 2) == 0) {
1459          lmgr_add_event_flag(bstrdup("free test"), i, LMGR_EVENT_FREE);
1460       } else {
1461          lmgr_add_event("My comment", i);
1462       }
1463    }
1464    thevent2ok = self->event_id == 10000;
1465    sleep(5);
1466    return NULL;
1467 }
1468 
1469 /*
1470  * TODO:
1471  *  - Must detect multiple lock
1472  *  - lock/unlock in wrong order
1473  *  - deadlock with 2 or 3 threads
1474  */
main(int argc,char ** argv)1475 int main(int argc, char **argv)
1476 {
1477    Unittests lmgr_test("lockmgr_test", true, argc != 2);
1478    void *ret=NULL;
1479    lmgr_thread_t *self;
1480    pthread_t id1, id2, id3, id4, id5, tab[200];
1481    bthread_mutex_t bmutex1;
1482    pthread_mutex_t pmutex2;
1483 
1484    use_undertaker = false;
1485    my_prog = argv[0];
1486    self = lmgr_get_thread_info();
1487 
1488    /* below is used for checking forced SIGSEGV in separate process */
1489    if (argc == 2) {             /* do priority check */
1490       P(mutex_p2);                /* not permited */
1491       P(mutex_p1);
1492       V(mutex_p1);                /* never goes here */
1493       V(mutex_p2);
1494       return 0;
1495    }
1496 
1497    /* workaround for bthread_change_uid() failure for non-root */
1498    if (getuid() == 0){
1499       /* we can change uid/git, so proceed the test */
1500       pthread_create(&id5, NULL, thuid, NULL);
1501       pthread_join(id5, NULL);
1502       Pmsg2(0, "UID %d:%d\n", (int)getuid(), (int)getgid());
1503    } else {
1504       Pmsg0(0, "Skipped bthread_change_uid() for non-root\n");
1505    }
1506 
1507    Pmsg0(0, "Starting mutex priority test\n");
1508    pthread_mutex_init(&bmutex1, NULL);
1509    bthread_mutex_set_priority(&bmutex1, 10);
1510 
1511    pthread_mutex_init(&pmutex2, NULL);
1512    P(bmutex1);
1513    ok(self->max_priority == 10, "Check self max_priority");
1514    P(pmutex2);
1515    ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
1516    V(pmutex2);
1517    V(bmutex1);
1518    ok(self->max_priority == 0, "Check self max_priority");
1519 
1520    Pmsg0(0, "Starting self deadlock tests\n");
1521    pthread_create(&id1, NULL, self_lock, NULL);
1522    sleep(2);
1523    ok(lmgr_detect_deadlock(), "Check self deadlock");
1524    lmgr_v(&mutex1.mutex);                /* a bit dirty */
1525    pthread_join(id1, NULL);
1526 
1527    Pmsg0(0, "Starting thread kill tests\n");
1528    pthread_create(&id1, NULL, nolock, NULL);
1529    sleep(2);
1530    ok(bthread_kill(id1, SIGUSR2) == 0, "Kill existing thread");
1531    pthread_join(id1, NULL);
1532    ok(bthread_kill(id1, SIGUSR2) == -1, "Kill non-existing thread");
1533    ok(bthread_kill(pthread_self(), SIGUSR2) == -1, "Kill self");
1534 
1535    Pmsg0(0, "Starting thread locks tests\n");
1536    pthread_create(&id1, NULL, nolock, NULL);
1537    sleep(2);
1538    nok(lmgr_detect_deadlock(), "Check for nolock");
1539    pthread_join(id1, NULL);
1540 
1541    P(mutex1);
1542    pthread_create(&id1, NULL, locker, &mutex1);
1543    pthread_create(&id2, NULL, locker, &mutex1);
1544    pthread_create(&id3, NULL, locker, &mutex1);
1545    sleep(2);
1546    nok(lmgr_detect_deadlock(), "Check for multiple lock");
1547    V(mutex1);
1548    pthread_join(id1, NULL);
1549    pthread_join(id2, NULL);
1550    pthread_join(id3, NULL);
1551 
1552    brwlock_t wr;
1553    rwl_init(&wr);
1554    rwl_writelock(&wr);
1555    rwl_writelock(&wr);
1556    pthread_create(&id1, NULL, rwlocker, &wr);
1557    pthread_create(&id2, NULL, rwlocker, &wr);
1558    pthread_create(&id3, NULL, rwlocker, &wr);
1559    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1560    rwl_writeunlock(&wr);
1561    nok(lmgr_detect_deadlock(), "Check for simple rwlock");
1562    rwl_writeunlock(&wr);
1563    nok(lmgr_detect_deadlock(), "Check for multiple rwlock");
1564 
1565    pthread_join(id1, NULL);
1566    pthread_join(id2, NULL);
1567    pthread_join(id3, NULL);
1568 
1569    rwl_writelock(&wr);
1570    P(mutex1);
1571    pthread_create(&id1, NULL, mix_rwl_mutex, &wr);
1572    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1573    V(mutex1);
1574    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1575    rwl_writeunlock(&wr);
1576    nok(lmgr_detect_deadlock(), "Check for mix rwlock/mutex");
1577    pthread_join(id1, NULL);
1578 
1579    P(mutex5);
1580    P(mutex6);
1581    V(mutex5);
1582    V(mutex6);
1583 
1584    nok(lmgr_detect_deadlock(), "Check for wrong order");
1585 
1586    for(int j=0; j<200; j++) {
1587       pthread_create(&tab[j], NULL, thx, NULL);
1588    }
1589    for(int j=0; j<200; j++) {
1590       pthread_join(tab[j], NULL);
1591       if (j%3) { lmgr_detect_deadlock();}
1592    }
1593    nok(lmgr_detect_deadlock(), "Check 200 lockers");
1594 
1595    P(mutex4);
1596    P(mutex5);
1597    P(mutex6);
1598    ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked");
1599    V(mutex6);
1600    ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is unlocked");
1601    V(mutex5);
1602    V(mutex4);
1603 
1604    Pmsg0(0, "Starting threads deadlock tests\n");
1605    pthread_create(&id1, NULL, th1, NULL);
1606    sleep(1);
1607    pthread_create(&id2, NULL, th2, NULL);
1608    sleep(1);
1609    ok(lmgr_detect_deadlock(), "Check for deadlock");
1610 
1611    Pmsg0(0, "Starting for max_priority locks tests\n");
1612    pthread_create(&id3, NULL, th_prio, NULL);
1613    pthread_join(id3, &ret);
1614    ok(ret != 0, "Check for priority segfault");
1615 
1616    P(mutex_p1);
1617    ok(self->max_priority == 1, "Check max_priority 1/4");
1618    P(mutex_p2);
1619    ok(self->max_priority == 2, "Check max_priority 2/4");
1620    P(mutex_p3);
1621    ok(self->max_priority == 3, "Check max_priority 3/4");
1622    P(mutex6);
1623    ok(self->max_priority == 3, "Check max_priority 4/4");
1624    V(mutex6);
1625    ok(self->max_priority == 3, "Check max_priority 1/5");
1626    V(mutex_p3);
1627    ok(self->max_priority == 2, "Check max_priority 4/5");
1628    V(mutex_p2);
1629    ok(self->max_priority == 1, "Check max_priority 4/5");
1630    V(mutex_p1);
1631    ok(self->max_priority == 0, "Check max_priority 5/5");
1632 
1633 
1634    P(mutex_p1);
1635    P(mutex_p2);
1636    P(mutex_p3);
1637    P(mutex6);
1638    ok(self->max_priority == 3, "Check max_priority mixed");
1639    V(mutex_p2);
1640    ok(self->max_priority == 3, "Check max_priority mixed");
1641    V(mutex_p1);
1642    ok(self->max_priority == 3, "Check max_priority mixed");
1643    V(mutex_p3);
1644    ok(self->max_priority == 0, "Check max_priority mixed");
1645    V(mutex6);
1646    ok(self->max_priority == 0, "Check max_priority mixed");
1647 
1648    P(mutex_p1);
1649    P(mutex_p2);
1650    V(mutex_p1);
1651    V(mutex_p2);
1652 
1653    /* To fix at some point? */
1654    lmgr_pre_lock(&wr, wr.priority, __FILE__, __LINE__);
1655    rwl_writelock(&wr);
1656    ok(lmgr_detect_deadlock(), "Simulate a signal inside a rwlock");
1657    rwl_writeunlock(&wr);
1658    lmgr_post_lock();
1659 
1660 
1661    Pmsg0(0, "Start lmgr_add_even tests\n");
1662    for (int i=0; i < 10000; i++) {
1663       if ((i % 7) == 0) {
1664          lmgr_add_event_flag("xxxxxxxxxxxxxxxx strdup test xxxxxxxxxxxxxxxx", i, LMGR_EVENT_DUP);
1665       } else {
1666          lmgr_add_event("My comment", i);
1667       }
1668    }
1669    ok(self->event_id == 10000, "Checking registered events in self");
1670 
1671    pthread_create(&id4, NULL, th_event1, NULL);
1672    pthread_create(&id5, NULL, th_event2, NULL);
1673 
1674    sleep(2);
1675 
1676    pthread_join(id4, NULL);
1677    pthread_join(id5, NULL);
1678 
1679    ok(thevent1ok, "Checking registered events in thread1");
1680    ok(thevent2ok, "Checking registered events in thread2");
1681 
1682    return report();
1683 }
1684 #endif   /* TEST_PROGRAM */
1685