[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