/*
Bacula® - The Network Backup Solution
- Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
+ Copyright (C) 2008-2011 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation, which is
listed in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ How to use mutex with bad order usage detection
+ ------------------------------------------------
+
+ Note: see file mutex_list.h for current mutexes with
+ defined priorities.
+
+ Instead of using:
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ P(mutex);
+ ..
+ V(mutex);
+
+ use:
+ bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
+ P(mutex);
+ ...
+ V(mutex);
+
+ Mutex that doesn't need this extra check can be declared as pthread_mutex_t.
+ You can use this object on pthread_mutex_lock/unlock/cond_wait/cond_timewait.
+
+ With dynamic creation, you can use:
+ bthread_mutex_t mutex;
+ pthread_mutex_init(&mutex);
+ bthread_mutex_set_priority(&mutex, 10);
+ pthread_mutex_destroy(&mutex);
+
+ */
+
#define _LOCKMGR_COMPLIANT
-#include "lockmgr.h"
+#include "bacula.h"
#undef ASSERT
#define ASSERT(x) if (!(x)) { \
char *jcr = NULL; \
- Pmsg3(000, _("%s:%i Failed ASSERT: %s\n"), __FILE__, __LINE__, #x); \
+ Pmsg3(000, _("ASSERT failed at %s:%i: %s\n"), __FILE__, __LINE__, #x); \
+ jcr[0] = 0; }
+
+#define ASSERT_p(x,f,l) if (!(x)) { \
+ char *jcr = NULL; \
+ Pmsg3(000, _("ASSERT failed at %s:%i: %s \n"), f, l, #x); \
jcr[0] = 0; }
/*
{
LMGR_WHITE, /* never seen */
LMGR_BLACK, /* no loop */
- LMGR_GREY, /* seen before */
+ LMGR_GREY /* seen before */
} lmgr_color_t;
/*
dlink link;
void *lock;
lmgr_state_t state;
-
+ int max_priority;
+ int priority;
+
const char *file;
int line;
lmgr_lock_t() {
lock = NULL;
state = LMGR_LOCK_EMPTY;
+ priority = max_priority = 0;
}
lmgr_lock_t(void *l) {
lmgr_lock_t lock_list[LMGR_MAX_LOCK];
int current;
int max;
+ int max_priority;
lmgr_thread_t() {
int status;
thread_id = pthread_self();
current = -1;
max = 0;
+ max_priority = 0;
}
void _dump(FILE *fp) {
- fprintf(fp, "threadid=0x%x max=%i current=%i\n", (int)thread_id, max, current);
+ fprintf(fp, "threadid=%p max=%i current=%i\n",
+ (void *)thread_id, max, current);
for(int i=0; i<=current; i++) {
- fprintf(fp, " lock=%p state=%c %s:%i\n",
- lock_list[i].lock, lock_list[i].state,
- lock_list[i].file, lock_list[i].line);
- }
+ fprintf(fp, " lock=%p state=%s priority=%i %s:%i\n",
+ lock_list[i].lock,
+ (lock_list[i].state=='W')?"Wanted ":"Granted",
+ lock_list[i].priority,
+ lock_list[i].file, lock_list[i].line);
+ }
}
void dump(FILE *fp) {
- pthread_mutex_lock(&mutex);
+ lmgr_p(&mutex);
{
_dump(fp);
}
- pthread_mutex_unlock(&mutex);
+ lmgr_v(&mutex);
}
/*
* Call before a lock operation (mark mutex as WANTED)
*/
- virtual void pre_P(void *m, const char *f="*unknown*", int l=0) {
- ASSERT(current < LMGR_MAX_LOCK);
- ASSERT(current >= -1);
- pthread_mutex_lock(&mutex);
+ virtual void pre_P(void *m, int priority,
+ const char *f="*unknown*", int l=0)
+ {
+ int max_prio = max_priority;
+ ASSERT_p(current < LMGR_MAX_LOCK, f, l);
+ ASSERT_p(current >= -1, f, l);
+ lmgr_p(&mutex);
{
current++;
lock_list[current].lock = m;
lock_list[current].state = LMGR_LOCK_WANTED;
lock_list[current].file = f;
lock_list[current].line = l;
+ lock_list[current].priority = priority;
+ lock_list[current].max_priority = MAX(priority, max_priority);
max = MAX(current, max);
+ max_priority = MAX(priority, max_priority);
}
- pthread_mutex_unlock(&mutex);
+ lmgr_v(&mutex);
+ ASSERT_p(!priority || priority >= max_prio, f, l);
}
/*
lock_list[current].state = LMGR_LOCK_GRANTED;
}
+ /* Using this function is some sort of bug */
void shift_list(int i) {
for(int j=i+1; j<=current; j++) {
lock_list[i] = lock_list[j];
lock_list[current].lock = NULL;
lock_list[current].state = LMGR_LOCK_EMPTY;
}
+ /* rebuild the priority list */
+ max_priority = 0;
+ for(int j=0; j< current; j++) {
+ max_priority = MAX(lock_list[j].priority, max_priority);
+ lock_list[j].max_priority = max_priority;
+ }
}
/*
* Remove the mutex from the list
*/
virtual void do_V(void *m, const char *f="*unknown*", int l=0) {
- ASSERT(current >= 0);
- pthread_mutex_lock(&mutex);
+ ASSERT_p(current >= 0, f, l);
+ lmgr_p(&mutex);
{
if (lock_list[current].lock == m) {
lock_list[current].lock = NULL;
}
}
}
+ /* reset max_priority to the last one */
+ if (current >= 0) {
+ max_priority = lock_list[current].max_priority;
+ } else {
+ max_priority = 0;
+ }
}
- pthread_mutex_unlock(&mutex);
+ lmgr_v(&mutex);
}
virtual ~lmgr_thread_t() {destroy();}
{
void do_V(void *m, const char *file, int l) {}
void post_P() {}
- void pre_P(void *m, const char *file, int l) {}
+ void pre_P(void *m, int priority, const char *file, int l) {}
};
/*
pthread_once_t key_lmgr_once = PTHREAD_ONCE_INIT;
static pthread_key_t lmgr_key; /* used to get lgmr_thread_t object */
-static dlist *global_mgr=NULL; /* used to store all lgmr_thread_t objects */
+static dlist *global_mgr = NULL; /* used to store all lgmr_thread_t objects */
static pthread_mutex_t lmgr_global_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t undertaker;
+static bool use_undertaker=true;
#define lmgr_is_active() (global_mgr != NULL)
*/
void lmgr_register_thread(lmgr_thread_t *item)
{
- pthread_mutex_lock(&lmgr_global_mutex);
+ lmgr_p(&lmgr_global_mutex);
{
global_mgr->prepend(item);
}
- pthread_mutex_unlock(&lmgr_global_mutex);
+ lmgr_v(&lmgr_global_mutex);
}
/*
if (!lmgr_is_active()) {
return;
}
- pthread_mutex_lock(&lmgr_global_mutex);
+ lmgr_p(&lmgr_global_mutex);
{
global_mgr->remove(item);
}
- pthread_mutex_unlock(&lmgr_global_mutex);
+ lmgr_v(&lmgr_global_mutex);
}
/*
return ret;
}
- pthread_mutex_lock(&lmgr_global_mutex);
+ lmgr_p(&lmgr_global_mutex);
{
lmgr_thread_t *item;
foreach_dlist(item, global_mgr) {
- pthread_mutex_lock(&item->mutex);
+ lmgr_p(&item->mutex);
}
ret = lmgr_detect_deadlock_unlocked();
foreach_dlist(item, global_mgr) {
- pthread_mutex_unlock(&item->mutex);
+ lmgr_v(&item->mutex);
}
}
- pthread_mutex_unlock(&lmgr_global_mutex);
+ lmgr_v(&lmgr_global_mutex);
return ret;
}
*/
void lmgr_dump()
{
- pthread_mutex_lock(&lmgr_global_mutex);
+ lmgr_p(&lmgr_global_mutex);
{
lmgr_thread_t *item;
foreach_dlist(item, global_mgr) {
item->dump(stderr);
}
}
- pthread_mutex_unlock(&lmgr_global_mutex);
+ lmgr_v(&lmgr_global_mutex);
}
void cln_hdl(void *a)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
pthread_testcancel();
}
- Pmsg0(000, "Undertaker is leaving...\n");
+ Dmsg0(100, "Exit check_deadlock.\n");
pthread_cleanup_pop(1);
return NULL;
}
/* This object is used when LMGR is not initialized */
-lmgr_dummy_thread_t dummy_lmgr;
+static lmgr_dummy_thread_t dummy_lmgr;
/*
* Retrieve the lmgr_thread_t object from the stack
lmgr_thread_t *n=NULL;
global_mgr = New(dlist(n, &n->link));
- if (pthread_create(&undertaker, NULL, check_deadlock, NULL) != 0) {
- berrno be;
- Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
- be.bstrerror(status));
- ASSERT(0);
+ if (use_undertaker) {
+ status = pthread_create(&undertaker, NULL, check_deadlock, NULL);
+ if (status != 0) {
+ berrno be;
+ Pmsg1(000, _("pthread_create failed: ERR=%s\n"),
+ be.bstrerror(status));
+ ASSERT(0);
+ }
}
}
if (!global_mgr) {
return;
}
- pthread_cancel(undertaker);
+ if (use_undertaker) {
+ pthread_cancel(undertaker);
+ }
lmgr_cleanup_thread();
- pthread_mutex_lock(&lmgr_global_mutex);
+ lmgr_p(&lmgr_global_mutex);
{
temp = global_mgr;
- global_mgr=NULL;
+ global_mgr = NULL;
delete temp;
}
- pthread_mutex_unlock(&lmgr_global_mutex);
+ lmgr_v(&lmgr_global_mutex);
+}
+
+/*
+ * Set the priority of the lmgr mutex object
+ */
+void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
+{
+#ifdef USE_LOCKMGR_PRIORITY
+ m->priority = prio;
+#endif
+}
+
+/*
+ * Replacement for pthread_mutex_init()
+ */
+int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr)
+{
+ m->priority = 0;
+ return pthread_mutex_init(&m->mutex, attr);
+}
+
+/*
+ * Replacement for pthread_mutex_destroy()
+ */
+int pthread_mutex_destroy(bthread_mutex_t *m)
+{
+ return pthread_mutex_destroy(&m->mutex);
+}
+
+/*
+ * Replacement for pthread_kill (only with USE_LOCKMGR_SAFEKILL)
+ */
+int bthread_kill(pthread_t thread, int sig,
+ const char *file, int line)
+{
+ bool thread_found_in_process=false;
+
+ /* We doesn't allow to send signal to ourself */
+ ASSERT(!pthread_equal(thread, pthread_self()));
+
+ /* This loop isn't very efficient with dozens of threads but we don't use
+ * signal very much, and this feature is for testing only
+ */
+ lmgr_p(&lmgr_global_mutex);
+ {
+ lmgr_thread_t *item;
+ foreach_dlist(item, global_mgr) {
+ if (pthread_equal(thread, item->thread_id)) {
+ thread_found_in_process=true;
+ break;
+ }
+ }
+ }
+ lmgr_v(&lmgr_global_mutex);
+
+ /* Sending a signal to non existing thread can create problem
+ * so, we can stop here.
+ */
+ ASSERT(thread_found_in_process == true);
+
+ Dmsg3(100, "%s:%d send kill to existing thread %p\n", file, line, thread);
+ return pthread_kill(thread, sig);
}
/*
* Replacement for pthread_mutex_lock()
+ * Returns always ok
*/
-int lmgr_mutex_lock(pthread_mutex_t *m, const char *file, int line)
+int bthread_mutex_lock_p(bthread_mutex_t *m, const char *file, int line)
{
- int ret;
lmgr_thread_t *self = lmgr_get_thread_info();
- self->pre_P(m, file, line);
- ret = pthread_mutex_lock(m);
+ self->pre_P(m, m->priority, file, line);
+ lmgr_p(&m->mutex);
self->post_P();
- return ret;
+ return 0;
}
/*
* Replacement for pthread_mutex_unlock()
+ * Returns always ok
*/
-int lmgr_mutex_unlock(pthread_mutex_t *m, const char *file, int line)
+int bthread_mutex_unlock_p(bthread_mutex_t *m, const char *file, int line)
{
lmgr_thread_t *self = lmgr_get_thread_info();
self->do_V(m, file, line);
- return pthread_mutex_unlock(m);
+ lmgr_v(&m->mutex);
+ return 0;
}
+/*
+ * Replacement for pthread_mutex_lock() but with real pthread_mutex_t
+ * Returns always ok
+ */
+int bthread_mutex_lock_p(pthread_mutex_t *m, const char *file, int line)
+{
+ lmgr_thread_t *self = lmgr_get_thread_info();
+ self->pre_P(m, 0, file, line);
+ lmgr_p(m);
+ self->post_P();
+ return 0;
+}
+
+/*
+ * Replacement for pthread_mutex_unlock() but with real pthread_mutex_t
+ * Returns always ok
+ */
+int bthread_mutex_unlock_p(pthread_mutex_t *m, const char *file, int line)
+{
+ lmgr_thread_t *self = lmgr_get_thread_info();
+ self->do_V(m, file, line);
+ lmgr_v(m);
+ return 0;
+}
+
+
/* TODO: check this
*/
-int lmgr_cond_wait(pthread_cond_t *cond,
- pthread_mutex_t *mutex,
- const char *file, int line)
+int bthread_cond_wait_p(pthread_cond_t *cond,
+ pthread_mutex_t *m,
+ const char *file, int line)
{
int ret;
lmgr_thread_t *self = lmgr_get_thread_info();
- self->do_V(mutex, file, line);
- ret = pthread_cond_wait(cond, mutex);
- self->pre_P(mutex, file, line);
+ self->do_V(m, file, line);
+ ret = pthread_cond_wait(cond, m);
+ self->pre_P(m, 0, file, line);
self->post_P();
return ret;
}
+/* TODO: check this
+ */
+int bthread_cond_timedwait_p(pthread_cond_t *cond,
+ pthread_mutex_t *m,
+ const struct timespec * abstime,
+ const char *file, int line)
+{
+ int ret;
+ lmgr_thread_t *self = lmgr_get_thread_info();
+ self->do_V(m, file, line);
+ ret = pthread_cond_timedwait(cond, m, abstime);
+ self->pre_P(m, 0, file, line);
+ self->post_P();
+ return ret;
+}
+
+/* TODO: check this
+ */
+int bthread_cond_wait_p(pthread_cond_t *cond,
+ bthread_mutex_t *m,
+ const char *file, int line)
+{
+ int ret;
+ lmgr_thread_t *self = lmgr_get_thread_info();
+ self->do_V(m, file, line);
+ ret = pthread_cond_wait(cond, &m->mutex);
+ self->pre_P(m, m->priority, file, line);
+ self->post_P();
+ return ret;
+}
+
+/* TODO: check this
+ */
+int bthread_cond_timedwait_p(pthread_cond_t *cond,
+ bthread_mutex_t *m,
+ const struct timespec * abstime,
+ const char *file, int line)
+{
+ int ret;
+ lmgr_thread_t *self = lmgr_get_thread_info();
+ self->do_V(m, file, line);
+ ret = pthread_cond_timedwait(cond, &m->mutex, abstime);
+ self->pre_P(m, m->priority, file, line);
+ self->post_P();
+ return ret;
+}
+
+/* Test if this mutex is locked by the current thread
+ * returns:
+ * 0 - unlocked
+ * 1 - locked by the current thread
+ * 2 - locked by an other thread
+ */
+int lmgr_mutex_is_locked(void *m)
+{
+ lmgr_thread_t *self = lmgr_get_thread_info();
+
+ for(int i=0; i <= self->current; i++) {
+ if (self->lock_list[i].lock == m) {
+ return 1; /* locked by us */
+ }
+ }
+
+ return 0; /* not locked by us */
+}
+
/*
* Use this function when the caller handle the mutex directly
*
- * lmgr_pre_lock(m);
+ * lmgr_pre_lock(m, 10);
* pthread_mutex_lock(m);
* lmgr_post_lock(m);
*/
-void lmgr_pre_lock(void *m, const char *file, int line)
+void lmgr_pre_lock(void *m, int prio, const char *file, int line)
{
lmgr_thread_t *self = lmgr_get_thread_info();
- self->pre_P(m, file, line);
+ self->pre_P(m, prio, file, line);
}
/*
/*
* Do directly pre_P and post_P (used by trylock)
*/
-void lmgr_do_lock(void *m, const char *file, int line)
+void lmgr_do_lock(void *m, int prio, const char *file, int line)
{
lmgr_thread_t *self = lmgr_get_thread_info();
- self->pre_P(m, file, line);
+ self->pre_P(m, prio, file, line);
self->post_P();
}
const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg)
{
+ /* lmgr should be active (lmgr_init_thread() call in main()) */
+ ASSERT(lmgr_is_active());
/* Will be freed by the child */
lmgr_thread_arg_t *a = (lmgr_thread_arg_t*) malloc(sizeof(lmgr_thread_arg_t));
a->start_routine = start_routine;
a->arg = arg;
- return pthread_create(thread, attr, lmgr_thread_launcher, a);
+ return pthread_create(thread, attr, lmgr_thread_launcher, a);
}
#else /* _USE_LOCKMGR */
#ifdef _TEST_IT
#include "lockmgr.h"
-#define pthread_mutex_lock(x) lmgr_mutex_lock(x)
-#define pthread_mutex_unlock(x) lmgr_mutex_unlock(x)
-#define pthread_cond_wait(x,y) lmgr_cond_wait(x,y)
-#define pthread_create(a, b, c, d) lmgr_thread_create(a,b,c,d)
#undef P
#undef V
-#define P(x) lmgr_mutex_lock(&(x), __FILE__, __LINE__)
-#define V(x) lmgr_mutex_unlock(&(x), __FILE__, __LINE__)
-
-pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t mutex5 = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t mutex6 = PTHREAD_MUTEX_INITIALIZER;
+#define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
+#define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__)
+#define pthread_create(a, b, c, d) lmgr_thread_create(a,b,c,d)
+
+bthread_mutex_t mutex1 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex2 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex3 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex4 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex5 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex6 = BTHREAD_MUTEX_NO_PRIORITY;
+bthread_mutex_t mutex_p1 = BTHREAD_MUTEX_PRIORITY(1);
+bthread_mutex_t mutex_p2 = BTHREAD_MUTEX_PRIORITY(2);
+bthread_mutex_t mutex_p3 = BTHREAD_MUTEX_PRIORITY(3);
+static const char *my_prog;
void *self_lock(void *temp)
{
void *locker(void *temp)
{
- pthread_mutex_t *m = (pthread_mutex_t*) temp;
- pthread_mutex_lock(m);
- pthread_mutex_unlock(m);
+ bthread_mutex_t *m = (bthread_mutex_t*) temp;
+ P(*m);
+ V(*m);
return NULL;
}
return NULL;
}
+void *th_prio(void *a) {
+ char buf[512];
+ bstrncpy(buf, my_prog, sizeof(buf));
+ bstrncat(buf, " priority", sizeof(buf));
+ int ret = system(buf);
+ return (void*) ret;
+}
+
int err=0;
int nb=0;
void _ok(const char *file, int l, const char *op, int value, const char *label)
* - lock/unlock in wrong order
* - deadlock with 2 or 3 threads
*/
-int main()
+int main(int argc, char **argv)
{
+ void *ret=NULL;
+ lmgr_thread_t *self;
pthread_t id1, id2, id3, tab[200];
+ bthread_mutex_t bmutex1;
+ pthread_mutex_t pmutex2;
+ my_prog = argv[0];
+
+ use_undertaker = false;
lmgr_init_thread();
+ self = lmgr_get_thread_info();
+
+ if (argc == 2) { /* do priority check */
+ P(mutex_p2); /* not permited */
+ P(mutex_p1);
+ V(mutex_p1); /* never goes here */
+ V(mutex_p2);
+ return 0;
+ }
+
+ pthread_mutex_init(&bmutex1, NULL);
+ bthread_mutex_set_priority(&bmutex1, 10);
+
+ pthread_mutex_init(&pmutex2, NULL);
+ P(bmutex1);
+ ok(self->max_priority == 10, "Check self max_priority");
+ P(pmutex2);
+ ok(bmutex1.priority == 10, "Check bmutex_set_priority()");
+ V(pmutex2);
+ V(bmutex1);
+ ok(self->max_priority == 0, "Check self max_priority");
pthread_create(&id1, NULL, self_lock, NULL);
sleep(2);
ok(lmgr_detect_deadlock(), "Check self deadlock");
- lmgr_v(&mutex1); /* a bit dirty */
+ lmgr_v(&mutex1.mutex); /* a bit dirty */
pthread_join(id1, NULL);
P(mutex4);
P(mutex5);
P(mutex6);
+ ok(lmgr_mutex_is_locked(&mutex6) == 1, "Check if mutex is locked");
V(mutex6);
+ ok(lmgr_mutex_is_locked(&mutex6) == 0, "Check if mutex is locked");
V(mutex5);
V(mutex4);
sleep(1);
ok(lmgr_detect_deadlock(), "Check for deadlock");
+ pthread_create(&id3, NULL, th_prio, NULL);
+ pthread_join(id3, &ret);
+ ok(ret != 0, "Check for priority segfault");
+
+ P(mutex_p1);
+ ok(self->max_priority == 1, "Check max_priority 1/4");
+ P(mutex_p2);
+ ok(self->max_priority == 2, "Check max_priority 2/4");
+ P(mutex_p3);
+ ok(self->max_priority == 3, "Check max_priority 3/4");
+ P(mutex6);
+ ok(self->max_priority == 3, "Check max_priority 4/4");
+ V(mutex6);
+ ok(self->max_priority == 3, "Check max_priority 1/5");
+ V(mutex_p3);
+ ok(self->max_priority == 2, "Check max_priority 4/5");
+ V(mutex_p2);
+ ok(self->max_priority == 1, "Check max_priority 4/5");
+ V(mutex_p1);
+ ok(self->max_priority == 0, "Check max_priority 5/5");
+
+
+ P(mutex_p1);
+ P(mutex_p2);
+ P(mutex_p3);
+ P(mutex6);
+ ok(self->max_priority == 3, "Check max_priority mixed");
+ V(mutex_p2);
+ ok(self->max_priority == 3, "Check max_priority mixed");
+ V(mutex_p1);
+ ok(self->max_priority == 3, "Check max_priority mixed");
+ V(mutex_p3);
+ ok(self->max_priority == 0, "Check max_priority mixed");
+ V(mutex6);
+ ok(self->max_priority == 0, "Check max_priority mixed");
+
+ P(mutex_p1);
+ P(mutex_p2);
+ V(mutex_p1);
+ V(mutex_p2);
+
// lmgr_dump();
//
// pthread_create(&id3, NULL, th3, NULL);