+
+/*
+ * Condition variable and Mutex for thread garbage collection
+ */
+static pthread_mutex_t thread_gc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t thread_gc_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t GC_thread;
+static char *CtdlThreadStates[CTDL_THREAD_LAST_STATE];
+/*
+ * Pinched the following bits regarding signals from Kannel.org
+ */
+
+/*
+ * Change this thread's signal mask to block user-visible signals
+ * (HUP, TERM, QUIT, INT), and store the old signal mask in
+ * *old_set_storage.
+ * Return 0 for success, or -1 if an error occurred.
+ */
+
+ /*
+ * This does not work in Darwin alias MacOS X alias Mach kernel,
+ * however. So we define a dummy function doing nothing.
+ */
+#if defined(DARWIN_OLD)
+ static int pthread_sigmask();
+#endif
+
+static int ctdl_thread_internal_block_signals(sigset_t *old_set_storage)
+{
+ int ret;
+ sigset_t block_signals;
+
+ ret = sigemptyset(&block_signals);
+ if (ret != 0) {
+ CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't initialize signal set\n");
+ return -1;
+ }
+ ret = sigaddset(&block_signals, SIGHUP);
+ ret |= sigaddset(&block_signals, SIGTERM);
+ ret |= sigaddset(&block_signals, SIGQUIT);
+ ret |= sigaddset(&block_signals, SIGINT);
+ if (ret != 0) {
+ CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't add signal to signal set.\n");
+ return -1;
+ }
+ ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage);
+ if (ret != 0) {
+ CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't disable signals for thread creation\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void ctdl_thread_internal_restore_signals(sigset_t *old_set)
+{
+ int ret;
+
+ ret = pthread_sigmask(SIG_SETMASK, old_set, NULL);
+ if (ret != 0) {
+ CtdlLogPrintf(CTDL_EMERG, "Thread system PANIC. Couldn't restore signal set.\n");
+ }
+}
+
+
+void ctdl_thread_internal_init(void)
+{
+ GC_thread = pthread_self();
+ CtdlThreadStates[CTDL_THREAD_INVALID] = strdup ("Invalid Thread");
+ CtdlThreadStates[CTDL_THREAD_VALID] = strdup("Valid Thread");
+ CtdlThreadStates[CTDL_THREAD_CREATE] = strdup("Thread being Created");
+ CtdlThreadStates[CTDL_THREAD_CANCELLED] = strdup("Thread Cancelled");
+ CtdlThreadStates[CTDL_THREAD_EXITED] = strdup("Thread Exited");
+ CtdlThreadStates[CTDL_THREAD_STOPPING] = strdup("Thread Stopping");
+ CtdlThreadStates[CTDL_THREAD_STOP_REQ] = strdup("Thread Stop Requested");
+ CtdlThreadStates[CTDL_THREAD_SLEEPING] = strdup("Thread Sleeping");
+ CtdlThreadStates[CTDL_THREAD_RUNNING] = strdup("Thread Running");
+}
+
+/*
+ * A function to tell all threads to exit
+ */
+void CtdlThreadStopAll(void)
+{
+ struct CtdlThreadNode *this_thread;
+
+ begin_critical_section(S_THREAD_LIST);
+ this_thread = CtdlThreadList;
+ while(this_thread)
+ {
+ pthread_mutex_lock(&this_thread->ThreadMutex); /* To prevent race condition of a sleeping thread */
+ if (this_thread->state > CTDL_THREAD_STOP_REQ)
+ this_thread->state = CTDL_THREAD_STOP_REQ;
+ pthread_mutex_unlock(&this_thread->ThreadMutex);
+ pthread_cond_signal(&this_thread->ThreadCond);
+ CtdlLogPrintf(CTDL_DEBUG, "Thread system stopping thread \"%s\" (%ld).\n", this_thread->name, this_thread->tid);
+ this_thread = this_thread->next;
+ }
+ end_critical_section(S_THREAD_LIST);
+}
+
+
+/*
+ * A function to signal that we need to do garbage collection on the thread list
+ */
+void CtdlThreadGC(void)
+{
+ pthread_cond_signal(&thread_gc_cond);
+}