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