Index: trunk/psLib/src/sys/psThread.c
===================================================================
--- trunk/psLib/src/sys/psThread.c	(revision 28307)
+++ trunk/psLib/src/sys/psThread.c	(revision 28351)
@@ -7,4 +7,13 @@
 #include <unistd.h>
 #include <string.h>
+
+// Backtrace to help nail down bugs
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#include <stdlib.h>
+#define BACKTRACE_BUFFER_SIZE 256       // Maximum size of backtrace
+static void **bt_buffer = NULL;         // Backtrace buffer
+static int bt_size = 0;                 // Backtrace buffer size
+#endif
 
 #include "psAssert.h"
@@ -33,4 +42,5 @@
 static psArray *tsd = NULL;             // Thread-specific data
 
+
 /***** basic thread functions *****/
 
@@ -91,4 +101,8 @@
     PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
 
+    psThreadTask *task = psHashLookup(tasks, job->type); // Task to execute job
+    psAssert(task, "Unable to find task %s", job->type);
+    psAssert(job->args->n == task->nArgs, "invalid number of arguments to %s", task->type);
+
     // if we failed to call psThreadPoolInit, or we called it with nThreads == 0,
     // find the matching function and just run it.
@@ -101,8 +115,4 @@
         psListAdd(done, PS_LIST_TAIL, job);
 
-        // find the corresponding task and run it
-        psThreadTask *task = psHashLookup(tasks, job->type); // Task to execute job
-        psAssert(task, "Unable to find task %s", job->type);
-        psAssert(job->args->n == task->nArgs, "invalid number of arguments to %s", task->type);
         return task->function(job);
     }
@@ -209,4 +219,23 @@
 
         psThreadTask *task = psHashLookup(tasks, job->type); // Task to execute job
+#ifdef HAVE_BACKTRACE
+        if (!task && bt_buffer) {
+            psLogMsg("psLib.sys", PS_LOG_ABORT, "Backtrace of waiter:\n");
+            char **strings = backtrace_symbols((void *const *)bt_buffer, bt_size);
+            psLogMsg("psLib.sys", PS_LOG_ABORT, "Backtrace depth: %d", bt_size);
+            for (int i = 0; i < bt_size; i++) {
+                char *caller = strchr(strings[i], '(');
+                if (caller) {
+                    caller++;
+                    size_t callerLength = abs(strchr(caller, '+') - caller);
+                    psString name = psStringNCopy(caller, callerLength);
+                    psLogMsg("psLib.sys", PS_LOG_ABORT, "Backtrace %d: %s", i, name);
+                    psFree(name);
+                } else {
+                    psLogMsg("psLib.sys", PS_LOG_ABORT, "Backtrace %d: (unknown)", i);
+                }
+            }
+        }
+#endif
         psAssert(task, "Couldn't find thread task %s", job->type);
         psAssert(job->args->n == task->nArgs,
@@ -282,4 +311,12 @@
         return true;
     }
+
+#ifdef HAVE_BACKTRACE
+    if (bt_buffer) {
+        psFree(bt_buffer);
+    }
+    bt_buffer = psAlloc(BACKTRACE_BUFFER_SIZE * sizeof(void *));
+    bt_size = backtrace(bt_buffer, BACKTRACE_BUFFER_SIZE);
+#endif
 
     while (1) {
@@ -343,4 +380,10 @@
     tsd = NULL;
 
+#ifdef HAVE_BACKTRACE
+    if (bt_buffer) {
+        psFree(bt_buffer);
+    }
+#endif
+
     return true;
 }
