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