summaryrefslogtreecommitdiffstats
path: root/src/server/locks.c
diff options
context:
space:
mode:
authorsr2013-07-16 21:20:07 +0200
committersr2013-07-16 21:20:07 +0200
commitc31b8d90a4e4809ada5b60fcdcc93b6ecf9326e4 (patch)
treecc5d5901ddb7bc7ba9c2c2beeaee3154c8a3b0f7 /src/server/locks.c
parentFix more bugs, remove debug messages (diff)
downloaddnbd3-c31b8d90a4e4809ada5b60fcdcc93b6ecf9326e4.tar.gz
dnbd3-c31b8d90a4e4809ada5b60fcdcc93b6ecf9326e4.tar.xz
dnbd3-c31b8d90a4e4809ada5b60fcdcc93b6ecf9326e4.zip
Add debug-lock functions that will helpt to spot deadlocks etc. while developing
Diffstat (limited to 'src/server/locks.c')
-rw-r--r--src/server/locks.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/server/locks.c b/src/server/locks.c
new file mode 100644
index 0000000..5a68747
--- /dev/null
+++ b/src/server/locks.c
@@ -0,0 +1,220 @@
+/*
+ * locks.c
+ *
+ * Created on: 16.07.2013
+ * Author: sr
+ */
+
+#include "locks.h"
+
+#ifdef _DEBUG
+
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "globals.h"
+
+#define MAXLOCKS 500
+#define MAXTHREADS 500
+#define LOCKLEN 60
+typedef struct
+{
+ void *lock;
+ volatile time_t locktime;
+ volatile char locked;
+ pthread_t thread;
+ int lockId;
+ char name[LOCKLEN];
+ char where[LOCKLEN];
+} debug_lock_t;
+
+typedef struct
+{
+ pthread_t tid;
+ time_t time;
+ char name[LOCKLEN];
+ char where[LOCKLEN];
+
+} debug_thread_t;
+
+static debug_lock_t locks[MAXLOCKS];
+static debug_thread_t threads[MAXTHREADS];
+static int init_done = 0;
+static pthread_spinlock_t initdestory;
+static volatile int lockId = 0;
+
+int debug_spin_init(const char *name, const char *file, int line, pthread_spinlock_t *lock, int shared)
+{
+ if ( !init_done ) {
+ memset( locks, 0, MAXLOCKS * sizeof(debug_lock_t) );
+ memset( threads, 0, MAXTHREADS * sizeof(debug_thread_t) );
+ pthread_spin_init( &initdestory, PTHREAD_PROCESS_PRIVATE );
+ init_done = 1;
+ }
+ int first = -1;
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXLOCKS; ++i) {
+ if ( locks[i].lock == lock ) {
+ printf( "[ERROR] Lock %p (%s) already initialized (%s:%d)\n", lock, name, file, line );
+ exit( 4 );
+ }
+ if ( first == -1 ) first = i;
+ }
+ if ( first == -1 ) {
+ printf( "[ERROR] No more free debug locks (%s:%d)\n", file, line );
+ exit( 4 );
+ }
+ locks[first].lock = (void*)lock;
+ locks[first].locked = 0;
+ snprintf( locks[first].name, LOCKLEN, "%s", name );
+ snprintf( locks[first].where, LOCKLEN, "I %s:%d", file, line );
+ pthread_spin_unlock( &initdestory );
+ return pthread_spin_init( lock, shared );
+}
+
+int debug_spin_lock(const char *name, const char *file, int line, pthread_spinlock_t *lock)
+{
+ debug_lock_t *l = NULL;
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXLOCKS; ++i) {
+ if ( locks[i].lock == lock ) {
+ l = &locks[i];
+ break;
+ }
+ }
+ pthread_spin_unlock( &initdestory );
+ if ( l == NULL ) {
+ printf( "[ERROR] Tried to lock uninitialized lock %p (%s) at %s:%d\n", lock, name, file, line );
+ exit( 4 );
+ }
+ debug_thread_t *t = NULL;
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXTHREADS; ++i) {
+ if ( threads[i].tid != 0 ) continue;
+ threads[i].tid = pthread_self();
+ threads[i].time = time( NULL );
+ snprintf( threads[i].name, LOCKLEN, "%s", name );
+ snprintf( threads[i].where, LOCKLEN, "%s:%d", file, line );
+ t = &threads[i];
+ }
+ pthread_spin_unlock( &initdestory );
+ int retval = pthread_spin_lock( lock );
+ pthread_spin_lock( &initdestory );
+ t->tid = 0;
+ pthread_spin_unlock( &initdestory );
+ if ( l->locked ) {
+ printf( "[ERROR] Lock sanity check: lock %p (%s) already locked at %s:%d\n", lock, name, file, line );
+ exit( 4 );
+ }
+ l->locked = 1;
+ l->locktime = time( NULL );
+ l->thread = pthread_self();
+ snprintf( l->where, LOCKLEN, "L %s:%d", file, line );
+ pthread_spin_lock( &initdestory );
+ l->lockId = ++lockId;
+ pthread_spin_unlock( &initdestory );
+ return retval;
+}
+
+int debug_spin_unlock(const char *name, const char *file, int line, pthread_spinlock_t *lock)
+{
+ debug_lock_t *l = NULL;
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXLOCKS; ++i) {
+ if ( locks[i].lock == lock ) {
+ l = &locks[i];
+ break;
+ }
+ }
+ pthread_spin_unlock( &initdestory );
+ if ( l == NULL ) {
+ printf( "[ERROR] Tried to unlock uninitialized lock %p (%s) at %s:%d\n", lock, name, file, line );
+ exit( 4 );
+ }
+ int retval = pthread_spin_unlock( lock );
+ if ( !l->locked ) {
+ printf( "[ERROR] Unlock sanity check: lock %p (%s) not locked at %s:%d\n", lock, name, file, line );
+ exit( 4 );
+ }
+ l->locked = 0;
+ l->locktime = 0;
+ l->thread = 0;
+ snprintf( l->where, LOCKLEN, "U %s:%d", file, line );
+ return retval;
+}
+
+int debug_spin_destory(const char *name, const char *file, int line, pthread_spinlock_t *lock)
+{
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXLOCKS; ++i) {
+ if ( locks[i].lock == lock ) {
+ if ( locks[i].locked ) {
+ printf( "[ERROR] Tried to destroy lock %p (%s) at %s:%d when it is still locked\n", lock, name, file, line );
+ exit( 4 );
+ }
+ locks[i].lock = NULL;
+ snprintf( locks[i].where, LOCKLEN, "D %s:%d", file, line );
+ pthread_spin_unlock( &initdestory );
+ return pthread_spin_destroy( lock );
+ }
+ }
+ printf( "[ERROR] Tried to destroy non-existent lock %p (%s) at %s:%d\n", lock, name, file, line );
+ exit( 4 );
+}
+
+void debug_dump_lock_stats()
+{
+ time_t now = time( NULL );
+ pthread_spin_lock( &initdestory );
+ printf( "\n **** LOCKS ****\n\n" );
+ for (int i = 0; i < MAXLOCKS; ++i) {
+ if ( locks[i].lock == NULL ) continue;
+ if ( locks[i].locked ) {
+ printf( "* *** %s ***\n"
+ "* Where: %s\n"
+ "* When: %d secs ago\n"
+ "* Locked: %d\n"
+ "* Serial: %d\n"
+ "* Thread: %d\n", locks[i].name, locks[i].where, (int)(now - locks[i].locktime), (int)locks[i].locked, locks[i].lockId,
+ (int)locks[i].thread );
+ } else {
+ printf( "* *** %s ***\n"
+ "* Where: %s\n"
+ "* Locked: %d\n", locks[i].name, locks[i].where, (int)locks[i].locked );
+ }
+ }
+ printf( "\n **** THREADS ****\n\n" );
+ for (int i = 0; i < MAXTHREADS; ++i) {
+ if ( threads[i].tid == 0 ) continue;
+ printf( "* *** Thread %d ***\n"
+ "* Lock: %s\n"
+ "* Where: %s\n"
+ "* How long: %d secs\n", (int)threads[i].tid, threads[i].name, threads[i].where, (int)(now - threads[i].time) );
+ }
+ pthread_spin_unlock( &initdestory );
+}
+
+void *debug_thread_watchdog(void *something)
+{
+ while (!_shutdown) {
+ time_t now = time(NULL);
+ pthread_spin_lock( &initdestory );
+ for (int i = 0; i < MAXTHREADS; ++i) {
+ if ( threads[i].tid == 0 ) continue;
+ const int diff = now - threads[i].time;
+ if ( diff > 6 && diff < 100000 ) {
+ printf("\n\n +++++++++ DEADLOCK ++++++++++++\n\n");
+ pthread_spin_unlock( &initdestory );
+ debug_dump_lock_stats();
+ exit(99);
+ }
+ }
+ pthread_spin_unlock( &initdestory );
+ sleep(10);
+ }
+ return NULL;
+}
+
+#endif