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