[xiph-commits] r13396 - in experimental/moritz: . thread
thread/win32
moritz at svn.xiph.org
moritz at svn.xiph.org
Sun Jul 29 17:46:55 PDT 2007
Author: moritz
Date: 2007-07-29 17:46:55 -0700 (Sun, 29 Jul 2007)
New Revision: 13396
Added:
experimental/moritz/thread/
experimental/moritz/thread/Makefile
experimental/moritz/thread/config.h
experimental/moritz/thread/main.c
experimental/moritz/thread/thread.c
experimental/moritz/thread/thread.h
experimental/moritz/thread/win32/
experimental/moritz/thread/win32/libthread.sln
experimental/moritz/thread/win32/libthread.vcproj
Log:
Add my re-write of Jack Moffitt's thread library, used as "libicethread" in
Icecast, among others. No copying and pasting was going on, but I did look at
his version for ideas and guidance, and there are a bunch of striking
similarities.
Since I am obviously wandering a grey area here, I emailed Jack about this
and he said it is okay.
He doesn't like the BSD license here very much, because of the many free-
riders that are already using Xiph.org's work without giving anything back --
he favors copyleft licenses. My own opinion in this regard is different and
biased like anyone else's, but I firmly believe that with these, BSD is the
way to go. They are so low-level that it is impossible to tell what they
might end up being used for (even within Xiph) and I do not want to force
people to libtoolize and separate these few lines of code just so they can
choose a license that is best for their project.
The API of this libthread version is still almost the same, just a little bit
more consistent in a few areas. The debugging facilities have been improved
and fleshed out, and there is no longer a dependency on libavl. My regression
test, using it within Icecast, worked out well, too.
TODO: Protect strerror().
Added: experimental/moritz/thread/Makefile
===================================================================
--- experimental/moritz/thread/Makefile (rev 0)
+++ experimental/moritz/thread/Makefile 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,36 @@
+PROG = thread
+LIB = libthread.a
+
+SRC = main.c
+OBJ = main.o
+LIBSRC = thread.c
+LIBOBJ = thread.o
+
+THREADS = -pthread
+CC ?= gcc
+CFLAGS ?= -O2 -pipe
+CFLAGS += -DHAVE_CONFIG_H=1 -DTHREAD_DEBUG=1 -DXALLOC_DEBUG=1 -DXALLOC_WITH_XASPRINTF=1 -fstrict-aliasing -Wall -ansi -pedantic -Wwrite-strings -Wpointer-arith -Wformat=2 $(THREADS)
+DEBUG ?= -g -ggdb
+INCLUDEFLAGS = -I../compat -I../xalloc -pthread
+LDFLAGS = -L. -L../xalloc -lxalloc -lthread $(THREADS)
+
+
+all: depend $(LIB) $(PROG)
+
+depend: $(SRC)
+ $(CC) -M $(CFLAGS) $(INCLUDEFLAGS) $(SRC) > .depend
+
+.c.o: $(SRC)
+ $(CC) $(CFLAGS) $(DEBUG) $(INCLUDEFLAGS) -c $<
+
+lib: $(LIB)
+
+$(LIB): $(LIBOBJ)
+ ar cru $(LIB) $(LIBOBJ)
+ ranlib $(LIB)
+
+$(PROG): $(OBJ)
+ $(CC) $(DEBUG) $(OBJ) $(LDFLAGS) -o $(PROG)
+
+clean:
+ - at rm *.o *~ *.core core .depend $(PROG) $(LIB)
Added: experimental/moritz/thread/config.h
===================================================================
--- experimental/moritz/thread/config.h (rev 0)
+++ experimental/moritz/thread/config.h 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,5 @@
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_NANOSLEEP 1
+#define HAVE_POLL_H 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_SYS_TREE_H 1
Added: experimental/moritz/thread/main.c
===================================================================
--- experimental/moritz/thread/main.c (rev 0)
+++ experimental/moritz/thread/main.c 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <stdio.h>
+
+#include "xalloc.h"
+#include "thread.h"
+
+void *
+hello(void *arg)
+{
+ printf("Hello World!\n");
+ return (arg);
+}
+
+int
+main(void)
+{
+ thread_t thread;
+
+#ifdef XALLOC_DEBUG
+ xalloc_initialize_debug(2, stdout);
+#else
+ xalloc_initialize();
+#endif
+
+#ifdef THREAD_DEBUG
+ thread_initialize_debug(4, stdout);
+#else
+ thread_initialize();
+#endif
+
+ thread = thread_create("Test", hello, NULL, THREAD_ATTACHED);
+
+ thread_join(&thread);
+
+ thread_shutdown();
+ xalloc_shutdown();
+ return (0);
+}
Added: experimental/moritz/thread/thread.c
===================================================================
--- experimental/moritz/thread/thread.c (rev 0)
+++ experimental/moritz/thread/thread.c 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,1289 @@
+/*
+ * libthread - Cross platform thread and syncronization library, with
+ * extensive error checking and debugging facility.
+ * Uses POSIX threads (libpthread, or pthread-win32 on
+ * Windows.)
+ *
+ * Library design and ideas adapted from libicethread, written by
+ * Jack Moffitt for the Icecast project, which is Copyright 2000-2004
+ * and licensed under the terms of the LGPL - available at
+ * http://www.icecast.org/. Licensed and used with permission.
+ *
+ * Copyright (C) 2007 Moritz Grimm <mgrimm at gmx.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TREE_H
+# include <sys/tree.h>
+#else
+# include "sys/tree.h"
+#endif /* HAVE_SYS_TREE_H */
+
+#include <errno.h>
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+#include <pthread.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef WIN32
+# include <windows.h>
+#endif
+
+#include "xalloc.h"
+#include "thread.h"
+
+
+#define MUTEX_LOCKED 1
+#define MUTEX_UNLOCKED 0
+#define MUTEX_NEVERLOCKED -1
+
+#define THREAD_DBGLVL_MAX 4
+#ifndef THREAD_DEBUG
+void thread_initialize_debug(unsigned int, FILE *);
+#else
+# ifdef THREAD_DIE_SILENT
+# undef THREAD_DIE_SILENT
+# endif /* THREAD_DIE_SILENT */
+#endif /* !THREAD_DEBUG */
+
+void _thread_fatal(const char *, ...);
+void _thread_debug_printf(unsigned int, const char *, ...);
+void _init_mutexes(void);
+void _catch_signals(void);
+void _block_signals(void);
+int _thread_cmp(void *, void *);
+int _mutex_cmp(void *, void *);
+int _cond_cmp(void *, void *);
+int _rwlock_cmp(void *, void *);
+void _thread_free(struct thread **);
+void * _thread_start_routine(void *);
+void _mutex_init(struct mutex *);
+void _mutex_lock(struct mutex *);
+void _mutex_unlock(struct mutex *);
+void _mutex_free(struct mutex **);
+void _cond_free(struct cond **);
+void _rwlock_free(struct rwlock **);
+
+
+struct thread {
+ RB_ENTRY(thread) entry;
+ int id;
+ char *name;
+ time_t create_time;
+ char *creator;
+ unsigned int line;
+ int detached;
+ pthread_t sys_thread;
+};
+RB_HEAD(thread_tree, thread) thread_tree_head = RB_INITIALIZER(&thread_tree_head);
+RB_GENERATE(thread_tree, thread, entry, _thread_cmp)
+
+struct thread_start {
+ void * (*start_routine)(void *);
+ void *start_arg;
+ struct thread *thread;
+ pthread_t sys_thread;
+};
+
+struct mutex {
+ RB_ENTRY(mutex) entry;
+ int id;
+ int thread_id;
+ char *name;
+ int state;
+ time_t create_time;
+ char *creator;
+ unsigned int line;
+ pthread_mutex_t sys_mutex;
+};
+RB_HEAD(mutex_tree, mutex) mutex_tree_head = RB_INITIALIZER(&mutex_tree_head);
+RB_GENERATE(mutex_tree, mutex, entry, _mutex_cmp)
+
+struct cond {
+ RB_ENTRY(cond) entry;
+ int id;
+ char *name;
+ time_t create_time;
+ char *creator;
+ unsigned int line;
+ pthread_mutex_t cond_mutex;
+ pthread_cond_t sys_cond;
+};
+RB_HEAD(cond_tree, cond) cond_tree_head = RB_INITIALIZER(&cond_tree_head);
+RB_GENERATE(cond_tree, cond, entry, _cond_cmp)
+
+struct rwlock {
+ RB_ENTRY(rwlock) entry;
+ int id;
+ char *name;
+ time_t create_time;
+ char *creator;
+ unsigned int line;
+ pthread_rwlock_t sys_rwlock;
+};
+RB_HEAD(rwlock_tree, rwlock) rwlock_tree_head = RB_INITIALIZER(&rwlock_tree_head);
+RB_GENERATE(rwlock_tree, rwlock, entry, _rwlock_cmp)
+
+
+extern char *__progname;
+
+
+static int thread_initialized = 0;
+static int next_thread_id = 0;
+static int next_mutex_id = 0;
+static int next_cond_id = 0;
+static int next_rwlock_id = 0;
+static int debug_level = 0;
+static FILE *debug_output = NULL;
+static struct mutex *threadtree_mutex;
+static struct mutex *mutextree_mutex;
+static struct mutex *condtree_mutex;
+static struct mutex *rwlocktree_mutex;
+static struct mutex *library_mutex;
+
+
+void
+_thread_fatal(const char *fmt, ...)
+{
+#ifndef THREAD_DIE_SILENT
+ va_list ap;
+
+ if (debug_output == NULL)
+ debug_output = THREAD_DEFAULT_OUTPUT;
+
+ if (thread_initialized)
+ THREAD_PROTECT(
+ {
+ va_start(ap, fmt);
+ vfprintf(debug_output, fmt, ap);
+ va_end(ap);
+ fflush(debug_output);
+ }
+ );
+ else {
+ va_start(ap, fmt);
+ vfprintf(debug_output, fmt, ap);
+ va_end(ap);
+ fflush(debug_output);
+ }
+#endif /* !THREAD_DIE_SILENT */
+ abort();
+}
+
+void
+_thread_debug_printf(unsigned int level, const char *fmt, ...)
+{
+#ifdef THREAD_DEBUG
+ va_list ap;
+
+ if (level > debug_level)
+ return;
+
+ if (thread_initialized)
+ THREAD_PROTECT(
+ {
+ va_start(ap, fmt);
+ vfprintf(debug_output, fmt, ap);
+ va_end(ap);
+ fflush(debug_output);
+ }
+ );
+ else {
+ va_start(ap, fmt);
+ vfprintf(debug_output, fmt, ap);
+ va_end(ap);
+ fflush(debug_output);
+ }
+#endif /* THREAD_DEBUG */
+}
+
+void
+_init_mutexes(void)
+{
+ int m_id = 0;
+
+ mutextree_mutex = xcalloc(1, sizeof(struct mutex));
+ mutextree_mutex->id = --m_id;
+ mutextree_mutex->name = xstrdup("Mutex-Tree Mutex");
+ mutextree_mutex->state = MUTEX_NEVERLOCKED;
+ mutextree_mutex->create_time = time(NULL);
+ mutextree_mutex->creator = xstrdup(__FILE__);
+ mutextree_mutex->line = __LINE__;
+ _mutex_init(mutextree_mutex);
+
+ threadtree_mutex = xcalloc(1, sizeof(struct mutex));
+ threadtree_mutex->id = --m_id;
+ threadtree_mutex->name = xstrdup("Thread-Tree Mutex");
+ threadtree_mutex->state = MUTEX_NEVERLOCKED;
+ threadtree_mutex->create_time = time(NULL);
+ threadtree_mutex->creator = xstrdup(__FILE__);
+ threadtree_mutex->line = __LINE__;
+ _mutex_init(threadtree_mutex);
+
+ condtree_mutex = xcalloc(1, sizeof(struct mutex));
+ condtree_mutex->id = --m_id;
+ condtree_mutex->name = xstrdup("Cond-Tree Mutex");
+ condtree_mutex->state = MUTEX_NEVERLOCKED;
+ condtree_mutex->create_time = time(NULL);
+ condtree_mutex->creator = xstrdup(__FILE__);
+ condtree_mutex->line = __LINE__;
+ _mutex_init(condtree_mutex);
+
+ rwlocktree_mutex = xcalloc(1, sizeof(struct mutex));
+ rwlocktree_mutex->id = --m_id;
+ rwlocktree_mutex->name = xstrdup("RWLock-Tree Mutex");
+ rwlocktree_mutex->state = MUTEX_NEVERLOCKED;
+ rwlocktree_mutex->create_time = time(NULL);
+ rwlocktree_mutex->creator = xstrdup(__FILE__);
+ rwlocktree_mutex->line = __LINE__;
+ _mutex_init(rwlocktree_mutex);
+
+ library_mutex = xcalloc(1, sizeof(struct mutex));
+ library_mutex->id = --m_id;
+ library_mutex->name = xstrdup("Library Call Mutex");
+ library_mutex->state = MUTEX_NEVERLOCKED;
+ library_mutex->create_time = time(NULL);
+ library_mutex->creator = xstrdup(__FILE__);
+ library_mutex->line = __LINE__;
+ _mutex_init(library_mutex);
+}
+
+void
+_catch_signals(void)
+{
+#ifndef WIN32
+ sigset_t ss;
+ int error;
+
+ sigemptyset(&ss);
+
+ /*
+ * These signals should only be accepted by the signal handling thread
+ * (main thread.)
+ */
+ sigaddset(&ss, SIGHUP);
+ sigaddset(&ss, SIGCHLD);
+ sigaddset(&ss, SIGINT);
+ sigaddset(&ss, SIGPIPE);
+ sigaddset(&ss, SIGTERM);
+
+ if ((error = pthread_sigmask(SIG_UNBLOCK, &ss, NULL)) != 0)
+ _thread_fatal("%s: pthread_sigmask(): %s\n",
+ __progname, strerror(error));
+#endif /* !WIN32 */
+}
+
+void
+_block_signals(void)
+{
+#ifndef WIN32
+ sigset_t ss;
+ int error;
+
+ sigfillset(&ss);
+
+ /*
+ * These are the only signals that sub-threads may receive.
+ */
+ sigdelset(&ss, SIGKILL);
+ sigdelset(&ss, SIGSTOP);
+ sigdelset(&ss, SIGSEGV);
+ sigdelset(&ss, SIGBUS);
+ if ((error = pthread_sigmask(SIG_BLOCK, &ss, NULL)) != 0)
+ _thread_fatal("%s: pthread_sigmask(): %s\n",
+ __progname, strerror(error));
+#endif /* !WIN32 */
+}
+
+int
+_thread_cmp(void *arg_a, void *arg_b)
+{
+ struct thread *a = (struct thread *)arg_a;
+ struct thread *b = (struct thread *)arg_b;
+
+ return (a->id - b->id);
+}
+
+int
+_mutex_cmp(void *arg_a, void *arg_b)
+{
+ struct mutex *a = (struct mutex *)arg_a;
+ struct mutex *b = (struct mutex *)arg_b;
+
+ return (a->id - b->id);
+}
+
+int
+_cond_cmp(void *arg_a, void *arg_b)
+{
+ struct cond *a = (struct cond *)arg_a;
+ struct cond *b = (struct cond *)arg_b;
+
+ return (a->id - b->id);
+}
+
+int
+_rwlock_cmp(void *arg_a, void *arg_b)
+{
+ struct rwlock *a = (struct rwlock *)arg_a;
+ struct rwlock *b = (struct rwlock *)arg_b;
+
+ return (a->id - b->id);
+}
+
+void
+_thread_free(struct thread **thread_p)
+{
+ struct thread *thread = *thread_p;
+
+ if (thread->name != NULL)
+ xfree(thread->name);
+ if (thread->creator != NULL)
+ xfree(thread->creator);
+ xfree(*thread_p);
+}
+
+void *
+_thread_start_routine(void *arg)
+{
+ struct thread_start *start = (struct thread_start *)arg;
+ void * (*start_routine)(void *) = start->start_routine;
+ void *real_arg = start->start_arg;
+ struct thread *thread = start->thread;
+ void *ret;
+ int error;
+
+ _block_signals();
+
+ _mutex_lock(threadtree_mutex);
+ thread->sys_thread = pthread_self();
+ RB_INSERT(thread_tree, &thread_tree_head, thread);
+ _mutex_unlock(threadtree_mutex);
+
+ if ((error = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0)
+ _thread_fatal("%s: pthread_setcancelstate(): %s\n",
+ __progname, strerror(error));
+
+ xfree(start);
+
+ ret = (start_routine)(real_arg);
+
+ if (thread->detached) {
+ _mutex_lock(threadtree_mutex);
+ RB_REMOVE(thread_tree, &thread_tree_head, thread);
+ _thread_free(&thread);
+ _mutex_unlock(threadtree_mutex);
+ }
+
+ return (ret);
+}
+
+void
+_mutex_init(struct mutex *mutex)
+{
+ int error;
+
+ mutex->sys_mutex = PTHREAD_MUTEX_INITIALIZER;
+ if ((error = pthread_mutex_init(&mutex->sys_mutex, NULL)) != 0)
+ _thread_fatal("%s: pthread_mutex_init(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+_mutex_lock(struct mutex *mutex)
+{
+ int error;
+
+ if ((error = pthread_mutex_lock(&mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_lock(): %s\n",
+ __progname, strerror(error));
+ mutex->state = MUTEX_LOCKED;
+}
+
+void
+_mutex_unlock(struct mutex *mutex)
+{
+ int error;
+
+ if ((error = pthread_mutex_unlock(&mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_unlock(): %s\n",
+ __progname, strerror(error));
+ mutex->state = MUTEX_UNLOCKED;
+}
+
+void
+_mutex_free(struct mutex **mutex_p)
+{
+ struct mutex *mutex = *mutex_p;
+
+ if (mutex->name != NULL)
+ xfree(mutex->name);
+ if (mutex->creator != NULL)
+ xfree(mutex->creator);
+ xfree(*mutex_p);
+}
+
+void
+_cond_free(struct cond **cond_p)
+{
+ struct cond *cond = *cond_p;
+
+ if (cond->name != NULL)
+ xfree(cond->name);
+ if (cond->creator != NULL)
+ xfree(cond->creator);
+ xfree(*cond_p);
+}
+
+void
+_rwlock_free(struct rwlock **rwlock_p)
+{
+ struct rwlock *rwlock = *rwlock_p;
+
+ if (rwlock->name != NULL)
+ xfree(rwlock->name);
+ if (rwlock->creator != NULL)
+ xfree(rwlock->creator);
+ xfree(*rwlock_p);
+}
+
+
+void
+thread_initialize_debug(unsigned int level, FILE *output)
+{
+ if ((debug_level = level) > THREAD_DBGLVL_MAX)
+ debug_level = THREAD_DBGLVL_MAX;
+ if (output == NULL)
+ debug_output = THREAD_DEFAULT_OUTPUT;
+ else
+ debug_output = output;
+
+ thread_initialize();
+}
+
+void
+thread_initialize(void)
+{
+ struct thread *thread;
+
+ if (thread_initialized)
+ _thread_fatal("%s: thread_init(): Internal error: Thread library already initialized\n",
+ __progname);
+
+ if (debug_output == NULL)
+ debug_output = THREAD_DEFAULT_OUTPUT;
+
+ _init_mutexes();
+
+ _thread_debug_printf(3, "======> INIT thread\n");
+
+ thread = xcalloc(1, sizeof(struct thread));
+ thread->id = next_thread_id++;
+ thread->name = xstrdup("Main Thread");
+ thread->create_time = time(NULL);
+ thread->creator = xstrdup(__FILE__);
+ thread->line = __LINE__;
+ thread->sys_thread = pthread_self();
+ RB_INSERT(thread_tree, &thread_tree_head, thread);
+
+ _catch_signals();
+
+ thread_initialized = 1;
+
+ _thread_debug_printf(4, "======> INIT thread done\n");
+}
+
+void
+thread_shutdown(void)
+{
+ struct thread *thread, *thread_next;
+ struct mutex *mutex, *mutex_next;
+ struct cond *cond, *cond_next;
+ struct rwlock *rwlock, *rwlock_next;
+ int error;
+
+ _thread_debug_printf(3, "======> SHUTDOWN thread\n");
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_shutdown(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ for (rwlock = RB_MIN(rwlock_tree, &rwlock_tree_head);
+ rwlock != NULL;
+ rwlock = rwlock_next) {
+ rwlock_next = RB_NEXT(rwlock_tree, &rwlock_tree_head, rwlock);
+ RB_REMOVE(rwlock_tree, &rwlock_tree_head, rwlock);
+ thread_rwlock_destroy(&rwlock);
+ }
+
+ for (cond = RB_MIN(cond_tree, &cond_tree_head);
+ cond != NULL;
+ cond = cond_next) {
+ cond_next = RB_NEXT(cond_tree, &cond_tree_head, cond);
+ RB_REMOVE(cond_tree, &cond_tree_head, cond);
+ thread_cond_destroy(&cond);
+ }
+
+ for (mutex = RB_MIN(mutex_tree, &mutex_tree_head);
+ mutex != NULL;
+ mutex = mutex_next) {
+ mutex_next = RB_NEXT(mutex_tree, &mutex_tree_head, mutex);
+ RB_REMOVE(mutex_tree, &mutex_tree_head, mutex);
+ thread_mutex_destroy(&mutex);
+ }
+
+ for (thread = RB_MIN(thread_tree, &thread_tree_head);
+ thread != NULL;
+ thread = thread_next) {
+ thread_next = RB_NEXT(thread_tree, &thread_tree_head, thread);
+ RB_REMOVE(thread_tree, &thread_tree_head, thread);
+ _thread_free(&thread);
+ }
+
+ if ((error = pthread_mutex_destroy(&library_mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(%s): %s\n",
+ __progname, library_mutex->name,
+ strerror(error));
+ _mutex_free(&library_mutex);
+ if ((error = pthread_mutex_destroy(&rwlocktree_mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(%s): %s\n",
+ __progname, rwlocktree_mutex->name,
+ strerror(error));
+ _mutex_free(&rwlocktree_mutex);
+ if ((error = pthread_mutex_destroy(&condtree_mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(%s): %s\n",
+ __progname, condtree_mutex->name,
+ strerror(error));
+ _mutex_free(&condtree_mutex);
+ if ((error = pthread_mutex_destroy(&threadtree_mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(%s): %s\n",
+ __progname, threadtree_mutex->name,
+ strerror(error));
+ _mutex_free(&threadtree_mutex);
+ if ((error = pthread_mutex_destroy(&mutextree_mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(%s): %s\n",
+ __progname, mutextree_mutex->name,
+ strerror(error));
+ _mutex_free(&mutextree_mutex);
+
+ thread_initialized = 0;
+
+ _thread_debug_printf(4, "======> SHUTDOWN thread done\n");
+}
+
+struct thread *
+thread_create_c(const char *name, void *(*start_routine)(void *),
+ void *start_routine_arg, int detached, unsigned int stack,
+ const char *file, unsigned int line)
+{
+ struct thread *thread = NULL;
+ struct thread_start *thread_start;
+ pthread_attr_t attr;
+ int error;
+ size_t stacksize;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_create(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> CREATE THREAD: %s:%u: '%s' (%stached)\n",
+ file, line, name, detached ? "de" : "at");
+
+ if (stack > 0)
+ stacksize = stack;
+ else
+ stacksize = THREAD_DEFAULT_STACKSIZE;
+
+ thread = xcalloc(1, sizeof(struct thread));
+ thread_start = xcalloc(1, sizeof(struct thread_start));
+ if ((error = pthread_attr_init(&attr)) != 0)
+ _thread_fatal("%s: pthread_attr_init(%s): %s\n",
+ __progname, name, strerror(error));
+
+ _mutex_lock(threadtree_mutex);
+ thread->id = next_thread_id++;
+ _mutex_unlock(threadtree_mutex);
+ thread->name = xstrdup(name);
+ thread->create_time = time(NULL);
+ thread->creator = xstrdup(file);
+ thread->line = line;
+ thread->detached = detached;
+
+ thread_start->start_routine = start_routine;
+ thread_start->start_arg = start_routine_arg;
+ thread_start->thread = thread;
+
+ if ((error = pthread_attr_setstacksize(&attr, stacksize)) != 0)
+ _thread_fatal("%s: pthread_attr_setstacksize(%s): %s\n",
+ __progname, name, strerror(error));
+ if ((error = pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED)) != 0)
+ _thread_fatal("%s: pthread_attr_setinheritsched(%s): %s\n",
+ __progname, name, strerror(error));
+ if (thread->detached) {
+ if ((error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) != 0)
+ _thread_fatal("%s: pthread_attr_setdetachstate(%s): %s\n",
+ __progname, name, strerror(error));
+ }
+
+ if ((error = pthread_create(&thread->sys_thread, &attr,
+ _thread_start_routine, thread_start)) != 0)
+ _thread_fatal("%s: pthread_create(%s): %s\n",
+ __progname, name, strerror(error));
+
+ if ((error = pthread_attr_destroy(&attr)) != 0)
+ _thread_fatal("%s: pthread_attr_destroy(): %s\n",
+ __progname, strerror(error));
+
+ _thread_debug_printf(4, "======> CREATE THREAD done: '%s'(%d)\n",
+ thread->name, thread->id);
+
+ return (thread);
+}
+
+struct thread *
+thread_self_c(const char *file, unsigned int line)
+{
+ struct thread *thread = NULL;
+ pthread_t sys_thread;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_self(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ sys_thread = pthread_self();
+
+ _mutex_lock(threadtree_mutex);
+ RB_FOREACH(thread, thread_tree, &thread_tree_head) {
+ if (thread && pthread_equal(sys_thread, thread->sys_thread))
+ break;
+ }
+ _mutex_unlock(threadtree_mutex);
+
+ if (thread == NULL)
+ _thread_fatal("%s: thread_self(): In %s:%u: No thread exist (anymore)\n",
+ __progname, file, line);
+
+ return (thread);
+}
+
+void
+thread_rename(const char *name)
+{
+ struct thread *thread;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rename(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ thread = thread_self();
+ if (thread->name != NULL)
+ xfree(thread->name);
+ thread->name = xstrdup(name);
+}
+
+void
+thread_join_c(struct thread **thread_p, const char *file, unsigned int line)
+{
+ struct thread *thread = NULL;
+ int error;
+ void *ret;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_join(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (thread_p == NULL || (thread = *thread_p) == NULL || thread == NULL)
+ _thread_fatal("%s: thread_join(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> THREAD JOIN: %s:%u: '%s'(%d) (from %s:%u, age %ds)\n",
+ file, line, thread->name, thread->id,
+ thread->creator, thread->line,
+ (int)(time(NULL) - thread->create_time));
+
+ if ((error = pthread_join(thread->sys_thread, &ret)) != 0)
+ _thread_fatal("%s: pthread_join(): %s\n",
+ __progname, strerror(error));
+
+ _mutex_lock(threadtree_mutex);
+ RB_REMOVE(thread_tree, &thread_tree_head, thread);
+ _thread_free(thread_p);
+ _mutex_unlock(threadtree_mutex);
+
+ _thread_debug_printf(4, "======> THREAD JOIN done\n");
+}
+
+void
+thread_exit_c(int val, const char *file, unsigned int line)
+{
+ struct thread *thread;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_exit(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ thread = thread_self();
+
+ _thread_debug_printf(3, "======> THREAD EXIT: %s:%u: '%s'(%d) (from %s:%u, age %ds)\n",
+ file, line, thread->name, thread->id,
+ thread->creator, thread->line,
+ (int)(time(NULL) - thread->create_time));
+
+#ifdef THREAD_CHECK_MUTEXES
+ if (debug_level > 0) {
+ struct mutex *mutex;
+
+ _mutex_lock(mutextree_mutex);
+ RB_FOREACH(mutex, mutex_tree, &mutex_tree_head) {
+ if (mutex->state == MUTEX_LOCKED &&
+ mutex->thread_id == thread->id)
+ _thread_debug_printf(1, "#> THREAD EXIT: Thread '%s'(%d) from %s:%u exiting in %s:%u without unlocking mutex '%s'(%d)\n",
+ thread->name, thread->id, thread->creator, thread->line, file, line, mutex->name, mutex->id);
+ }
+ _mutex_unlock(mutextree_mutex);
+ }
+#endif /* THREAD_CHECK_MUTEXES */
+
+ if (thread->detached) {
+ _mutex_lock(threadtree_mutex);
+ RB_REMOVE(thread_tree, &thread_tree_head, thread);
+ _thread_free(&thread);
+ _mutex_unlock(threadtree_mutex);
+ }
+
+ _thread_debug_printf(4, "======> THREAD exiting\n");
+
+ pthread_exit((void *)&val);
+}
+
+struct mutex *
+thread_mutex_create_c(const char *name, const char *file, unsigned int line)
+{
+ struct mutex *mutex = NULL;
+ struct thread *thread = NULL;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_mutex_create(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ thread = thread_self();
+ _thread_debug_printf(3, "======> CREATE MUTEX: %s:%u: %s\n",
+ file, line, name);
+
+ mutex = xcalloc(1, sizeof(struct mutex));
+ mutex->thread_id = thread->id;
+ mutex->name = xstrdup(name);
+ mutex->state = MUTEX_NEVERLOCKED;
+ mutex->create_time = time(NULL);
+ mutex->creator = xstrdup(file);
+ mutex->line = line;
+ _mutex_init(mutex);
+ _mutex_lock(mutextree_mutex);
+ mutex->id = next_mutex_id++;
+ RB_INSERT(mutex_tree, &mutex_tree_head, mutex);
+ _mutex_unlock(mutextree_mutex);
+
+ _thread_debug_printf(4, "======> CREATE MUTEX done: '%s'(%d)\n",
+ mutex->name, mutex->id);
+
+ return (mutex);
+}
+
+void
+thread_mutex_lock_c(struct mutex *mutex, const char *file, unsigned int line)
+{
+ struct thread *thread;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_mutex_lock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (mutex == NULL)
+ _thread_fatal("%s: thread_mutex_lock(): Internal error: Bad argument\n",
+ __progname);
+
+ thread = thread_self();
+ _thread_debug_printf(3, "======> LOCK MUTEX: %s:%u: '%s'(%d) thread '%s'%d\n",
+ file, line, mutex->name, mutex->id,
+ thread->name, thread->id);
+
+#ifdef THREAD_CHECK_MUTEXES
+ if (debug_level > 0) {
+ struct mutex *mtx;
+ unsigned int locks = 0;
+
+ _mutex_lock(mutextree_mutex);
+ RB_FOREACH(mtx, mutex_tree, &mutex_tree_head) {
+ if (mtx->state == MUTEX_LOCKED &&
+ mtx->thread_id == thread->id) {
+ locks++;
+ if (mtx->id == mutex->id)
+ _thread_debug_printf(1, "#> LOCK MUTEX: DEADLOCK DETECTED! Thread '%s'(%d) locks mutex '%s'(%d) twice in %s:%u\n",
+ thread->name, thread->id, mutex->name, mutex->id, file, line);
+ }
+ }
+ _mutex_unlock(mutextree_mutex);
+
+ if (locks > 0)
+ _thread_debug_printf(1, "#> LOCK MUTEX: Warning: Thread '%s'(%d) already has %u locks\n",
+ thread->name, thread->id, locks);
+ }
+#endif /* THREAD_CHECK_MUTEXES */
+
+ _mutex_lock(mutex);
+ mutex->thread_id = thread->id;
+
+ _thread_debug_printf(4, "======> LOCK MUTEX done: '%s'(%d)\n",
+ mutex->name, mutex->id);
+}
+
+void
+thread_mutex_unlock_c(struct mutex *mutex, const char *file, unsigned int line)
+{
+ struct thread *thread;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_mutex_unlock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (mutex == NULL)
+ _thread_fatal("%s: thread_mutex_unlock(): Internal error: Bad argument\n",
+ __progname);
+
+ thread = thread_self();
+ _thread_debug_printf(3, "======> UNLOCK MUTEX: %s:%u: '%s'(%d) thread '%s'(%d)\n",
+ file, line, mutex->name, mutex->id,
+ thread->name, thread->id);
+
+#ifdef THREAD_CHECK_MUTEXES
+ if (debug_level > 0) {
+ struct mutex *mtx;
+
+ _mutex_lock(mutextree_mutex);
+ RB_FOREACH(mtx, mutex_tree, &mutex_tree_head) {
+ if (mtx->state == MUTEX_LOCKED &&
+ mtx->thread_id != thread->id &&
+ mtx->id == mutex->id)
+ _thread_debug_printf(1, "#> UNLOCK MUTEX: ILLEGAL UNLOCK! Thread '%s'(%d) tries to unlock mutex '%s'(%d) without owning it in %s:%u\n",
+ thread->name, thread->id, mutex->name, mutex->id, file, line);
+ }
+ _mutex_unlock(mutextree_mutex);
+ }
+#endif /* THREAD_CHECK_MUTEXES */
+
+ _mutex_unlock(mutex);
+ mutex->thread_id = thread->id;
+
+ _thread_debug_printf(4, "======> UNLOCK MUTEX done: '%s'(%d)\n",
+ mutex->name, mutex->id);
+}
+
+void
+thread_mutex_destroy_c(struct mutex **mutex_p,
+ const char *file, unsigned int line)
+{
+ struct mutex *mutex = NULL;
+ struct thread *thread;
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_mutex_destroy(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (mutex_p == NULL || (mutex = *mutex_p) == NULL || mutex == NULL)
+ _thread_fatal("%s: thread_mutex_destroy(): Internal error: Bad argument\n",
+ __progname);
+
+ thread = thread_self();
+ _thread_debug_printf(3, "======> MUTEX DESTROY: %s:%u: '%s'(%d) (from %s:%u, age %ds) thread '%s'(%d)\n",
+ file, line, mutex->name, mutex->id,
+ mutex->creator, mutex->line,
+ (int)(time(NULL) - mutex->create_time),
+ thread->name, thread->id);
+
+ if (mutex->state == MUTEX_NEVERLOCKED)
+ _thread_debug_printf(2, ">>>>> Mutex '%s'(%d) from %s:%u was never locked\n",
+ mutex->name, mutex->id, mutex->creator,
+ mutex->line);
+
+ if ((error = pthread_mutex_destroy(&mutex->sys_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(): %s\n",
+ __progname, strerror(error));
+ _mutex_lock(mutextree_mutex);
+ RB_REMOVE(mutex_tree, &mutex_tree_head, mutex);
+ _mutex_free(mutex_p);
+ _mutex_unlock(mutextree_mutex);
+
+ _thread_debug_printf(4, "======> MUTEX DESTROY done\n");
+}
+
+struct cond *
+thread_cond_create_c(const char *name, const char *file, unsigned int line)
+{
+ struct cond *cond = NULL;
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_create(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> CREATE COND: %s:%u: %s\n",
+ file, line, name);
+
+ cond = xcalloc(1, sizeof(struct cond));
+ cond->name = xstrdup(name);
+ cond->create_time = time(NULL);
+ cond->creator = xstrdup(file);
+ cond->line = line;
+ if ((error = pthread_cond_init(&cond->sys_cond, NULL)) != 0)
+ _thread_fatal("%s: pthread_cond_init(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_mutex_init(&cond->cond_mutex, NULL)) != 0)
+ _thread_fatal("%s: pthread_mutex_init(): %s\n",
+ __progname, strerror(error));
+ _mutex_lock(condtree_mutex);
+ cond->id = next_cond_id++;
+ RB_INSERT(cond_tree, &cond_tree_head, cond);
+ _mutex_unlock(condtree_mutex);
+
+ _thread_debug_printf(4, "======> CREATE COND done: '%s'(%d)\n",
+ cond->name, cond->id);
+
+ return (cond);
+}
+
+void
+thread_cond_signal_c(struct cond *cond, const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_signal(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (cond == NULL)
+ _thread_fatal("%s: thread_cond_signal(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> SIGNAL COND: %s:%u: '%s'(%d)\n",
+ file, line, cond->name, cond->id);
+
+ if ((error = pthread_cond_signal(&cond->sys_cond)) != 0)
+ _thread_fatal("%s: pthread_cond_signal(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+thread_cond_broadcast_c(struct cond *cond, const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_broadcast(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (cond == NULL)
+ _thread_fatal("%s: thread_cond_broadcast(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> BROADCAST COND: %s:%u: '%s'(%d)\n",
+ file, line, cond->name, cond->id);
+
+ if ((error = pthread_cond_broadcast(&cond->sys_cond)) != 0)
+ _thread_fatal("%s: pthread_cond_broadcast(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+thread_cond_wait_c(struct cond *cond, const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_wait(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (cond == NULL)
+ _thread_fatal("%s: thread_cond_wait(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> COND WAIT: %s:%u: '%s'(%d)\n",
+ file, line, cond->name, cond->id);
+
+ if ((error = pthread_mutex_lock(&cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_lock(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_cond_wait(&cond->sys_cond,
+ &cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_cond_wait(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_mutex_unlock(&cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_unlock(): %s\n",
+ __progname, strerror(error));
+
+ _thread_debug_printf(4, "======> COND WAIT done: '%s'(%d)\n",
+ cond->name, cond->id);
+}
+
+void
+thread_cond_timedwait_c(struct cond *cond, unsigned int ms,
+ const char *file, unsigned int line)
+{
+ int error;
+ struct timespec tv;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_timedwait(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (cond == NULL)
+ _thread_fatal("%s: thread_cond_timedwait(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> COND TIMEDWAIT (%ums): %s:%u: '%s'(%d)\n",
+ ms, file, line, cond->name, cond->id);
+
+ tv.tv_sec = ms / 1000;
+ tv.tv_nsec = (ms - tv.tv_sec * 1000) * 1000000;
+
+ if ((error = pthread_mutex_lock(&cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_lock(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_cond_timedwait(&cond->sys_cond, &cond->cond_mutex,
+ &tv)) != 0)
+ _thread_fatal("%s: pthread_cond_wait(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_mutex_unlock(&cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_unlock(): %s\n",
+ __progname, strerror(error));
+
+ _thread_debug_printf(4, "======> COND TIMEDWAIT (%ums) done: '%s'(%d)\n",
+ ms, cond->name, cond->id);
+}
+
+void
+thread_cond_destroy_c(struct cond **cond_p,
+ const char *file, unsigned int line)
+{
+ int error;
+ struct cond *cond = NULL;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_cond_destroy(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (cond_p == NULL || (cond = *cond_p) == NULL || cond == NULL)
+ _thread_fatal("%s: thread_cond_destroy(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> COND DESTROY: %s:%u: '%s'(%d) (from %s:%u, age %ds)\n",
+ file, line, cond->name, cond->id, cond->creator,
+ cond->line,
+ (int)(time(NULL) - cond->create_time));
+
+ if ((error = pthread_mutex_destroy(&cond->cond_mutex)) != 0)
+ _thread_fatal("%s: pthread_mutex_destroy(): %s\n",
+ __progname, strerror(error));
+ if ((error = pthread_cond_destroy(&cond->sys_cond)) != 0)
+ _thread_fatal("%s: pthread_cond_destroy(): %s\n",
+ __progname, strerror(error));
+ _mutex_lock(condtree_mutex);
+ RB_REMOVE(cond_tree, &cond_tree_head, cond);
+ _cond_free(cond_p);
+ _mutex_unlock(condtree_mutex);
+
+ _thread_debug_printf(4, "======> COND DESTROY done\n");
+}
+
+struct rwlock *
+thread_rwlock_create_c(const char *name, const char *file, unsigned int line)
+{
+ struct rwlock *rwlock = NULL;
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rwlock_create(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> CREATE RWLOCK: %s:%u: %s\n",
+ file, line, name);
+
+ rwlock = xcalloc(1, sizeof(struct rwlock));
+ rwlock->name = xstrdup(name);
+ rwlock->create_time = time(NULL);
+ rwlock->creator = xstrdup(file);
+ rwlock->line = line;
+ if ((error = pthread_rwlock_init(&rwlock->sys_rwlock, NULL)) != 0)
+ _thread_fatal("%s: pthread_rwlock_init(): %s\n",
+ __progname, strerror(error));
+ _mutex_lock(rwlocktree_mutex);
+ rwlock->id = next_rwlock_id++;
+ RB_INSERT(rwlock_tree, &rwlock_tree_head, rwlock);
+ _mutex_unlock(rwlocktree_mutex);
+
+ _thread_debug_printf(4, "======> CREATE RWLOCK done: '%s'(%d)\n",
+ rwlock->name, rwlock->id);
+
+ return (rwlock);
+}
+
+void
+thread_rwlock_rlock_c(struct rwlock *rwlock,
+ const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rwlock_rlock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> RWLOCK READ: %s:%u: '%s'(%d)\n",
+ file, line, rwlock->name, rwlock->id);
+
+ if ((error = pthread_rwlock_rdlock(&rwlock->sys_rwlock)) != 0)
+ _thread_fatal("%s: pthread_rwlock_rdlock(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+thread_rwlock_wlock_c(struct rwlock *rwlock,
+ const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rwlock_wlock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> RWLOCK WRITE: %s:%u: '%s'(%d)\n",
+ file, line, rwlock->name, rwlock->id);
+
+ if ((error = pthread_rwlock_wrlock(&rwlock->sys_rwlock)) != 0)
+ _thread_fatal("%s: pthread_rwlock_wrlock(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+thread_rwlock_unlock_c(struct rwlock *rwlock,
+ const char *file, unsigned int line)
+{
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rwlock_unlock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> RWLOCK UNLOCK: %s:%u: '%s'(%d)\n",
+ file, line, rwlock->name, rwlock->id);
+
+ if ((error = pthread_rwlock_unlock(&rwlock->sys_rwlock)) != 0)
+ _thread_fatal("%s: pthread_rwlock_unlock(): %s\n",
+ __progname, strerror(error));
+}
+
+void
+thread_rwlock_destroy_c(struct rwlock **rwlock_p,
+ const char *file, unsigned int line)
+{
+ struct rwlock *rwlock = NULL;
+ int error;
+
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_rwlock_destroy(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ if (rwlock_p == NULL || (rwlock = *rwlock_p) == NULL || rwlock == NULL)
+ _thread_fatal("%s: thread_rwlock_destroy(): Internal error: Bad argument\n",
+ __progname);
+
+ _thread_debug_printf(3, "======> RWLOCK DESTROY: %s:%u: '%s'(%d) (from %s:%u, age %ds)\n",
+ file, line, rwlock->name, rwlock->id,
+ rwlock->creator, rwlock->line,
+ (int)(time(NULL) - rwlock->create_time));
+
+ if ((error = pthread_rwlock_destroy(&rwlock->sys_rwlock)) != 0)
+ _thread_fatal("%s: pthread_rwlock_destroy(): %s\n",
+ __progname, strerror(error));
+ _mutex_lock(rwlocktree_mutex);
+ RB_REMOVE(rwlock_tree, &rwlock_tree_head, rwlock);
+ _rwlock_free(rwlock_p);
+ _mutex_unlock(rwlocktree_mutex);
+
+ _thread_debug_printf(4, "======> RWLOCK DESTROY done\n");
+}
+
+void
+thread_sleep_ms(unsigned int ms)
+{
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_sleep(): Internal error: Thread library not initialized\n",
+ __progname);
+
+#ifdef WIN32
+ Sleep(ms);
+#else
+# ifdef HAVE_NANOSLEEP
+ {
+ struct timespec tv_sleep;
+ struct timespec tv_remaining;
+ int ret;
+
+ tv_sleep.tv_sec = ms / 1000;
+ tv_sleep.tv_nsec = (ms % 1000) * 1000000;
+
+ while ((ret = nanosleep(&tv_sleep, &tv_remaining)) != 0 &&
+ errno == EINTR) {
+ tv_sleep.tv_sec = tv_remaining.tv_sec;
+ tv_sleep.tv_nsec = tv_remaining.tv_nsec;
+ }
+ }
+# else
+ poll(NULL, 0, ms);
+# endif /* HAVE_NANOSLEEP */
+#endif /* WIN32 */
+}
+
+void
+thread_library_lock(void)
+{
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_library_lock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _mutex_lock(library_mutex);
+}
+
+void
+thread_library_unlock(void)
+{
+ if (!thread_initialized)
+ _thread_fatal("%s: thread_library_unlock(): Internal error: Thread library not initialized\n",
+ __progname);
+
+ _mutex_unlock(library_mutex);
+}
Added: experimental/moritz/thread/thread.h
===================================================================
--- experimental/moritz/thread/thread.h (rev 0)
+++ experimental/moritz/thread/thread.h 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,230 @@
+/*
+ * libthread - Cross platform thread and syncronization library, with
+ * extensive error checking and debugging facility.
+ * Uses POSIX threads (libpthread, or pthread-win32 on
+ * Windows.)
+ *
+ * Library design and ideas adapted from libicethread, written by
+ * Jack Moffitt for the Icecast project, which is Copyright 2000-2004
+ * and licensed under the terms of the LGPL - available at
+ * http://www.icecast.org/. Licensed and used with permission.
+ *
+ * Copyright (C) 2007 Moritz Grimm <mgrimm at gmx.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __THREAD_H__
+#define __THREAD_H__
+
+/*
+ * Define THREAD_DEBUG to get the thread_debug_initialize_debug() function,
+ * which enables debugging output of /level/s between 0 and 4, inclusive.
+ * The higher the number, the more verbose is the output. A value of 0 is
+ * equivalent to using thread_initialize().
+ * Define THREAD_CHECK_MUTEXES to perform additional checks on mutexes.
+ * To make libthread abort() silently and never output anything, define
+ * THREAD_DIE_SILENT (will be undefined if THREAD_DEBUG is defined.)
+ */
+/* #define THREAD_DEBUG 1 */
+/* #define THREAD_CHECK_MUTEXES 1 */
+/* #define THREAD_DIE_SILENT 1 */
+
+
+#define THREAD_DEFAULT_STACKSIZE (512 * 1024)
+#define THREAD_DEFAULT_OUTPUT stderr
+
+#define THREAD_ATTACHED 0
+#define THREAD_DETACHED 1
+
+
+typedef struct thread *thread_t;
+typedef struct mutex *mutex_t;
+typedef struct cond *cond_t;
+typedef struct rwlock *rwlock_t;
+
+
+/*
+ * Library initialization and shutdown.
+ */
+
+void thread_initialize(void);
+#ifdef THREAD_DEBUG
+/* Output stream defaults to standard error, if NULL. */
+void thread_initialize_debug(unsigned int /* level */,
+ FILE * /* output stream */);
+#endif /* THREAD_DEBUG */
+void thread_shutdown(void);
+
+
+/*
+ * Threads
+ */
+
+#define thread_create(n, r, a, d) \
+ thread_create_c(n, r, a, d, 0, __FILE__, __LINE__)
+#define thread_create_with_stacksize(n, r, a, d, s) \
+ thread_create_c(n, r, a, d, s, __FILE__, __LINE__)
+thread_t thread_create_c(const char * /* name */,
+ void *(*)(void *) /* start routine */,
+ void * /* start routine argument */,
+ int /* run detached */,
+ unsigned int /* stack size, 0 for default */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_self() \
+ thread_self_c(__FILE__, __LINE__)
+thread_t thread_self_c(const char * /* file */,
+ unsigned int /* line */);
+
+void thread_rename(const char * /* name */);
+
+#define thread_join(t) \
+ thread_join_c(t, __FILE__, __LINE__)
+void thread_join_c(thread_t * /* thread pointer */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_exit(t) \
+ thread_exit_c(t, __FILE__, __LINE__)
+void thread_exit_c(int /* exit value */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+
+/*
+ * Mutexes
+ */
+
+#define thread_mutex_create(n) \
+ thread_mutex_create_c(n, __FILE__, __LINE__)
+mutex_t thread_mutex_create_c(const char * /* name */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_mutex_lock(x) \
+ thread_mutex_lock_c(x, __FILE__, __LINE__)
+void thread_mutex_lock_c(mutex_t /* mutex */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_mutex_unlock(x) \
+ thread_mutex_unlock_c(x, __FILE__, __LINE__)
+void thread_mutex_unlock_c(mutex_t /* mutex */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_mutex_destroy(x) \
+ thread_mutex_destroy_c(x, __FILE__, __LINE__)
+void thread_mutex_destroy_c(mutex_t * /* mutex pointer */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+
+/*
+ * Conds
+ */
+
+#define thread_cond_create(n) \
+ thread_cond_create_c(n, __FILE__, __LINE__)
+cond_t thread_cond_create_c(const char * /* name */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_cond_signal(c) \
+ thread_cond_signal_c(c, __FILE__, __LINE__)
+void thread_cond_signal_c(cond_t /* cond */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_cond_broadcast(c) \
+ thread_cond_broadcast_c(c, __FILE__, __LINE__)
+void thread_cond_broadcast_c(cond_t /* cond */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_cond_wait(c) \
+ thread_cond_wait_c(c, __FILE__, __LINE__)
+void thread_cond_wait_c(cond_t /* cond */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_cond_timedwait(c, s) \
+ thread_cond_timedwait_c(c, s, __FILE__, __LINE__)
+void thread_cond_timedwait_c(cond_t /* cond */,
+ unsigned int /* milliseconds */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_cond_destroy(c) \
+ thread_cond_destroy_c(c, __FILE__, __LINE__)
+void thread_cond_destroy_c(cond_t * /* cond pointer */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+
+/*
+ * RW locks
+ */
+
+#define thread_rwlock_create(n) \
+ thread_rwlock_create_c(n, __FILE__, __LINE__)
+rwlock_t thread_rwlock_create_c(const char * /* name */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_rwlock_rlock(l) \
+ thread_rwlock_rlock_c(l, __FILE__, __LINE__)
+void thread_rwlock_rlock_c(rwlock_t /* rwlock */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_rwlock_wlock(l) \
+ thread_rwlock_wlock_c(l, __FILE__, __LINE__)
+void thread_rwlock_wlock_c(rwlock_t /* rwlock */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_rwlock_unlock(l) \
+ thread_rwlock_unlock_c(l, __FILE__, __LINE__)
+void thread_rwlock_unlock_c(rwlock_t /* rwlock */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+#define thread_rwlock_destroy(l) \
+ thread_rwlock_destroy_c(l, __FILE__, __LINE__)
+void thread_rwlock_destroy_c(rwlock_t * /* rwlock pointer */,
+ const char * /* file */,
+ unsigned int /* line */);
+
+
+/*
+ * Miscellaneous
+ */
+
+/* The thread_sleep() macro takes microseconds for backwards-compatibility. */
+#define thread_sleep(t) \
+ thread_sleep_ms(t / 1000)
+void thread_sleep_ms(unsigned int /* milliseconds */);
+
+void thread_library_lock(void);
+void thread_library_unlock(void);
+#define THREAD_PROTECT(code) \
+ do { \
+ thread_library_lock(); \
+ code; \
+ thread_library_unlock(); \
+ } while (0)
+
+#endif /* __THREAD_H__ */
Added: experimental/moritz/thread/win32/libthread.sln
===================================================================
--- experimental/moritz/thread/win32/libthread.sln (rev 0)
+++ experimental/moritz/thread/win32/libthread.sln 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,53 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libthread", "libthread.vcproj", "{ECBE0684-1DAB-4018-9830-706C9BD0A25E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0} = {ED9F1811-718B-40CE-95FA-E9409F77D8F0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxalloc", "..\..\xalloc\win32\libxalloc.vcproj", "{ED9F1811-718B-40CE-95FA-E9409F77D8F0}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B} = {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthread", "..\..\pthreads\pthread.vcproj", "{0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Debug Static = Debug Static
+ Release = Release
+ Release Static = Release Static
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Debug.ActiveCfg = Debug|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Debug.Build.0 = Debug|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Debug Static.ActiveCfg = Debug|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Debug Static.Build.0 = Debug|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Release.ActiveCfg = Release|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Release.Build.0 = Release|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Release Static.ActiveCfg = Release|Win32
+ {ECBE0684-1DAB-4018-9830-706C9BD0A25E}.Release Static.Build.0 = Release|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Debug.ActiveCfg = Debug|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Debug.Build.0 = Debug|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Debug Static.ActiveCfg = Debug|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Debug Static.Build.0 = Debug|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Release.ActiveCfg = Release|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Release.Build.0 = Release|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Release Static.ActiveCfg = Release|Win32
+ {ED9F1811-718B-40CE-95FA-E9409F77D8F0}.Release Static.Build.0 = Release|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Debug.ActiveCfg = Debug|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Debug.Build.0 = Debug|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Debug Static.ActiveCfg = Debug Static|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Debug Static.Build.0 = Debug Static|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Release.ActiveCfg = Release|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Release.Build.0 = Release|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Release Static.ActiveCfg = Release Static|Win32
+ {0ACFE379-35EA-4FDC-B0F1-40C9D0E7EE2B}.Release Static.Build.0 = Release Static|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
Added: experimental/moritz/thread/win32/libthread.vcproj
===================================================================
--- experimental/moritz/thread/win32/libthread.vcproj (rev 0)
+++ experimental/moritz/thread/win32/libthread.vcproj 2007-07-30 00:46:55 UTC (rev 13396)
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="libthread"
+ ProjectGUID="{ECBE0684-1DAB-4018-9830-706C9BD0A25E}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\xalloc;..\..\compat;..\..\pthreads"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;THREAD_DEBUG;THREAD_CHECK_MUTEXES"
+ StringPooling="TRUE"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/libthread.lib"
+ IgnoreDefaultLibraryNames=""/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\xalloc;..\..\compat;..\..\pthreads"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/libthread.lib"
+ IgnoreDefaultLibraryNames=""/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\thread.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\thread.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
More information about the commits
mailing list