Subject: Re: Threading problems
To: Jaromir Dolecek <jdolecek@NetBSD.org>
From: Nathan J. Williams <nathanw@wasabisystems.com>
List: tech-userlevel
Date: 12/06/2004 14:13:03
"Nathan J. Williams" <nathanw@wasabisystems.com> writes:
> Thinking about this more, a better answer might be for <pthread.h> to
> #define pthread_mutex_lock(x) to __libc_mutex_lock(x), so that ~all
> code that is written to use locking routines from pthread.h will go
> through the libc redirection by default, instead of making them
> rewrite to mutex_lock() [that those names are used in libc is
> something of a historical accident involving the import of Sun code
> before pthreads were firmly entrenched as the only real thread
> interface].
Okay, here's my proposed patch to implement this scheme. It seems to
work on my systems, and I was able to rebuild a bunch of pkgsrc with
no ill effects on the programs. I was able to remove the libpthread
dependancy from, for example pkgsrc/graphics/gd, which is a prime
example of "defensive-only" threading.
Following this, I'll fold threadlib.h back into an intewrnal libc
heade, and switch xsrc back to using pthread.h and standard functions
for its threading. As far as I know, libc and xsrc's Xthreads.h are
the only consumers of threadlib.h.
- Nathan
Index: lib/libpthread/pthread.h
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread.h,v
retrieving revision 1.16
diff -u -r1.16 pthread.h
--- lib/libpthread/pthread.h 7 Dec 2003 20:29:07 -0000 1.16
+++ lib/libpthread/pthread.h 6 Dec 2004 19:00:27 -0000
@@ -220,4 +220,113 @@
#define PTHREAD_RWLOCK_INITIALIZER _PTHREAD_RWLOCK_INITIALIZER
#define PTHREAD_SPINLOCK_INITIALIZER _PTHREAD_SPINLOCK_INITIALIZER
+/*
+ * Use macros to rename many pthread functions to the corresponding
+ * libc symbols which are either trivial/no-op stubs or the real
+ * thing, depending on whether libpthread is linked in to the
+ * program. This permits code, particularly libraries that do not
+ * directly use threads but want to be thread-safe in the presence of
+ * threaded callers, to use pthread mutexes and the like without
+ * unnecessairly including libpthread in their linkage.
+ *
+ * Left out of this list are functions that can't sensibly be trivial
+ * or no-op stubs in a single-threaded process (pthread_create,
+ * pthread_kill, pthread_detach), functions that normally block and
+ * wait for another thread to do something (pthread_join,
+ * pthread_cond_wait, pthread_cond_timedwait), and functions that
+ * don't make sense without the previous functions (pthread_attr_*).
+ *
+ * The rename is done as:
+ * #define pthread_foo __libc_foo
+ * instead of
+ * #define pthread_foo(x) __libc_foo((x))
+ * in order that taking the address of the function ("func =
+ * &pthread_foo;") continue to work.
+ *
+ * POSIX/SUSv3 requires that its functions exist as functions (even if
+ * macro versions exist) and specifically that "#undef pthread_foo" is
+ * legal and should not break anything. Code that does such will not
+ * successfully get the stub behavior implemented here and will
+ * require libpthread to be linked in.
+ */
+
+#ifndef __LIBPTHREAD_SOURCE__
+__BEGIN_DECLS
+int __libc_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int __libc_mutex_lock(pthread_mutex_t *);
+int __libc_mutex_trylock(pthread_mutex_t *);
+int __libc_mutex_unlock(pthread_mutex_t *);
+int __libc_mutex_destroy(pthread_mutex_t *);
+
+int __libc_mutexattr_init(pthread_mutexattr_t *);
+int __libc_mutexattr_settype(pthread_mutexattr_t *, int);
+int __libc_mutexattr_destroy(pthread_mutexattr_t *);
+__END_DECLS
+
+#define pthread_mutex_init __libc_mutex_init
+#define pthread_mutex_lock __libc_mutex_lock
+#define pthread_mutex_trylock __libc_mutex_trylock
+#define pthread_mutex_unlock __libc_mutex_unlock
+#define pthread_mutex_destroy __libc_mutex_destroy
+
+#define pthread_mutexattr_init __libc_mutexattr_init
+#define pthread_mutexattr_settype __libc_mutexattr_settype
+#define pthread_mutexattr_destroy __libc_mutexattr_destroy
+
+__BEGIN_DECLS
+int __libc_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+int __libc_cond_signal(pthread_cond_t *);
+int __libc_cond_broadcast(pthread_cond_t *);
+int __libc_cond_destroy(pthread_cond_t *);
+__END_DECLS
+
+#define pthread_cond_init __libc_cond_init
+#define pthread_cond_signal __libc_cond_signal
+#define pthread_cond_broadcast __libc_cond_broadcast
+#define pthread_cond_destroy __libc_cond_destroy
+
+__BEGIN_DECLS
+int __libc_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
+int __libc_rwlock_rdlock(pthread_rwlock_t *);
+int __libc_rwlock_wrlock(pthread_rwlock_t *);
+int __libc_rwlock_tryrdlock(pthread_rwlock_t *);
+int __libc_rwlock_trywrlock(pthread_rwlock_t *);
+int __libc_rwlock_unlock(pthread_rwlock_t *);
+int __libc_rwlock_destroy(pthread_rwlock_t *);
+__END_DECLS
+
+#define pthread_rwlock_init __libc_rwlock_init
+#define pthread_rwlock_rdlock __libc_rwlock_rdlock
+#define pthread_rwlock_wrlock __libc_rwlock_wrlock
+#define pthread_rwlock_tryrdlock __libc_rwlock_tryrdlock
+#define pthread_rwlock_trywrlock __libc_rwlock_trywrlock
+#define pthread_rwlock_unlock __libc_rwlock_unlock
+#define pthread_rwlock_destroy __libc_rwlock_destroy
+
+__BEGIN_DECLS
+int __libc_thr_keycreate(pthread_key_t *, void (*)(void *));
+int __libc_thr_setspecific(pthread_key_t, const void *);
+void *__libc_thr_getspecific(pthread_key_t);
+int __libc_thr_keydelete(pthread_key_t);
+__END_DECLS
+
+#define pthread_key_create __libc_thr_keycreate
+#define pthread_setspecific __libc_thr_setspecific
+#define pthread_getspecific __libc_thr_getspecific
+#define pthread_key_delete __libc_thr_keydelete
+
+__BEGIN_DECLS
+int __libc_thr_once(pthread_once_t *, void (*)(void));
+pthread_t __libc_thr_self(void);
+void __libc_thr_exit(void *) __attribute__((__noreturn__));
+int __libc_thr_setcancelstate(int, int *);
+__END_DECLS
+
+#define pthread_once __libc_thr_once
+#define pthread_self __libc_thr_self
+#define pthread_exit __libc_thr_exit
+#define pthread_setcancelstate __libc_thr_setcancelstate
+
+#endif /* __LIBPTHREAD_SOURCE__ */
+
#endif /* _LIB_PTHREAD_H */
Index: lib/libpthread/Makefile
===================================================================
RCS file: /cvsroot/src/lib/libpthread/Makefile,v
retrieving revision 1.27
diff -u -r1.27 Makefile
--- lib/libpthread/Makefile 2 Jun 2004 14:07:07 -0000 1.27
+++ lib/libpthread/Makefile 6 Dec 2004 19:00:27 -0000
@@ -26,6 +26,7 @@
.PATH: ${ARCHDIR}
CPPFLAGS+= -I${ARCHDIR} -I${.CURDIR} -I${.OBJDIR} -D_LIBC
+CPPFLAGS+= -D__LIBPTHREAD_SOURCE__
DPSRCS+= assym.h
CLEANFILES+= assym.h
Index: include/sched.h
===================================================================
RCS file: /cvsroot/src/include/sched.h,v
retrieving revision 1.4
diff -u -r1.4 sched.h
--- include/sched.h 8 Jul 2003 05:41:51 -0000 1.4
+++ include/sched.h 6 Dec 2004 19:00:27 -0000
@@ -64,8 +64,13 @@
/* Not optional in the presence of _POSIX_THREADS */
int sched_yield(void);
+void __libc_thr_yield(void);
__END_DECLS
+#ifndef __LIBPTHREAD_SOURCE__
+#define sched_yield __libc_thr_yield
+#endif /* __LIBPTHREAD_SOURCE__ */
+
#if defined(_NETBSD_SOURCE)
/*
Index: include/signal.h
===================================================================
RCS file: /cvsroot/src/include/signal.h,v
retrieving revision 1.38
diff -u -r1.38 signal.h
--- include/signal.h 1 Jul 2004 23:46:07 -0000 1.38
+++ include/signal.h 6 Dec 2004 19:00:28 -0000
@@ -66,6 +66,10 @@
defined(_NETBSD_SOURCE)
int pthread_sigmask __P((int, const sigset_t *, sigset_t *));
int pthread_kill __P((pthread_t, int));
+int __libc_thr_sigsetmask(int, const sigset_t *, sigset_t *);
+#ifndef __LIBPTHREAD_SOURCE__
+#define pthread_sigmask __libc_thr_sigsetmask
+#endif /* __LIBPTHREAD_SOURCE__ */
#endif
#ifdef __LIBC12_SOURCE__