src/ModuleFunctions.c \
src/statistics.c \
src/log.c \
- src/memoryDebug.c
+ src/memoryDebug.c \
+ src/mutexDebug.c
neonserv_LDADD = $(MYSQL_LIBS) $(SYSTEM_LIBS)
],
[])
+AC_ARG_ENABLE([mutex-debug],
+ [AS_HELP_STRING([--enable-mutex-debug], [run mutex debugger])],
+ [
+ AC_DEFINE([ENABLE_MUTEX_DEBUG], 1, [Define if you enable mutexDebug.c])
+ ],
+ [])
+
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug], [debug mode (compile using -O0 -Wall -Wshadow -Werror)])],
[CFLAGS='-g -O0 -Wall -Wshadow -Werror'],
initMemoryDebug();
#endif
+ //initialize mutex debugger BEFORE using any mutexes
+ #ifdef ENABLE_MUTEX_DEBUG
+ initMutexDebug();
+ #endif
+
//deny root startup
#ifndef WIN32
if(geteuid() == 0 || getuid() == 0) {
free(mem_ref);
}
-
static void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line) {
- SYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_lock(&synchronized);
+ #endif
struct MemoryLeak *mem_leak_info = malloc(sizeof(*mem_leak_info));
own_allocated_memleaks++;
mem_leak_info->mem_info.address = mem_ref;
mem_leak_info->mem_info.line = line;
mem_leak_info->next = ptr_start;
ptr_start = mem_leak_info;
- DESYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_unlock(&synchronized);
+ #endif
}
static void remove_mem_info(void *mem_ref) {
- SYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_lock(&synchronized);
+ #endif
struct MemoryLeak *leak_info, *next, *prev = NULL;
for(leak_info = ptr_start; leak_info; leak_info = next) {
next = leak_info->next;
} else
prev = leak_info;
}
- DESYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_unlock(&synchronized);
+ #endif
}
void initMemoryDebug() {
}
struct memoryInfoFiles *getMemoryInfoFiles() {
- SYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_lock(&synchronized);
+ #endif
struct MemoryLeak *leak_info;
struct memoryInfoFiles *list = NULL, *element;
for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
element->allocated = own_allocated_memleaks * sizeof(struct MemoryLeak);
element->next = list;
list = element;
- DESYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_unlock(&synchronized);
+ #endif
return list;
}
}
struct memoryInfoLines *getMemoryInfoLines(const char *filename) {
- SYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_lock(&synchronized);
+ #endif
struct MemoryLeak *leak_info;
struct memoryInfoLines *list = NULL, *element;
for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
element->next = list;
list = element;
}
- DESYNCHRONIZE(synchronized);
+ #ifdef HAVE_THREADS
+ pthread_mutex_unlock(&synchronized);
+ #endif
return list;
}
/* 000-001 */ #include "main.h"
/* 002-004 */ #include "tools.h"
-/* 005-006 */ /* deprecated */
+#ifdef ENABLE_MUTEX_DEBUG
+/* 005-006 */ #include "mutexDebug.h"
+#endif
/* 007-009 */ /* main.h */
/* 010 */ #include "log.h"
/* 011 */ /* main.h */
/* 099-102 */ #include "memoryDebug.h"
#endif
/* 103-106 */ #include "memoryInfo.h"
-/* 107-125 */ #include "modcmd.h"
+/* 107-122 */ #include "modcmd.h"
+/* 123 */ /* deprecated */
+/* 124-125 */ /* modcmd.h */
/* 126-136 */ #include "ModeNode.h"
/* 137-142 */ #include "mysqlConn.h"
/* 143-149 */ #include "timeq.h"
/* 002 */ (Function) getCurrentSecondsOfDay,
/* 003 */ (Function) stricmp,
/* 004 */ (Function) stricmplen,
-/* 005 */ (Function) NULL, /* deprecated */
-/* 006 */ (Function) NULL, /* deprecated */
+#ifdef ENABLE_MUTEX_DEBUG
+/* 005 */ (Function) xmutex,
+/* 006 */ (Function) mutex_debug,
+#else
+/* 005 */ (Function) NULL,
+/* 006 */ (Function) NULL,
+#endif
/* 007 */ (Function) restart_bot,
/* 008 */ (Function) stop_bot,
/* 009 */ (Function) reload_config,
/* 002 */ #define getCurrentSecondsOfDay ((int (*)(void))global[2])
/* 003 */ #define stricmp ((int (*)(const char *, const char *))global[3])
/* 004 */ #define stricmplen ((int (*)(const char *, const char *, int))global[4])
-/* 005 */ /* deprecated */
-/* 006 */ /* deprecated */
+#ifdef ENABLE_MUTEX_DEBUG
+/* 005 */ #define xmutex ((void (*)(int, pthread_mutex_t *, const char *, unsigned int))global[005])
+/* 006 */ #define mutex_debug ((void (*)(pthread_mutex_t *))global[006])
+#endif
/* 007 */ #define restart_bot ((void (*)(int))global[7])
/* 008 */ #define stop_bot ((void (*)(void))global[8])
/* 009 */ #define reload_config ((void (*)(void))global[9])
--- /dev/null
+/* mutexDebug.c - NeonServ v5.6
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "main.h"
+#include "mutexDebug.h"
+
+#ifdef ENABLE_MUTEX_DEBUG
+
+struct MutexLockEvent {
+ int locked;
+ const char *file;
+ unsigned int line;
+ struct MutexLockEvent *next;
+};
+
+struct MutexLock {
+ int thread;
+ int count;
+ struct MutexLockEvent *first_event, *last_event;
+ struct MutexLock *prev, *next;
+};
+
+struct MutexNode {
+ pthread_mutex_t *mutex;
+ struct MutexLock *first_lock, *last_lock;
+ struct MutexNode *next;
+};
+
+static pthread_mutex_t synchronized;
+static struct MutexNode *mutex_nodes = NULL;
+
+static struct MutexNode *getMutexNode(pthread_mutex_t *mutex, int create);
+static void lockMutex(struct MutexNode *node, const char *file, unsigned int line);
+static void unlockMutex(struct MutexNode *node, const char *file, unsigned int line);
+
+void xmutex(int lock, pthread_mutex_t *mutex, const char *file, unsigned int line) {
+ pthread_mutex_lock(&synchronized);
+ struct MutexNode *node = getMutexNode(mutex, 1);
+ if(lock)
+ lockMutex(node, file, line);
+ else
+ unlockMutex(node, file, line);
+ pthread_mutex_unlock(&synchronized);
+}
+
+void initMutexDebug() {
+ THREAD_MUTEX_INIT(synchronized);
+}
+
+static struct MutexNode *getMutexNode(pthread_mutex_t *mutex, int create) {
+ struct MutexNode *node;
+ for(node = mutex_nodes; node; node = node->next) {
+ if(node->mutex == mutex)
+ return node;
+ }
+ if(!create)
+ return NULL;
+ node = malloc(sizeof(*node));
+ node->first_lock = NULL;
+ node->last_lock = NULL;
+ node->mutex = mutex;
+ node->next = mutex_nodes;
+ mutex_nodes = node;
+ return node;
+}
+
+static void lockMutex(struct MutexNode *node, const char *file, unsigned int line) {
+ struct MutexLock *lock;
+ int thread = getCurrentThreadID();
+ for(lock = node->first_lock; lock; lock = lock->next) {
+ if(lock->thread == thread)
+ break;
+ }
+ if(!lock) {
+ lock = malloc(sizeof(*lock));
+ lock->thread = thread;
+ lock->count = 0;
+ lock->first_event = NULL;
+ lock->last_event = NULL;
+ lock->prev = node->last_lock;
+ lock->next = NULL;
+ node->last_lock = lock;
+ if(!node->first_lock)
+ node->first_lock = lock;
+ }
+ lock->count++;
+ //add event
+ struct MutexLockEvent *event = malloc(sizeof(*event));
+ event->locked = 1;
+ event->file = file;
+ event->line = line;
+ event->next = NULL;
+ if(lock->last_event) {
+ lock->last_event->next = event;
+ lock->last_event = event;
+ } else {
+ lock->first_event = event;
+ lock->last_event = event;
+ }
+}
+
+static void unlockMutex(struct MutexNode *node, const char *file, unsigned int line) {
+ struct MutexLock *lock;
+ int thread = getCurrentThreadID();
+ for(lock = node->first_lock; lock; lock = lock->next) {
+ if(lock->thread == thread)
+ break;
+ }
+ if(!lock)
+ return;
+ lock->count--;
+ if(lock->count <= 0) {
+ //remove lock
+ if(lock->prev)
+ lock->prev->next = lock->next;
+ else
+ node->first_lock = lock->next;
+ if(lock->next)
+ lock->next->prev = lock->prev;
+ else
+ node->last_lock = lock->prev;
+ //recursive free all events
+ struct MutexLockEvent *event, *next_event;
+ for(event = lock->first_event; event; event = next_event) {
+ next_event = event->next;
+ free(event);
+ }
+ free(lock);
+ } else {
+ //add event
+ struct MutexLockEvent *event = malloc(sizeof(*event));
+ event->locked = 0;
+ event->file = file;
+ event->line = line;
+ event->next = NULL;
+ if(lock->last_event) {
+ lock->last_event->next = event;
+ lock->last_event = event;
+ } else {
+ lock->first_event = event;
+ lock->last_event = event;
+ }
+ }
+}
+
+void mutex_debug(pthread_mutex_t *mutex) {
+ //replay mutex events to stdout
+ struct MutexNode *node = getMutexNode(mutex, 0);
+ if(!node) {
+ printf("[MUTEX_DEBUG] unknown mutex!\n");
+ return;
+ }
+ printf("[MUTEX_DEBUG] mutex replay:\n");
+ struct MutexLock *lock;
+ struct MutexLockEvent *event;
+ for(lock = node->first_lock; lock; lock = lock->next) {
+ printf("[MUTEX_DEBUG] THREAD %d (%d locks):\n", lock->thread, lock->count);
+ for(event = lock->first_event; event; event = event->next) {
+ printf("[MUTEX_DEBUG] %s in %s:%d\n", (event->locked ? "lock " : "unlock"), event->file, event->line);
+ }
+ }
+ printf("[MUTEX_DEBUG] end of mutex replay.\n");
+}
+
+#endif
--- /dev/null
+/* mutexDebug.h - NeonServ v5.6
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _mutexdebug_h
+#define _mutexdebug_h
+
+#ifndef DND_FUNCTIONS
+#ifdef ENABLE_MUTEX_DEBUG
+/* MODULAR ACCESSIBLE */ void xmutex(int lock, pthread_mutex_t *mutex, const char *file, unsigned int line);
+/* MODULAR ACCESSIBLE */ void mutex_debug(pthread_mutex_t *mutex);
+
+void initMutexDebug();
+
+#endif
+#endif
+#endif
pthread_mutexattr_settype(&mutex_attr, type);\
pthread_mutex_init(&var, &mutex_attr); \
}
+#ifdef ENABLE_MUTEX_DEBUG
+#include "mutexDebug.h"
+#define SYNCHRONIZE(var) xmutex(1, &var, __FILE__, __LINE__); pthread_mutex_lock(&var)
+#define DESYNCHRONIZE(var) xmutex(0, &var, __FILE__, __LINE__); pthread_mutex_unlock(&var)
+#else
#define SYNCHRONIZE(var) pthread_mutex_lock(&var)
-#define SET_SYNCHRONIZE(var) pthread_mutex_trylock(&var)
#define DESYNCHRONIZE(var) pthread_mutex_unlock(&var)
+#endif
#else
#define THREAD_MUTEX_INIT(var)
#define SYNCHRONIZE(var)
#define DESYNCHRONIZE(var)
+#ifdef ENABLE_MUTEX_DEBUG
+#undef ENABLE_MUTEX_DEBUG
+#endif
#endif
#if __GNUC__