Index: branches/pap/psLib/src/sys/psThread.c
===================================================================
--- branches/pap/psLib/src/sys/psThread.c	(revision 28179)
+++ branches/pap/psLib/src/sys/psThread.c	(revision 28484)
@@ -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"
@@ -29,4 +38,5 @@
 static psList *pending = NULL;          // queue of pending jobs
 static psList *done = NULL;             // queue of done jobs
+static pthread_t *threads = NULL;       // array of the POSIX thread handles
 static psArray *pool = NULL;            // array of defined threads
 static psHash *tasks = NULL;            // List of defined tasks
@@ -89,5 +99,12 @@
 bool psThreadJobAddPending(psThreadJob *job)
 {
-    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
+    if (!job) {
+        // Asking for a no-op
+        return true;
+    }
+
+    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,
@@ -100,9 +117,5 @@
         }
         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);
+        psFree(job);
         return task->function(job);
     }
@@ -113,4 +126,5 @@
     }
     psListAdd(pending, PS_LIST_TAIL, job);
+    psFree(job);
     psThreadUnlock();
 
@@ -209,6 +223,27 @@
 
         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, "invalid number of arguments to %s (%ld supplied, expected %d)", task->type, job->args->n, task->nArgs);
+        psAssert(job->args->n == task->nArgs,
+                 "invalid number of arguments to %s (%ld supplied, expected %d)",
+                 task->type, job->args->n, task->nArgs);
         bool status = task->function(job); // Status of executing task
 
@@ -234,5 +269,5 @@
 bool psThreadPoolInit(int nThreads)
 {
-    if (pool) {
+    if (pool || threads) {
         psAbort("psThreadsInit already called");
     }
@@ -245,8 +280,10 @@
 
     pool = psArrayAlloc(nThreads);
+    threads = psAlloc(nThreads * sizeof(pthread_t));
     for (int i = 0; i < nThreads; i++) {
-        psThread *thread = psThreadAlloc(); // Thread for pool
-        pthread_create(&thread->pt, NULL, psThreadLauncher, thread);
-        pool->data[i] = thread;
+        psThread *thread = pool->data[i] = psThreadAlloc(); // Thread for pool
+        if (pthread_create(&threads[i], NULL, psThreadLauncher, thread)) {
+            psAbort("Unable to create thread");
+        }
     }
     return true;
@@ -280,4 +317,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) {
@@ -326,4 +371,5 @@
 bool psThreadPoolFinalize(void)
 {
+    psThreadLock();
     psFree(pending);
     pending = NULL;
@@ -335,4 +381,7 @@
     pool = NULL;
 
+    psFree(threads);
+    threads = NULL;
+
     psFree(tasks);
     tasks = NULL;
@@ -340,4 +389,12 @@
     psFree(tsd);
     tsd = NULL;
+
+#ifdef HAVE_BACKTRACE
+    if (bt_buffer) {
+        psFree(bt_buffer);
+    }
+#endif
+
+    psThreadUnlock();
 
     return true;
