/*
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.
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;
+ bthread_mutex_t mutex = BTHREAD_MUTEX_PRIORITY(1);
P(mutex);
...
V(mutex);
#undef ASSERT
#define ASSERT(x) if (!(x)) { \
char *jcr = NULL; \
- Pmsg3(000, _("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, _("from %s:%i Failed ASSERT: %s\n"), f, l, #x); \
+ 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;
/*
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=%s %s:%i\n",
+ 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);
}
}
* Call before a lock operation (mark mutex as WANTED)
*/
virtual void pre_P(void *m, int priority,
- const char *f="*unknown*", int l=0) {
+ 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);
- ASSERT_p(!priority || priority >= max_priority, f, l);
lmgr_p(&mutex);
{
current++;
max_priority = MAX(priority, max_priority);
}
lmgr_v(&mutex);
+ ASSERT_p(!priority || priority >= max_prio, f, l);
}
/*
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;
}
*/
void bthread_mutex_set_priority(bthread_mutex_t *m, int prio)
{
+#ifdef USE_LOCKMGR_PRIORITY
m->priority = prio;
+#endif
}
/*
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
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
*
#ifdef _TEST_IT
#include "lockmgr.h"
-#define BTHREAD_MUTEX_NO_PRIORITY {PTHREAD_MUTEX_INITIALIZER, 0}
-#define BTHREAD_MUTEX_PRIORITY(p) {PTHREAD_MUTEX_INITIALIZER, p}
#undef P
#undef V
#define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__)
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);