summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpthread/linuxthreads/Changes18
-rw-r--r--libpthread/linuxthreads/Makefile3
-rw-r--r--libpthread/linuxthreads/Versions121
-rw-r--r--libpthread/linuxthreads/attr.c367
-rw-r--r--libpthread/linuxthreads/cancel.c23
-rw-r--r--libpthread/linuxthreads/condvar.c103
-rw-r--r--libpthread/linuxthreads/configure5
-rw-r--r--libpthread/linuxthreads/descr.h310
-rw-r--r--libpthread/linuxthreads/errno.c14
-rw-r--r--libpthread/linuxthreads/events.c10
-rw-r--r--libpthread/linuxthreads/internals.h283
-rw-r--r--libpthread/linuxthreads/join.c4
-rw-r--r--libpthread/linuxthreads/linuxthreads.texi365
-rw-r--r--libpthread/linuxthreads/lockfile.c10
-rw-r--r--libpthread/linuxthreads/manager.c130
-rw-r--r--libpthread/linuxthreads/mutex.c8
-rw-r--r--libpthread/linuxthreads/oldsemaphore.c12
-rw-r--r--libpthread/linuxthreads/pt-machine.c11
-rw-r--r--libpthread/linuxthreads/pthread.c208
-rw-r--r--libpthread/linuxthreads/restart.h7
-rw-r--r--libpthread/linuxthreads/rwlock.c239
-rw-r--r--libpthread/linuxthreads/semaphore.h5
-rw-r--r--libpthread/linuxthreads/signals.c70
-rw-r--r--libpthread/linuxthreads/specific.c192
-rw-r--r--libpthread/linuxthreads/spinlock.c2
-rw-r--r--libpthread/linuxthreads/spinlock.h2
-rw-r--r--libpthread/linuxthreads/sysdeps/alpha/pt-machine.h5
-rw-r--r--libpthread/linuxthreads/sysdeps/cris/pt-machine.h4
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/pt-machine.h8
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/tls.h4
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/useldt.h15
-rw-r--r--libpthread/linuxthreads/sysdeps/m68k/pt-machine.h4
-rw-r--r--libpthread/linuxthreads/sysdeps/mips/pt-machine.h5
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h3
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h2
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/pthread.h60
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/pt-machine.h4
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/tls.h10
-rw-r--r--libpthread/linuxthreads/wrapsyscall.c220
-rw-r--r--test/mmap/mmap.c62
-rw-r--r--test/mmap/mmap64.c4
42 files changed, 1876 insertions, 1084 deletions
diff --git a/libpthread/linuxthreads/Changes b/libpthread/linuxthreads/Changes
index 8ec26c9a6..b213f36c5 100644
--- a/libpthread/linuxthreads/Changes
+++ b/libpthread/linuxthreads/Changes
@@ -1,3 +1,15 @@
+Release 0.9:
+- more ports (SH, IA-64, s390)
+- many bug fixes
+- timed sync object wait functions
+- barrier implementation
+- spinlocks implementation
+- thread register on x86
+- variable stack size and position on some platforms
+
+Release 0.8:
+(ehmm, forgot to update, don't know anymore)
+
Release 0.7:
- Destructors for thread-specific data now conform to the POSIX semantics
(call destructors again if non-NULL TSD remains after a round of
@@ -6,7 +18,7 @@ Release 0.7:
and smaller thread descriptors (Ulrich Drepper).
- Added "error checking" mutexes.
- Protect against multiple sigwait() on the same signals.
-- Simplified implementation of semaphores when compare_and_swap is
+- Simplified implementation of semaphores when compare_and_swap is
not available.
- Fixed bug in fork() where stdin was closed if fork() was called before
the first pthread_create().
@@ -20,7 +32,7 @@ Release 0.6:
- Validation of thread identifiers: no more crashes when operating on
a thread that has exited (based on Pavel Krauz's ideas).
- Added fallback implementation of semaphores for the 386 and the
- Sparc.
+ Sparc.
- Fixed a bug in signal handling causing false restarts of suspended
threads.
- Fixed a bug in realtime scheduling causing all threads to have
@@ -49,7 +61,7 @@ Release 0.4:
- Race condition in pthread_cond_timedwait fixed.
- Recursive mutexes are back by popular demand.
- Partial support for realtime scheduling (initiated by Richard Neitzel).
-- pthread.h cleaned up a lot: now C++ compatible, added missing "const"
+- pthread.h cleaned up a lot: now C++ compatible, added missing "const"
qualifiers, added short documentation, put to GNU libc standards
for name space pollution (Ulrich Drepper).
- Motorola 68k port (contributed by Andreas Schwab).
diff --git a/libpthread/linuxthreads/Makefile b/libpthread/linuxthreads/Makefile
index cca65d51c..08ff8a2d8 100644
--- a/libpthread/linuxthreads/Makefile
+++ b/libpthread/linuxthreads/Makefile
@@ -47,8 +47,7 @@ CFLAGS += $(SYSDEPINC)
CSRC=attr.c cancel.c condvar.c errno.c events.c join.c lockfile.c manager.c \
mutex.c oldsemaphore.c pt-machine.c ptfork.c pthread.c \
- ptlongjmp.c rwlock.c semaphore.c signals.c specific.c spinlock.c \
- wrapsyscall.c
+ ptlongjmp.c rwlock.c semaphore.c signals.c specific.c spinlock.c
ifeq ($(UCLIBC_HAS_XLOCALE),y)
CSRC += locale.c
diff --git a/libpthread/linuxthreads/Versions b/libpthread/linuxthreads/Versions
deleted file mode 100644
index c0ec79238..000000000
--- a/libpthread/linuxthreads/Versions
+++ /dev/null
@@ -1,121 +0,0 @@
-libc {
- GLIBC_2.0 {
- pthread_attr_destroy; pthread_attr_getdetachstate;
- pthread_attr_getinheritsched; pthread_attr_getschedparam;
- pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init;
- pthread_attr_setdetachstate; pthread_attr_setinheritsched;
- pthread_attr_setschedparam; pthread_attr_setschedpolicy;
- pthread_attr_setscope; pthread_cond_broadcast; pthread_cond_destroy;
- pthread_cond_init; pthread_cond_signal; pthread_cond_wait;
- pthread_condattr_destroy; pthread_condattr_init; pthread_equal;
- pthread_exit; pthread_getschedparam; pthread_mutex_destroy;
- pthread_mutex_init; pthread_mutex_lock; pthread_mutex_unlock;
- pthread_mutexattr_getkind_np; pthread_mutexattr_setkind_np;
- pthread_self; pthread_setcancelstate; pthread_setcanceltype;
- pthread_setschedparam;
-
- # Internal libc interface to libpthread
- __libc_internal_tsd_get; __libc_internal_tsd_set;
- }
- GLIBC_2.1 {
- pthread_attr_init;
- }
-}
-
-ld.so {
- GLIBC_2.0 {
- # Internal libc interface to libpthread
- __libc_internal_tsd_get; __libc_internal_tsd_set;
- }
-}
-
-libpthread {
- GLIBC_2.0 {
- # Hidden entry point (through macros).
- _pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push;
- _pthread_cleanup_push_defer;
-
- # Internal libc interface to libpthread
- __libc_internal_tsd_get; __libc_internal_tsd_set;
-
- # Overwritten libc functions.
- accept; close; connect; fcntl; fork; fsync; longjmp; lseek; msync;
- nanosleep; open; pause; raise; read; recv; recvfrom; recvmsg; send;
- sendmsg; sendto; sigaction; siglongjmp; system; tcdrain; wait;
- waitpid; write;
- __close; __connect; __fcntl; __lseek; __open; __read; __send; __wait;
- __write;
- _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile;
- vfork; __fork;
-
- # POSIX.1c extensions to libc.
- flockfile; funlockfile; ftrylockfile;
-
- # Non-standard POSIX1.x functions.
- pthread_kill_other_threads_np; pthread_mutexattr_getkind_np;
- pthread_mutexattr_setkind_np;
-
- # Real POSIX.1c functions.
- pthread_atfork; pthread_attr_destroy; pthread_attr_getdetachstate;
- pthread_attr_getinheritsched; pthread_attr_getschedparam;
- pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init;
- pthread_attr_setdetachstate; pthread_attr_setinheritsched;
- pthread_attr_setschedparam; pthread_attr_setschedpolicy;
- pthread_attr_setscope; pthread_cancel; pthread_cond_broadcast;
- pthread_cond_destroy; pthread_cond_init; pthread_cond_signal;
- pthread_cond_timedwait; pthread_cond_wait; pthread_condattr_destroy;
- pthread_condattr_init; pthread_create; pthread_detach; pthread_equal;
- pthread_exit; pthread_getschedparam; pthread_getspecific; pthread_join;
- pthread_key_create; pthread_key_delete; pthread_kill;
- pthread_mutex_destroy; pthread_mutex_init; pthread_mutex_lock;
- pthread_mutex_trylock; pthread_mutex_unlock; pthread_mutexattr_destroy;
- pthread_mutexattr_init; pthread_once; pthread_self; pthread_setcancelstate;
- pthread_setcanceltype; pthread_setschedparam; pthread_setspecific;
- pthread_sigmask; pthread_testcancel;
-
- sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
- sigwait;
-
- # Protected names for functions used in other shared objects.
- __pthread_atfork; __pthread_initialize; __pthread_getspecific;
- __pthread_key_create; __pthread_mutex_destroy; __pthread_mutex_init;
- __pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock;
- __pthread_mutexattr_destroy; __pthread_mutexattr_init;
- __pthread_mutexattr_settype; __pthread_once; __pthread_setspecific;
-
- # The error functions.
- __errno_location; __h_errno_location;
- }
- GLIBC_2.1 {
- # Functions with changed interface.
- pthread_attr_init; pthread_create;
-
- # Unix98 extensions.
- pthread_rwlock_init; pthread_rwlock_destroy; pthread_rwlock_rdlock;
- pthread_rwlock_tryrdlock; pthread_rwlock_wrlock; pthread_rwlock_trywrlock;
- pthread_rwlock_unlock; pthread_rwlockattr_init; pthread_rwlockattr_destroy;
- pthread_rwlockattr_getpshared; pthread_rwlockattr_setpshared;
- pthread_rwlockattr_getkind_np; pthread_rwlockattr_setkind_np;
-
- pthread_attr_getguardsize; pthread_attr_setguardsize;
- pthread_attr_getstackaddr; pthread_attr_setstackaddr;
- pthread_attr_getstacksize; pthread_attr_setstacksize;
-
- pthread_getconcurrency; pthread_setconcurrency;
-
- pthread_mutexattr_gettype; pthread_mutexattr_settype;
-
- sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
-
- # helper functions
- __libc_current_sigrtmin; __libc_current_sigrtmax;
- __libc_allocate_rtsig;
- }
- GLIBC_2.1.1 {
- sem_close; sem_open; sem_unlink;
- }
- GLIBC_2.1.2 {
- __pthread_kill_other_threads_np;
- __vfork;
- }
-}
diff --git a/libpthread/linuxthreads/attr.c b/libpthread/linuxthreads/attr.c
index 4432a04d1..c84da0d30 100644
--- a/libpthread/linuxthreads/attr.c
+++ b/libpthread/linuxthreads/attr.c
@@ -12,27 +12,50 @@
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU Library General Public License for more details. */
-/* changed for uClibc */
+/* Handling of thread attributes */
+
+/* mods for uClibc */
+#define __getpagesize getpagesize
#define __sched_get_priority_min sched_get_priority_min
#define __sched_get_priority_max sched_get_priority_max
+#define __sched_getscheduler sched_getscheduler
+#define __sched_getparam sched_getparam
-/* Handling of thread attributes */
-
+#include <features.h>
+#define __USE_GNU
#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
+#include <sys/resource.h>
#include "pthread.h"
#include "internals.h"
-extern int __getpagesize(void);
+/* glibc uses strong aliases, we wont bother */
+#undef strong_alias
+#define strong_alias(sym, alias)
+#define __pthread_attr_destroy pthread_attr_destroy
+#define __pthread_attr_setdetachstate pthread_attr_setdetachstate
+#define __pthread_attr_getdetachstate pthread_attr_getdetachstate
+#define __pthread_attr_setschedparam pthread_attr_setschedparam
+#define __pthread_attr_getschedparam pthread_attr_getschedparam
+#define __pthread_attr_setschedpolicy pthread_attr_setschedpolicy
+#define __pthread_attr_getschedpolicy pthread_attr_getschedpolicy
+#define __pthread_attr_setinheritsched pthread_attr_setinheritsched
+#define __pthread_attr_getinheritsched pthread_attr_getinheritsched
+#define __pthread_attr_setscope pthread_attr_setscope
+#define __pthread_attr_getscope pthread_attr_getscope
/* NOTE: With uClibc I don't think we need this versioning stuff.
* Therefore, define the function pthread_attr_init() here using
* a strong symbol. */
-//int __pthread_attr_init_2_1(pthread_attr_t *attr)
-int pthread_attr_init(pthread_attr_t *attr)
+#define __pthread_attr_init_2_1 pthread_attr_init
+int __pthread_attr_init_2_1(pthread_attr_t *attr)
{
size_t ps = __getpagesize ();
@@ -41,7 +64,11 @@ int pthread_attr_init(pthread_attr_t *attr)
attr->__schedparam.sched_priority = 0;
attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
attr->__scope = PTHREAD_SCOPE_SYSTEM;
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ attr->__guardsize = ps + ps;
+#else
attr->__guardsize = ps;
+#endif
attr->__stackaddr = NULL;
attr->__stackaddr_set = 0;
attr->__stacksize = STACK_SIZE - ps;
@@ -49,10 +76,11 @@ int pthread_attr_init(pthread_attr_t *attr)
}
/* uClibc: leave out this for now. */
-#if DO_PTHREAD_VERSIONING_WITH_UCLIBC
-#if defined __HAVE_ELF__ && defined __PIC__ && defined DO_VERSIONING
-default_symbol_version (__pthread_attr_init_2_1, pthread_attr_init, GLIBC_2.1);
+#if 0
+versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init,
+ GLIBC_2_1);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
int __pthread_attr_init_2_0(pthread_attr_t *attr)
{
attr->__detachstate = PTHREAD_CREATE_JOINABLE;
@@ -62,18 +90,18 @@ int __pthread_attr_init_2_0(pthread_attr_t *attr)
attr->__scope = PTHREAD_SCOPE_SYSTEM;
return 0;
}
-symbol_version (__pthread_attr_init_2_0, pthread_attr_init, GLIBC_2.0);
-#else
-strong_alias (__pthread_attr_init_2_1, pthread_attr_init)
+compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init,
+ GLIBC_2_0);
+#endif
#endif
-#endif /* DO_PTHREAD_VERSIONING_WITH_UCLIBC */
-int pthread_attr_destroy(pthread_attr_t *attr)
+int __pthread_attr_destroy(pthread_attr_t *attr)
{
return 0;
}
+strong_alias (__pthread_attr_destroy, pthread_attr_destroy);
-int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
{
if (detachstate < PTHREAD_CREATE_JOINABLE ||
detachstate > PTHREAD_CREATE_DETACHED)
@@ -81,15 +109,17 @@ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
attr->__detachstate = detachstate;
return 0;
}
+strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate);
-int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
{
*detachstate = attr->__detachstate;
return 0;
}
+strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate);
-int pthread_attr_setschedparam(pthread_attr_t *attr,
- const struct sched_param *param)
+int __pthread_attr_setschedparam(pthread_attr_t *attr,
+ const struct sched_param *param)
{
int max_prio = __sched_get_priority_max(attr->__schedpolicy);
int min_prio = __sched_get_priority_min(attr->__schedpolicy);
@@ -99,43 +129,49 @@ int pthread_attr_setschedparam(pthread_attr_t *attr,
memcpy (&attr->__schedparam, param, sizeof (struct sched_param));
return 0;
}
+strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam);
-int pthread_attr_getschedparam(const pthread_attr_t *attr,
- struct sched_param *param)
+int __pthread_attr_getschedparam(const pthread_attr_t *attr,
+ struct sched_param *param)
{
memcpy (param, &attr->__schedparam, sizeof (struct sched_param));
return 0;
}
+strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam);
-int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
{
if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
return EINVAL;
attr->__schedpolicy = policy;
return 0;
}
+strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
-int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
{
*policy = attr->__schedpolicy;
return 0;
}
+strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
-int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
+int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
{
if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
return EINVAL;
attr->__inheritsched = inherit;
return 0;
}
+strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched);
-int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
+int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
{
*inherit = attr->__inheritsched;
return 0;
}
+strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched);
-int pthread_attr_setscope(pthread_attr_t *attr, int scope)
+int __pthread_attr_setscope(pthread_attr_t *attr, int scope)
{
switch (scope) {
case PTHREAD_SCOPE_SYSTEM:
@@ -147,20 +183,17 @@ int pthread_attr_setscope(pthread_attr_t *attr, int scope)
return EINVAL;
}
}
+strong_alias (__pthread_attr_setscope, pthread_attr_setscope);
-int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
+int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
{
*scope = attr->__scope;
return 0;
}
+strong_alias (__pthread_attr_getscope, pthread_attr_getscope);
int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
{
- size_t ps = __getpagesize ();
-
- /* First round up the guard size. */
- guardsize = roundup (guardsize, ps);
-
/* The guard size must not be larger than the stack itself */
if (guardsize >= attr->__stacksize) return EINVAL;
@@ -185,6 +218,9 @@ int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
}
weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
+link_warning (pthread_attr_setstackaddr,
+ "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
+
int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
{
/* XXX This function has a stupid definition. The standard specifies
@@ -195,8 +231,27 @@ int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
}
weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
+link_warning (pthread_attr_getstackaddr,
+ "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
+
+
int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
+#ifdef FLOATING_STACKS
+ /* We have to check against the maximum allowed stack size. This is no
+ problem if the manager is already started and we determined it. If
+ this hasn't happened, we have to find the limit outself. */
+ if (__pthread_max_stacksize == 0)
+ __pthread_init_max_stacksize ();
+
+ if (stacksize > __pthread_max_stacksize)
+ return EINVAL;
+#else
+ /* We have a fixed size limit. */
+ if (stacksize > STACK_SIZE)
+ return EINVAL;
+#endif
+
/* We don't accept value smaller than PTHREAD_STACK_MIN. */
if (stacksize < PTHREAD_STACK_MIN)
return EINVAL;
@@ -204,7 +259,45 @@ int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
attr->__stacksize = stacksize;
return 0;
}
+
+/* Don't bother with this version stuff in uClibc */
+#if 1 /*PTHREAD_STACK_MIN == 16384*/
weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
+#else
+versioned_symbol (libpthread, __pthread_attr_setstacksize,
+ pthread_attr_setstacksize, GLIBC_2_3_3);
+
+# if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3)
+
+int __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+# ifdef FLOATING_STACKS
+ /* We have to check against the maximum allowed stack size. This is no
+ problem if the manager is already started and we determined it. If
+ this hasn't happened, we have to find the limit outself. */
+ if (__pthread_max_stacksize == 0)
+ __pthread_init_max_stacksize ();
+
+ if (stacksize > __pthread_max_stacksize)
+ return EINVAL;
+# else
+ /* We have a fixed size limit. */
+ if (stacksize > STACK_SIZE)
+ return EINVAL;
+# endif
+
+ /* We don't accept value smaller than old PTHREAD_STACK_MIN. */
+ if (stacksize < 16384)
+ return EINVAL;
+
+ attr->__stacksize = stacksize;
+ return 0;
+}
+compat_symbol (libpthread, __old_pthread_attr_setstacksize,
+ pthread_attr_setstacksize, GLIBC_2_1);
+# endif
+#endif
+
int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
{
@@ -212,3 +305,215 @@ int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
return 0;
}
weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
+
+int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int err;
+
+ if ((((uintptr_t) stackaddr)
+ & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
+ err = EINVAL;
+ else
+ err = __pthread_attr_setstacksize (attr, stacksize);
+ if (err == 0)
+ {
+#ifndef _STACK_GROWS_UP
+ attr->__stackaddr = (char *) stackaddr + stacksize;
+#else
+ attr->__stackaddr = stackaddr;
+#endif
+ attr->__stackaddr_set = 1;
+ }
+
+ return err;
+}
+
+/* Don't bother with this version stuff in uClibc */
+#if 1 /*PTHREAD_STACK_MIN == 16384*/
+weak_alias (__pthread_attr_setstack, pthread_attr_setstack)
+#else
+versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack,
+ GLIBC_2_3_3);
+# if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3)
+int __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize)
+{
+ int err;
+
+ if ((((uintptr_t) stackaddr)
+ & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
+ err = EINVAL;
+ else
+ err = __old_pthread_attr_setstacksize (attr, stacksize);
+ if (err == 0)
+ {
+# ifndef _STACK_GROWS_UP
+ attr->__stackaddr = (char *) stackaddr + stacksize;
+# else
+ attr->__stackaddr = stackaddr;
+# endif
+ attr->__stackaddr_set = 1;
+ }
+
+ return err;
+}
+
+compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack,
+ GLIBC_2_2);
+
+# endif
+#endif
+
+int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr,
+ size_t *stacksize)
+{
+ /* XXX This function has a stupid definition. The standard specifies
+ no error value but what is if no stack address was set? We simply
+ return the value we have in the member. */
+#ifndef _STACK_GROWS_UP
+ *stackaddr = (char *) attr->__stackaddr - attr->__stacksize;
+#else
+ *stackaddr = attr->__stackaddr;
+#endif
+ *stacksize = attr->__stacksize;
+ return 0;
+}
+weak_alias (__pthread_attr_getstack, pthread_attr_getstack)
+
+/* can't fully support this just yet */
+#if 0
+int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
+{
+ pthread_handle handle = thread_handle (thread);
+ pthread_descr descr;
+ int ret = 0;
+
+ if (handle == NULL)
+ return ENOENT;
+
+ descr = handle->h_descr;
+
+ attr->__detachstate = (descr->p_detached
+ ? PTHREAD_CREATE_DETACHED
+ : PTHREAD_CREATE_JOINABLE);
+
+ attr->__schedpolicy = __sched_getscheduler (descr->p_pid);
+ if (attr->__schedpolicy == -1)
+ return errno;
+
+ if (__sched_getparam (descr->p_pid,
+ (struct sched_param *) &attr->__schedparam) != 0)
+ return errno;
+
+ attr->__inheritsched = descr->p_inheritsched;
+ attr->__scope = PTHREAD_SCOPE_SYSTEM;
+
+#ifdef _STACK_GROWS_DOWN
+# ifdef USE_TLS
+ attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr
+ - descr->p_guardsize;
+# else
+ attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
+ - descr->p_guardsize;
+# endif
+#else
+# ifdef USE_TLS
+ attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr;
+# else
+ attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
+# endif
+#endif
+ attr->__guardsize = descr->p_guardsize;
+ attr->__stackaddr_set = descr->p_userstack;
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ if (descr->p_userstack == 0)
+ attr->__stacksize *= 2;
+ /* XXX This is awkward. The guard pages are in the middle of the
+ two stacks. We must count the guard size in the stack size since
+ otherwise the range of the stack area cannot be computed. */
+ attr->__stacksize += attr->__guardsize;
+#endif
+#ifdef USE_TLS
+ attr->__stackaddr = descr->p_stackaddr;
+#else
+# ifndef _STACK_GROWS_UP
+ attr->__stackaddr = (char *)(descr + 1);
+# else
+ attr->__stackaddr = (char *)descr;
+# endif
+#endif
+
+#ifdef USE_TLS
+ if (attr->__stackaddr == NULL)
+#else
+ if (descr == &__pthread_initial_thread)
+#endif
+ {
+ /* Stack size limit. */
+ struct rlimit rl;
+
+ /* The safest way to get the top of the stack is to read
+ /proc/self/maps and locate the line into which
+ __libc_stack_end falls. */
+ FILE *fp = fopen ("/proc/self/maps", "rc");
+ if (fp == NULL)
+ ret = errno;
+ /* We need the limit of the stack in any case. */
+ else if (getrlimit (RLIMIT_STACK, &rl) != 0)
+ ret = errno;
+ else
+ {
+ /* We need no locking. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+ /* Until we found an entry (which should always be the case)
+ mark the result as a failure. */
+ ret = ENOENT;
+
+ char *line = NULL;
+ size_t linelen = 0;
+ uintptr_t last_to = 0;
+
+ while (! feof_unlocked (fp))
+ {
+ if (__getdelim (&line, &linelen, '\n', fp) <= 0)
+ break;
+
+ uintptr_t from;
+ uintptr_t to;
+ if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
+ continue;
+ if (from <= (uintptr_t) __libc_stack_end
+ && (uintptr_t) __libc_stack_end < to)
+ {
+ /* Found the entry. Now we have the info we need. */
+ attr->__stacksize = rl.rlim_cur;
+#ifdef _STACK_GROWS_UP
+ /* Don't check to enforce a limit on the __stacksize */
+ attr->__stackaddr = (void *) from;
+#else
+ attr->__stackaddr = (void *) to;
+
+ /* The limit might be too high. */
+ if ((size_t) attr->__stacksize
+ > (size_t) attr->__stackaddr - last_to)
+ attr->__stacksize = (size_t) attr->__stackaddr - last_to;
+#endif
+
+ /* We succeed and no need to look further. */
+ ret = 0;
+ break;
+ }
+ last_to = to;
+ }
+
+ fclose (fp);
+ free (line);
+ }
+ }
+
+ return 0;
+
+}
+#endif
diff --git a/libpthread/linuxthreads/cancel.c b/libpthread/linuxthreads/cancel.c
index 1356348a7..dbba7eef4 100644
--- a/libpthread/linuxthreads/cancel.c
+++ b/libpthread/linuxthreads/cancel.c
@@ -26,6 +26,14 @@
extern void __rpc_thread_destroy(void);
#endif
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
int pthread_setcancelstate(int state, int * oldstate)
{
@@ -62,28 +70,31 @@ int pthread_cancel(pthread_t thread)
int dorestart = 0;
pthread_descr th;
pthread_extricate_if *pextricate;
+ int already_canceled;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, thread)) {
+ if (nonexisting_handle(handle, thread)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
th = handle->h_descr;
- if (th->p_canceled) {
+ already_canceled = th->p_canceled;
+ th->p_canceled = 1;
+
+ if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
__pthread_unlock(&handle->h_lock);
return 0;
}
pextricate = th->p_extricate;
- th->p_canceled = 1;
pid = th->p_pid;
/* If the thread has registered an extrication interface, then
invoke the interface. If it returns 1, then we succeeded in
dequeuing the thread from whatever waiting object it was enqueued
- with. In that case, it is our responsibility to wake it up.
+ with. In that case, it is our responsibility to wake it up.
And also to set the p_woken_by_cancel flag so the woken thread
can tell that it was woken by cancellation. */
@@ -125,6 +136,8 @@ void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
buffer->__routine = routine;
buffer->__arg = arg;
buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+ if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+ buffer->__prev = NULL;
THREAD_SETMEM(self, p_cleanup, buffer);
}
@@ -144,6 +157,8 @@ void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
buffer->__arg = arg;
buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+ if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+ buffer->__prev = NULL;
THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
THREAD_SETMEM(self, p_cleanup, buffer);
}
diff --git a/libpthread/linuxthreads/condvar.c b/libpthread/linuxthreads/condvar.c
index f9c46a331..b051afd4c 100644
--- a/libpthread/linuxthreads/condvar.c
+++ b/libpthread/linuxthreads/condvar.c
@@ -25,19 +25,52 @@
#include "queue.h"
#include "restart.h"
-int pthread_cond_init(pthread_cond_t *cond,
- const pthread_condattr_t *cond_attr)
+/* glibc uses strong aliases, we wont bother */
+#undef strong_alias
+#define strong_alias(sym, alias)
+#define __pthread_cond_init pthread_cond_init
+#define __pthread_cond_destroy pthread_cond_destroy
+#define __pthread_cond_wait pthread_cond_wait
+#define __pthread_cond_timedwait pthread_cond_timedwait
+#define __pthread_cond_signal pthread_cond_signal
+#define __pthread_cond_broadcast pthread_cond_broadcast
+#define __pthread_condattr_init pthread_condattr_init
+#define __pthread_condattr_destroy pthread_condattr_destroy
+
+
+int __pthread_cond_init(pthread_cond_t *cond,
+ const pthread_condattr_t *cond_attr)
{
__pthread_init_lock(&cond->__c_lock);
cond->__c_waiting = NULL;
return 0;
}
-
-int pthread_cond_destroy(pthread_cond_t *cond)
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_init, __old_pthread_cond_init)
+compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init,
+ GLIBC_2_0);
+#endif
+#endif
+
+int __pthread_cond_destroy(pthread_cond_t *cond)
{
if (cond->__c_waiting != NULL) return EBUSY;
return 0;
}
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_destroy, __old_pthread_cond_destroy)
+compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy,
+ GLIBC_2_0);
+#endif
+#endif
/* Function called by pthread_cancel to remove the thread from
waiting on a condition variable queue. */
@@ -55,7 +88,7 @@ static int cond_extricate_func(void *obj, pthread_descr th)
return did_remove;
}
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
pthread_extricate_if extr;
@@ -132,6 +165,16 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
pthread_mutex_lock(mutex);
return 0;
}
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_wait, __old_pthread_cond_wait)
+compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait,
+ GLIBC_2_0);
+#endif
+#endif
static int
pthread_cond_timedwait_relative(pthread_cond_t *cond,
@@ -227,14 +270,24 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
return 0;
}
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec * abstime)
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec * abstime)
{
/* Indirect call through pointer! */
return pthread_cond_timedwait_relative(cond, mutex, abstime);
}
-
-int pthread_cond_signal(pthread_cond_t *cond)
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_timedwait, __old_pthread_cond_timedwait)
+compat_symbol (libpthread, __old_pthread_cond_timedwait,
+ pthread_cond_timedwait, GLIBC_2_0);
+#endif
+#endif
+
+int __pthread_cond_signal(pthread_cond_t *cond)
{
pthread_descr th;
@@ -248,8 +301,18 @@ int pthread_cond_signal(pthread_cond_t *cond)
}
return 0;
}
-
-int pthread_cond_broadcast(pthread_cond_t *cond)
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_signal, __old_pthread_cond_signal)
+compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal,
+ GLIBC_2_0);
+#endif
+#endif
+
+int __pthread_cond_broadcast(pthread_cond_t *cond)
{
pthread_descr tosignal, th;
@@ -266,16 +329,28 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
}
return 0;
}
-
-int pthread_condattr_init(pthread_condattr_t *attr)
+/* Don't bother with this version stuff in uClibc */
+#if 0
+versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
+ GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_broadcast, __old_pthread_cond_broadcast)
+compat_symbol (libpthread, __old_pthread_cond_broadcast,
+ pthread_cond_broadcast, GLIBC_2_0);
+#endif
+#endif
+
+int __pthread_condattr_init(pthread_condattr_t *attr)
{
return 0;
}
+strong_alias (__pthread_condattr_init, pthread_condattr_init)
-int pthread_condattr_destroy(pthread_condattr_t *attr)
+int __pthread_condattr_destroy(pthread_condattr_t *attr)
{
return 0;
}
+strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy)
int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
{
diff --git a/libpthread/linuxthreads/configure b/libpthread/linuxthreads/configure
deleted file mode 100644
index 3eafc93f5..000000000
--- a/libpthread/linuxthreads/configure
+++ /dev/null
@@ -1,5 +0,0 @@
-# This is only to keep the GNU C library configure mechanism happy.
-#
-# Perhaps some day we need a real configuration script for different
-# kernel versions or so.
-exit 0
diff --git a/libpthread/linuxthreads/descr.h b/libpthread/linuxthreads/descr.h
new file mode 100644
index 000000000..fd9e8d461
--- /dev/null
+++ b/libpthread/linuxthreads/descr.h
@@ -0,0 +1,310 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix */
+/* threads for Linux. */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
+/* */
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Library General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU Library General Public License for more details. */
+
+#ifndef _DESCR_H
+#define _DESCR_H 1
+
+#include <features.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <tls.h>
+
+#if 1
+# include <bits/libc-tsd.h>
+#else
+/* Fast thread-specific data internal to libc. */
+enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
+ _LIBC_TSD_KEY_DL_ERROR,
+ _LIBC_TSD_KEY_RPC_VARS,
+ _LIBC_TSD_KEY_LOCALE,
+ _LIBC_TSD_KEY_CTYPE_B,
+ _LIBC_TSD_KEY_CTYPE_TOLOWER,
+ _LIBC_TSD_KEY_CTYPE_TOUPPER,
+ _LIBC_TSD_KEY_N };
+#endif
+
+/* The type of thread descriptors */
+typedef struct _pthread_descr_struct *pthread_descr;
+
+
+/* Some more includes. */
+#include <pt-machine.h>
+#include "../linuxthreads_db/thread_dbP.h"
+
+
+/* Arguments passed to thread creation routine */
+struct pthread_start_args {
+ void *(*start_routine)(void *); /* function to run */
+ void *arg; /* its argument */
+ sigset_t mask; /* initial signal mask for thread */
+ int schedpolicy; /* initial scheduling policy (if any) */
+ struct sched_param schedparam; /* initial scheduling parameters (if any) */
+};
+
+
+/* Callback interface for removing the thread from waiting on an
+ object if it is cancelled while waiting or about to wait.
+ This hold a pointer to the object, and a pointer to a function
+ which ``extricates'' the thread from its enqueued state.
+ The function takes two arguments: pointer to the wait object,
+ and a pointer to the thread. It returns 1 if an extrication
+ actually occured, and hence the thread must also be signalled.
+ It returns 0 if the thread had already been extricated. */
+typedef struct _pthread_extricate_struct {
+ void *pu_object;
+ int (*pu_extricate_func)(void *, pthread_descr);
+} pthread_extricate_if;
+
+
+/* Atomic counter made possible by compare_and_swap */
+struct pthread_atomic {
+ long p_count;
+ int p_spinlock;
+};
+
+
+/* Context info for read write locks. The pthread_rwlock_info structure
+ is information about a lock that has been read-locked by the thread
+ in whose list this structure appears. The pthread_rwlock_context
+ is embedded in the thread context and contains a pointer to the
+ head of the list of lock info structures, as well as a count of
+ read locks that are untracked, because no info structure could be
+ allocated for them. */
+struct _pthread_rwlock_t;
+typedef struct _pthread_rwlock_info {
+ struct _pthread_rwlock_info *pr_next;
+ struct _pthread_rwlock_t *pr_lock;
+ int pr_lock_count;
+} pthread_readlock_info;
+
+
+/* We keep thread specific data in a special data structure, a two-level
+ array. The top-level array contains pointers to dynamically allocated
+ arrays of a certain number of data pointers. So we can implement a
+ sparse array. Each dynamic second-level array has
+ PTHREAD_KEY_2NDLEVEL_SIZE
+ entries. This value shouldn't be too large. */
+#define PTHREAD_KEY_2NDLEVEL_SIZE 32
+
+/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
+ keys in each subarray. */
+#define PTHREAD_KEY_1STLEVEL_SIZE \
+ ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
+ / PTHREAD_KEY_2NDLEVEL_SIZE)
+
+
+union dtv;
+
+struct _pthread_descr_struct
+{
+#if !defined USE_TLS || !TLS_DTV_AT_TP
+ /* This overlaps tcbhead_t (see tls.h), as used for TLS without threads. */
+ union
+ {
+ struct
+ {
+ void *tcb; /* Pointer to the TCB. This is not always
+ the address of this thread descriptor. */
+ union dtv *dtvp;
+ pthread_descr self; /* Pointer to this structure */
+ int multiple_threads;
+# ifdef NEED_DL_SYSINFO
+ uintptr_t sysinfo;
+# endif
+ } data;
+ void *__padding[16];
+ } p_header;
+# define p_multiple_threads p_header.data.multiple_threads
+#elif TLS_MULTIPLE_THREADS_IN_TCB
+ int p_multiple_threads;
+#endif
+
+ pthread_descr p_nextlive, p_prevlive;
+ /* Double chaining of active threads */
+ pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */
+ pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */
+ pthread_t p_tid; /* Thread identifier */
+ int p_pid; /* PID of Unix process */
+ int p_priority; /* Thread priority (== 0 if not realtime) */
+ struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
+ int p_signal; /* last signal received */
+ sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
+ sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
+ char p_terminated; /* true if terminated e.g. by pthread_exit */
+ char p_detached; /* true if detached */
+ char p_exited; /* true if the assoc. process terminated */
+ void * p_retval; /* placeholder for return value */
+ int p_retcode; /* placeholder for return code */
+ pthread_descr p_joining; /* thread joining on that thread or NULL */
+ struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
+ char p_cancelstate; /* cancellation state */
+ char p_canceltype; /* cancellation type (deferred/async) */
+ char p_canceled; /* cancellation request pending */
+ char * p_in_sighandler; /* stack address of sighandler, or NULL */
+ char p_sigwaiting; /* true if a sigwait() is in progress */
+ struct pthread_start_args p_start_args; /* arguments for thread creation */
+ void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
+#if !(USE_TLS && HAVE___THREAD)
+ void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
+ int * p_errnop; /* pointer to used errno variable */
+ int p_errno; /* error returned by last system call */
+ int * p_h_errnop; /* pointer to used h_errno variable */
+ int p_h_errno; /* error returned by last netdb function */
+#endif
+ int p_userstack; /* nonzero if the user provided the stack */
+ void *p_guardaddr; /* address of guard area or NULL */
+ size_t p_guardsize; /* size of guard area */
+ pthread_descr p_self; /* Pointer to this structure */
+ int p_nr; /* Index of descriptor in __pthread_handles */
+ int p_report_events; /* Nonzero if events must be reported. */
+ td_eventbuf_t p_eventbuf; /* Data for event. */
+ struct pthread_atomic p_resume_count; /* number of times restart() was
+ called on thread */
+ char p_woken_by_cancel; /* cancellation performed wakeup */
+ char p_condvar_avail; /* flag if conditional variable became avail */
+ char p_sem_avail; /* flag if semaphore became available */
+ pthread_extricate_if *p_extricate; /* See above */
+ pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
+ pthread_readlock_info *p_readlock_free; /* Free list of structs */
+ int p_untracked_readlock_count; /* Readlocks not tracked by list */
+ int p_inheritsched; /* copied from the thread attribute */
+#if HP_TIMING_AVAIL
+ hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */
+#endif
+#ifdef USE_TLS
+ char *p_stackaddr; /* Stack address. */
+#endif
+ size_t p_alloca_cutoff; /* Maximum size which should be allocated
+ using alloca() instead of malloc(). */
+ /* New elements must be added at the end. */
+#ifdef __UCLIBC_HAS_XLOCALE__
+ __locale_t locale; /* thread-specific locale from uselocale() only! */
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+} __attribute__ ((aligned(32))); /* We need to align the structure so that
+ doubles are aligned properly. This is 8
+ bytes on MIPS and 16 bytes on MIPS64.
+ 32 bytes might give better cache
+ utilization. */
+
+
+
+/* Limit between the stack of the initial thread (above) and the
+ stacks of other threads (below). Aligned on a STACK_SIZE boundary.
+ Initially 0, meaning that the current thread is (by definition)
+ the initial thread. */
+
+/* For non-MMU systems also remember to stack top of the initial thread.
+ * This is adapted when other stacks are malloc'ed since we don't know
+ * the bounds a-priori. -StS */
+
+extern char *__pthread_initial_thread_bos;
+#ifndef __ARCH_HAS_MMU__
+extern char *__pthread_initial_thread_tos;
+#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) if ((tos)>=__pthread_initial_thread_bos && (bos)<=__pthread_initial_thread_tos) __pthread_initial_thread_bos = (tos)+1
+#else
+#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) /* empty */
+#endif /* __ARCH_HAS_MMU__ */
+
+/* Descriptor of the initial thread */
+
+extern struct _pthread_descr_struct __pthread_initial_thread;
+
+/* Limits of the thread manager stack. */
+
+extern char *__pthread_manager_thread_bos;
+extern char *__pthread_manager_thread_tos;
+
+/* Descriptor of the manager thread */
+
+extern struct _pthread_descr_struct __pthread_manager_thread;
+extern pthread_descr __pthread_manager_threadp attribute_hidden;
+
+/* Indicate whether at least one thread has a user-defined stack (if 1),
+ or all threads have stacks supplied by LinuxThreads (if 0). */
+
+extern int __pthread_nonstandard_stacks;
+
+/* The max size of the thread stack segments. If the default
+ THREAD_SELF implementation is used, this must be a power of two and
+ a multiple of PAGE_SIZE. */
+#ifndef STACK_SIZE
+#ifdef __ARCH_HAS_MMU__
+#define STACK_SIZE (2 * 1024 * 1024)
+#else
+#define STACK_SIZE (4 * __pagesize)
+#endif
+#endif
+
+/* Get some notion of the current stack. Need not be exactly the top
+ of the stack, just something somewhere in the current frame. */
+#ifndef CURRENT_STACK_FRAME
+#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
+#endif
+
+/* Recover thread descriptor for the current thread */
+
+extern pthread_descr __pthread_find_self (void) __attribute__ ((pure));
+
+static inline pthread_descr thread_self (void) __attribute__ ((pure));
+static inline pthread_descr thread_self (void)
+{
+#ifdef THREAD_SELF
+ return THREAD_SELF;
+#else
+ char *sp = CURRENT_STACK_FRAME;
+#ifdef __ARCH_HAS_MMU__
+ if (sp >= __pthread_initial_thread_bos)
+ return &__pthread_initial_thread;
+ else if (sp >= __pthread_manager_thread_bos
+ && sp < __pthread_manager_thread_tos)
+ return &__pthread_manager_thread;
+ else if (__pthread_nonstandard_stacks)
+ return __pthread_find_self();
+ else
+#ifdef _STACK_GROWS_DOWN
+ return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
+#else
+ return (pthread_descr)((unsigned long)sp &~ (STACK_SIZE-1));
+#endif
+#else /* !__ARCH_HAS_MMU__ */
+ /* For non-MMU we need to be more careful about the initial thread stack.
+ * We refine the initial thread stack bounds dynamically as we allocate
+ * the other stack frame such that it doesn't overlap with them. Then
+ * we can be sure to pick the right thread according to the current SP */
+
+ /* Since we allow other stack frames to be above or below, we need to
+ * treat this case special. When pthread_initialize() wasn't called yet,
+ * only the initial thread is there. */
+ if (__pthread_initial_thread_bos == NULL) {
+ return &__pthread_initial_thread;
+ }
+ else if (sp >= __pthread_initial_thread_bos
+ && sp < __pthread_initial_thread_tos) {
+ return &__pthread_initial_thread;
+ }
+ else if (sp >= __pthread_manager_thread_bos
+ && sp < __pthread_manager_thread_tos) {
+ return &__pthread_manager_thread;
+ }
+ else {
+ return __pthread_find_self();
+ }
+#endif /* __ARCH_HAS_MMU__ */
+#endif
+}
+
+#endif /* descr.h */
diff --git a/libpthread/linuxthreads/errno.c b/libpthread/linuxthreads/errno.c
index 9f651b8ec..f5778f98a 100644
--- a/libpthread/linuxthreads/errno.c
+++ b/libpthread/linuxthreads/errno.c
@@ -22,14 +22,16 @@
#include "internals.h"
#include <stdio.h>
-int * __errno_location()
+int *
+__errno_location (void)
{
- pthread_descr self = thread_self();
- return THREAD_GETMEM (self, p_errnop);
+ pthread_descr self = thread_self();
+ return THREAD_GETMEM (self, p_errnop);
}
-int * __h_errno_location()
+int *
+__h_errno_location (void)
{
- pthread_descr self = thread_self();
- return THREAD_GETMEM (self, p_h_errnop);
+ pthread_descr self = thread_self();
+ return THREAD_GETMEM (self, p_h_errnop);
}
diff --git a/libpthread/linuxthreads/events.c b/libpthread/linuxthreads/events.c
index a4bf1f898..b4ca3846e 100644
--- a/libpthread/linuxthreads/events.c
+++ b/libpthread/linuxthreads/events.c
@@ -1,18 +1,18 @@
/* Event functions used while debugging.
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
+ You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
diff --git a/libpthread/linuxthreads/internals.h b/libpthread/linuxthreads/internals.h
index 623a0e891..1f60caac3 100644
--- a/libpthread/linuxthreads/internals.h
+++ b/libpthread/linuxthreads/internals.h
@@ -13,21 +13,25 @@
/* GNU Library General Public License for more details. */
#ifndef _INTERNALS_H
-#define _INTERNALS_H 1
+#define _INTERNALS_H 1
/* Internal data structures */
/* Includes */
+#include <features.h>
#include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
#include <limits.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
+#include <bits/stackinfo.h>
#include <sys/types.h>
#include "pt-machine.h"
+#include <ucontext.h>
+#include <bits/sigcontextinfo.h>
#include "semaphore.h"
-#include "../linuxthreads_db/thread_dbP.h"
+#include "descr.h"
#ifdef __UCLIBC_HAS_XLOCALE__
#include <bits/uClibc_locale.h>
#endif /* __UCLIBC_HAS_XLOCALE__ */
@@ -51,30 +55,14 @@
# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
#endif
-/* Arguments passed to thread creation routine */
-
-struct pthread_start_args {
- void * (*start_routine)(void *); /* function to run */
- void * arg; /* its argument */
- sigset_t mask; /* initial signal mask for thread */
- int schedpolicy; /* initial scheduling policy (if any) */
- struct sched_param schedparam; /* initial scheduling parameters (if any) */
-};
-
-
-/* We keep thread specific data in a special data structure, a two-level
- array. The top-level array contains pointers to dynamically allocated
- arrays of a certain number of data pointers. So we can implement a
- sparse array. Each dynamic second-level array has
- PTHREAD_KEY_2NDLEVEL_SIZE
- entries. This value shouldn't be too large. */
-#define PTHREAD_KEY_2NDLEVEL_SIZE 32
-
-/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
- keys in each subarray. */
-#define PTHREAD_KEY_1STLEVEL_SIZE \
- ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
- / PTHREAD_KEY_2NDLEVEL_SIZE)
+#if !defined NOT_IN_libc && defined FLOATING_STACKS
+# define LIBC_THREAD_GETMEM(descr, member) THREAD_GETMEM (descr, member)
+# define LIBC_THREAD_SETMEM(descr, member, value) \
+ THREAD_SETMEM (descr, member, value)
+#else
+# define LIBC_THREAD_GETMEM(descr, member) descr->member
+# define LIBC_THREAD_SETMEM(descr, member, value) descr->member = (value)
+#endif
typedef void (*destr_function)(void *);
@@ -84,105 +72,9 @@ struct pthread_key_struct {
};
-#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, {{0, }}, 0, { 0 } }
-
-/* The type of thread descriptors */
+#define PTHREAD_START_ARGS_INITIALIZER(fct) \
+ { (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } }
-typedef struct _pthread_descr_struct * pthread_descr;
-
-/* Callback interface for removing the thread from waiting on an
- object if it is cancelled while waiting or about to wait.
- This hold a pointer to the object, and a pointer to a function
- which ``extricates'' the thread from its enqueued state.
- The function takes two arguments: pointer to the wait object,
- and a pointer to the thread. It returns 1 if an extrication
- actually occured, and hence the thread must also be signalled.
- It returns 0 if the thread had already been extricated. */
-
-typedef struct _pthread_extricate_struct {
- void *pu_object;
- int (*pu_extricate_func)(void *, pthread_descr);
-} pthread_extricate_if;
-
-/* Atomic counter made possible by compare_and_swap */
-
-struct pthread_atomic {
- long p_count;
- int p_spinlock;
-};
-
-/* Context info for read write locks. The pthread_rwlock_info structure
- is information about a lock that has been read-locked by the thread
- in whose list this structure appears. The pthread_rwlock_context
- is embedded in the thread context and contains a pointer to the
- head of the list of lock info structures, as well as a count of
- read locks that are untracked, because no info structure could be
- allocated for them. */
-
-struct _pthread_rwlock_t;
-
-typedef struct _pthread_rwlock_info {
- struct _pthread_rwlock_info *pr_next;
- struct _pthread_rwlock_t *pr_lock;
- int pr_lock_count;
-} pthread_readlock_info;
-
-struct _pthread_descr_struct {
- pthread_descr p_nextlive, p_prevlive;
- /* Double chaining of active threads */
- pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */
- pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */
- pthread_t p_tid; /* Thread identifier */
- int p_pid; /* PID of Unix process */
- int p_priority; /* Thread priority (== 0 if not realtime) */
- struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
- int p_signal; /* last signal received */
- sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
- sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
- char p_terminated; /* true if terminated e.g. by pthread_exit */
- char p_detached; /* true if detached */
- char p_exited; /* true if the assoc. process terminated */
- void * p_retval; /* placeholder for return value */
- int p_retcode; /* placeholder for return code */
- pthread_descr p_joining; /* thread joining on that thread or NULL */
- struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
- char p_cancelstate; /* cancellation state */
- char p_canceltype; /* cancellation type (deferred/async) */
- char p_canceled; /* cancellation request pending */
- int * p_errnop; /* pointer to used errno variable */
- int p_errno; /* error returned by last system call */
- int * p_h_errnop; /* pointer to used h_errno variable */
- int p_h_errno; /* error returned by last netdb function */
- char * p_in_sighandler; /* stack address of sighandler, or NULL */
- char p_sigwaiting; /* true if a sigwait() is in progress */
- struct pthread_start_args p_start_args; /* arguments for thread creation */
- void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
- void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
- int p_userstack; /* nonzero if the user provided the stack */
- void *p_guardaddr; /* address of guard area or NULL */
- size_t p_guardsize; /* size of guard area */
- pthread_descr p_self; /* Pointer to this structure */
- int p_nr; /* Index of descriptor in __pthread_handles */
- int p_report_events; /* Nonzero if events must be reported. */
- td_eventbuf_t p_eventbuf; /* Data for event. */
- struct pthread_atomic p_resume_count; /* number of times restart() was
- called on thread */
- char p_woken_by_cancel; /* cancellation performed wakeup */
- char p_condvar_avail; /* flag if conditional variable became avail */
- char p_sem_avail; /* flag if semaphore became available */
- pthread_extricate_if *p_extricate; /* See above */
- pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
- pthread_readlock_info *p_readlock_free; /* Free list of structs */
- int p_untracked_readlock_count; /* Readlocks not tracked by list */
- /* New elements must be added at the end. */
-#ifdef __UCLIBC_HAS_XLOCALE__
- __locale_t locale; /* thread-specific locale from uselocale() only! */
-#endif /* __UCLIBC_HAS_XLOCALE__ */
-} __attribute__ ((aligned(32))); /* We need to align the structure so that
- doubles are aligned properly. This is 8
- bytes on MIPS and 16 bytes on MIPS64.
- 32 bytes might give better cache
- utilization. */
/* The type of thread handles. */
@@ -200,7 +92,7 @@ struct pthread_request {
pthread_descr req_thread; /* Thread doing the request */
enum { /* Request kind */
REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
- REQ_POST, REQ_DEBUG, REQ_KICK
+ REQ_POST, REQ_DEBUG, REQ_KICK, REQ_FOR_EACH_THREAD
} req_kind;
union { /* Arguments for request */
struct { /* For REQ_CREATE: */
@@ -216,10 +108,24 @@ struct pthread_request {
int code; /* exit status */
} exit;
void * post; /* For REQ_POST: the semaphore */
+ struct { /* For REQ_FOR_EACH_THREAD: callback */
+ void (*fn)(void *, pthread_descr);
+ void *arg;
+ } for_each;
} req_args;
};
+
+typedef void (*arch_sighandler_t) (int, SIGCONTEXT);
+union sighandler
+{
+ arch_sighandler_t old;
+ void (*rt) (int, struct siginfo *, struct ucontext *);
+};
+extern union sighandler __sighandler[NSIG];
+
+
/* Signals used for suspend/restart and for cancellation notification. */
extern int __pthread_sig_restart;
@@ -235,41 +141,10 @@ extern int __pthread_sig_debug;
extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX];
-/* Descriptor of the initial thread */
-
-extern struct _pthread_descr_struct __pthread_initial_thread;
-
-/* Descriptor of the manager thread */
-
-extern struct _pthread_descr_struct __pthread_manager_thread;
-
/* Descriptor of the main thread */
extern pthread_descr __pthread_main_thread;
-/* Limit between the stack of the initial thread (above) and the
- stacks of other threads (below). Aligned on a STACK_SIZE boundary.
- Initially 0, meaning that the current thread is (by definition)
- the initial thread. */
-
-/* For non-MMU systems also remember to stack top of the initial thread.
- * This is adapted when other stacks are malloc'ed since we don't know
- * the bounds a-priori. -StS */
-
-extern char *__pthread_initial_thread_bos;
-#ifndef __ARCH_HAS_MMU__
-extern char *__pthread_initial_thread_tos;
-#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) if ((tos)>=__pthread_initial_thread_bos && (bos)<=__pthread_initial_thread_tos) __pthread_initial_thread_bos = (tos)+1
-#else
-#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) /* empty */
-#endif /* __ARCH_HAS_MMU__ */
-
-
-/* Indicate whether at least one thread has a user-defined stack (if 1),
- or all threads have stacks supplied by LinuxThreads (if 0). */
-
-extern int __pthread_nonstandard_stacks;
-
/* File descriptor for sending requests to the thread manager.
Initially -1, meaning that __pthread_initialize_manager must be called. */
@@ -279,10 +154,10 @@ extern int __pthread_manager_request;
extern int __pthread_manager_reader;
-/* Limits of the thread manager stack. */
-
-extern char *__pthread_manager_thread_bos;
-extern char *__pthread_manager_thread_tos;
+#ifdef FLOATING_STACKS
+/* Maximum stack size. */
+extern size_t __pthread_max_stacksize;
+#endif
/* Pending request for a process-wide exit */
@@ -298,6 +173,9 @@ extern volatile td_thr_events_t __pthread_threads_events;
/* Pointer to descriptor of thread with last event. */
extern volatile pthread_descr __pthread_last_event;
+/* Flag which tells whether we are executing on SMP kernel. */
+extern int __pthread_smp_kernel;
+
/* Return the handle corresponding to a thread id */
static inline pthread_handle thread_handle(pthread_t id)
@@ -309,28 +187,27 @@ static inline pthread_handle thread_handle(pthread_t id)
static inline int invalid_handle(pthread_handle h, pthread_t id)
{
+ return h->h_descr == NULL || h->h_descr->p_tid != id || h->h_descr->p_terminated;
+}
+
+static inline int nonexisting_handle(pthread_handle h, pthread_t id)
+{
return h->h_descr == NULL || h->h_descr->p_tid != id;
}
/* Fill in defaults left unspecified by pt-machine.h. */
+/* We round up a value with page size. */
+#ifndef page_roundup
+#define page_roundup(v,p) ((((size_t) (v)) + (p) - 1) & ~((p) - 1))
+#endif
+
/* The page size we can get from the system. This should likely not be
changed by the machine file but, you never know. */
extern size_t __pagesize;
#include <bits/uClibc_page.h>
#ifndef PAGE_SIZE
-#define PAGE_SIZE (sysconf (_SC_PAGESIZE))
-#endif
-
-/* The max size of the thread stack segments. If the default
- THREAD_SELF implementation is used, this must be a power of two and
- a multiple of PAGE_SIZE. */
-#ifndef STACK_SIZE
-#ifdef __ARCH_HAS_MMU__
-#define STACK_SIZE (2 * 1024 * 1024)
-#else
-#define STACK_SIZE (4 * __pagesize)
-#endif
+#define PAGE_SIZE (sysconf (_SC_PAGE_SIZE))
#endif
/* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */
@@ -351,17 +228,12 @@ extern size_t __pagesize;
#define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos
#endif
-/* Get some notion of the current stack. Need not be exactly the top
- of the stack, just something somewhere in the current frame. */
-#ifndef CURRENT_STACK_FRAME
-#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
-#endif
-
/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the
architecture doesn't need a memory barrier instruction (e.g. Intel
x86). Still we need the compiler to respect the barrier and emit
all outstanding operations which modify memory. Some architectures
distinguish between full, read and write barriers. */
+
#ifndef MEMORY_BARRIER
#define MEMORY_BARRIER() asm ("" : : : "memory")
#endif
@@ -372,54 +244,6 @@ extern size_t __pagesize;
#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER()
#endif
-/* Recover thread descriptor for the current thread */
-
-extern pthread_descr __pthread_find_self (void) __attribute__ ((const));
-
-static inline pthread_descr thread_self (void) __attribute__ ((const));
-static inline pthread_descr thread_self (void)
-{
-#ifdef THREAD_SELF
- return THREAD_SELF;
-#else
- char *sp = CURRENT_STACK_FRAME;
-#ifdef __ARCH_HAS_MMU__
- if (sp >= __pthread_initial_thread_bos)
- return &__pthread_initial_thread;
- else if (sp >= __pthread_manager_thread_bos
- && sp < __pthread_manager_thread_tos)
- return &__pthread_manager_thread;
- else if (__pthread_nonstandard_stacks)
- return __pthread_find_self();
- else
- return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
-#else
- /* For non-MMU we need to be more careful about the initial thread stack.
- * We refine the initial thread stack bounds dynamically as we allocate
- * the other stack frame such that it doesn't overlap with them. Then
- * we can be sure to pick the right thread according to the current SP */
-
- /* Since we allow other stack frames to be above or below, we need to
- * treat this case special. When pthread_initialize() wasn't called yet,
- * only the initial thread is there. */
- if (__pthread_initial_thread_bos == NULL) {
- return &__pthread_initial_thread;
- }
- else if (sp >= __pthread_initial_thread_bos
- && sp < __pthread_initial_thread_tos) {
- return &__pthread_initial_thread;
- }
- else if (sp >= __pthread_manager_thread_bos
- && sp < __pthread_manager_thread_tos) {
- return &__pthread_manager_thread;
- }
- else {
- return __pthread_find_self();
- }
-#endif /* __ARCH_HAS_MMU__ */
-#endif
-}
-
/* Max number of times we must spin on a spinlock calling sched_yield().
After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
@@ -427,6 +251,13 @@ static inline pthread_descr thread_self (void)
#define MAX_SPIN_COUNT 50
#endif
+/* Max number of times the spinlock in the adaptive mutex implementation
+ spins actively on SMP systems. */
+
+#ifndef MAX_ADAPTIVE_SPIN_COUNT
+#define MAX_ADAPTIVE_SPIN_COUNT 100
+#endif
+
/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
after MAX_SPIN_COUNT iterations of sched_yield().
With the 2.0 and 2.1 kernels, this MUST BE > 2ms.
diff --git a/libpthread/linuxthreads/join.c b/libpthread/linuxthreads/join.c
index 5aeec6a20..83761e199 100644
--- a/libpthread/linuxthreads/join.c
+++ b/libpthread/linuxthreads/join.c
@@ -124,7 +124,7 @@ int pthread_join(pthread_t thread_id, void ** thread_return)
extr.pu_extricate_func = join_extricate_func;
__pthread_lock(&handle->h_lock, self);
- if (invalid_handle(handle, thread_id)) {
+ if (nonexisting_handle(handle, thread_id)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
@@ -190,7 +190,7 @@ int pthread_detach(pthread_t thread_id)
pthread_descr th;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, thread_id)) {
+ if (nonexisting_handle(handle, thread_id)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
diff --git a/libpthread/linuxthreads/linuxthreads.texi b/libpthread/linuxthreads/linuxthreads.texi
index 7a98103b3..795fb7097 100644
--- a/libpthread/linuxthreads/linuxthreads.texi
+++ b/libpthread/linuxthreads/linuxthreads.texi
@@ -19,7 +19,7 @@ use @var{errno}.
* Thread Attributes:: Tuning thread scheduling.
* Cancellation:: Stopping a thread before it's done.
* Cleanup Handlers:: Deallocating resources when a thread is
- cancelled.
+ canceled.
* Mutexes:: One way to synchronize threads.
* Condition Variables:: Another way.
* POSIX Semaphores:: And a third way.
@@ -27,6 +27,10 @@ use @var{errno}.
different threads.
* Threads and Signal Handling:: Why you should avoid mixing the two, and
how to do it if you must.
+* Threads and Fork:: Interactions between threads and the
+ @code{fork} function.
+* Streams and Fork:: Interactions between stdio streams and
+ @code{fork}.
* Miscellaneous Thread Functions:: A grab bag of utility routines.
@end menu
@@ -98,12 +102,12 @@ returns 0. @xref{Cancellation}, for details.
@deftypefun int pthread_join (pthread_t @var{th}, void **thread_@var{return})
@code{pthread_join} suspends the execution of the calling thread until
the thread identified by @var{th} terminates, either by calling
-@code{pthread_exit} or by being cancelled.
+@code{pthread_exit} or by being canceled.
If @var{thread_return} is not @code{NULL}, the return value of @var{th}
is stored in the location pointed to by @var{thread_return}. The return
value of @var{th} is either the argument it gave to @code{pthread_exit},
-or @code{PTHREAD_CANCELED} if @var{th} was cancelled.
+or @code{PTHREAD_CANCELED} if @var{th} was canceled.
The joined thread @code{th} must be in the joinable state: it must not
have been detached using @code{pthread_detach} or the
@@ -177,13 +181,18 @@ left in an undefined state, and you must not use it again in a call to
any pthreads function until it has been reinitialized.
@end deftypefun
+@findex pthread_attr_setdetachstate
+@findex pthread_attr_setguardsize
@findex pthread_attr_setinheritsched
@findex pthread_attr_setschedparam
@findex pthread_attr_setschedpolicy
@findex pthread_attr_setscope
+@findex pthread_attr_setstack
+@findex pthread_attr_setstackaddr
+@findex pthread_attr_setstacksize
@comment pthread.h
@comment POSIX
-@deftypefun int pthread_attr_set@var{attr} (pthread_attr_t *@var{obj}, int @var{value})
+@deftypefun int pthread_attr_setattr (pthread_attr_t *@var{obj}, int @var{value})
Set attribute @var{attr} to @var{value} in the attribute object pointed
to by @var{obj}. See below for a list of possible attributes and the
values they can take.
@@ -194,13 +203,18 @@ for the @var{attr} being modified, they will return the error code
below.
@end deftypefun
+@findex pthread_attr_getdetachstate
+@findex pthread_attr_getguardsize
@findex pthread_attr_getinheritsched
@findex pthread_attr_getschedparam
@findex pthread_attr_getschedpolicy
@findex pthread_attr_getscope
+@findex pthread_attr_getstack
+@findex pthread_attr_getstackaddr
+@findex pthread_attr_getstacksize
@comment pthread.h
@comment POSIX
-@deftypefun int pthread_attr_get@var{attr} (const pthread_attr_t *@var{obj}, int *@var{value})
+@deftypefun int pthread_attr_getattr (const pthread_attr_t *@var{obj}, int *@var{value})
Store the current setting of @var{attr} in @var{obj} into the variable
pointed to by @var{value}.
@@ -275,8 +289,45 @@ interpreted relative to the priorities of the other threads of the
process, regardless of the priorities of other processes.
@code{PTHREAD_SCOPE_PROCESS} is not supported in LinuxThreads. If you
-try to set the scope to this value @code{pthread_attr_setscope} will
+try to set the scope to this value, @code{pthread_attr_setscope} will
fail and return @code{ENOTSUP}.
+
+@item stackaddr
+Provide an address for an application managed stack. The size of the
+stack must be at least @code{PTHREAD_STACK_MIN}.
+
+@item stacksize
+Change the size of the stack created for the thread. The value defines
+the minimum stack size, in bytes.
+
+If the value exceeds the system's maximum stack size, or is smaller
+than @code{PTHREAD_STACK_MIN}, @code{pthread_attr_setstacksize} will
+fail and return @code{EINVAL}.
+
+@item stack
+Provide both the address and size of an application managed stack to
+use for the new thread. The base of the memory area is @var{stackaddr}
+with the size of the memory area, @var{stacksize}, measured in bytes.
+
+If the value of @var{stacksize} is less than @code{PTHREAD_STACK_MIN},
+or greater than the system's maximum stack size, or if the value of
+@var{stackaddr} lacks the proper alignment, @code{pthread_attr_setstack}
+will fail and return @code{EINVAL}.
+
+@item guardsize
+Change the minimum size in bytes of the guard area for the thread's
+stack. The default size is a single page. If this value is set, it
+will be rounded up to the nearest page size. If the value is set to 0,
+a guard area will not be created for this thread. The space allocated
+for the guard area is used to catch stack overflow. Therefore, when
+allocating large structures on the stack, a larger guard area may be
+required to catch a stack overflow.
+
+If the caller is managing their own stacks (if the @code{stackaddr}
+attribute has been set), then the @code{guardsize} attribute is ignored.
+
+If the value exceeds the @code{stacksize}, @code{pthread_atrr_setguardsize}
+will fail and return @code{EINVAL}.
@end table
@node Cancellation
@@ -294,7 +345,7 @@ When a thread eventually honors a cancellation request, it behaves as if
@code{pthread_exit(PTHREAD_CANCELED)} was called. All cleanup handlers
are executed in reverse order, finalization functions for
thread-specific data are called, and finally the thread stops executing.
-If the cancelled thread was joinable, the return value
+If the canceled thread was joinable, the return value
@code{PTHREAD_CANCELED} is provided to whichever thread calls
@var{pthread_join} on it. See @code{pthread_exit} for more information.
@@ -377,7 +428,7 @@ stack-like discipline.
The purpose of cleanup handlers is to free the resources that a thread
may hold at the time it terminates. In particular, if a thread exits or
-is cancelled while it owns a locked mutex, the mutex will remain locked
+is canceled while it owns a locked mutex, the mutex will remain locked
forever and prevent other threads from executing normally. The best way
to avoid this is, just before locking the mutex, to install a cleanup
handler whose effect is to unlock the mutex. Cleanup handlers can be
@@ -493,7 +544,7 @@ The sequence
@smallexample
pthread_cleanup_push_defer_np(routine, arg);
...
-pthread_cleanup_pop_defer_np(execute);
+pthread_cleanup_pop_restore_np(execute);
@end smallexample
@noindent
@@ -546,15 +597,16 @@ calling thread.
If @var{mutexattr} is @code{NULL}, default attributes are used instead.
The LinuxThreads implementation supports only one mutex attribute,
-the @var{mutex kind}, which is either ``fast'', ``recursive'', or
-``error checking''. The kind of a mutex determines whether
+the @var{mutex type}, which is either ``fast'', ``recursive'', or
+``error checking''. The type of a mutex determines whether
it can be locked again by a thread that already owns it.
-The default kind is ``fast''.
+The default type is ``fast''.
Variables of type @code{pthread_mutex_t} can also be initialized
statically, using the constants @code{PTHREAD_MUTEX_INITIALIZER} (for
-fast mutexes), @code{PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} (for
-recursive mutexes), and @code{PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP}
+timed mutexes), @code{PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} (for
+recursive mutexes), @code{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP}
+(for fast mutexes(, and @code{PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP}
(for error checking mutexes).
@code{pthread_mutex_init} always returns 0.
@@ -570,16 +622,17 @@ already locked by another thread, @code{pthread_mutex_lock} suspends the
calling thread until the mutex is unlocked.
If the mutex is already locked by the calling thread, the behavior of
-@code{pthread_mutex_lock} depends on the kind of the mutex. If the mutex
-is of the ``fast'' kind, the calling thread is suspended. It will
+@code{pthread_mutex_lock} depends on the type of the mutex. If the mutex
+is of the ``fast'' type, the calling thread is suspended. It will
remain suspended forever, because no other thread can unlock the mutex.
-If the mutex is of the ``error checking'' kind, @code{pthread_mutex_lock}
+If the mutex is of the ``error checking'' type, @code{pthread_mutex_lock}
returns immediately with the error code @code{EDEADLK}. If the mutex is
-of the ``recursive'' kind, @code{pthread_mutex_lock} succeeds and
+of the ``recursive'' type, @code{pthread_mutex_lock} succeeds and
returns immediately, recording the number of times the calling thread
has locked the mutex. An equal number of @code{pthread_mutex_unlock}
operations must be performed before the mutex returns to the unlocked
state.
+@c This doesn't discuss PTHREAD_MUTEX_TIMED_NP mutex attributes. FIXME
@end deftypefun
@comment pthread.h
@@ -595,12 +648,31 @@ calling thread in the case of a ``fast'' mutex). Instead,
@comment pthread.h
@comment POSIX
+@deftypefun int pthread_mutex_timedlock (pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime})
+The @code{pthread_mutex_timedlock} is similar to the
+@code{pthread_mutex_lock} function but instead of blocking for in
+indefinite time if the mutex is locked by another thread, it returns
+when the time specified in @var{abstime} is reached.
+
+This function can only be used on standard (``timed'') and ``error
+checking'' mutexes. It behaves just like @code{pthread_mutex_lock} for
+all other types.
+
+If the mutex is successfully locked, the function returns zero. If the
+time specified in @var{abstime} is reached without the mutex being locked,
+@code{ETIMEDOUT} is returned.
+
+This function was introduced in the POSIX.1d revision of the POSIX standard.
+@end deftypefun
+
+@comment pthread.h
+@comment POSIX
@deftypefun int pthread_mutex_unlock (pthread_mutex_t *@var{mutex})
@code{pthread_mutex_unlock} unlocks the given mutex. The mutex is
assumed to be locked and owned by the calling thread on entrance to
-@code{pthread_mutex_unlock}. If the mutex is of the ``fast'' kind,
+@code{pthread_mutex_unlock}. If the mutex is of the ``fast'' type,
@code{pthread_mutex_unlock} always returns it to the unlocked state. If
-it is of the ``recursive'' kind, it decrements the locking count of the
+it is of the ``recursive'' type, it decrements the locking count of the
mutex (number of @code{pthread_mutex_lock} operations performed on it by
the calling thread), and only when this count reaches zero is the mutex
actually unlocked.
@@ -673,45 +745,52 @@ LinuxThreads implementation.
This function always returns 0.
@end deftypefun
-LinuxThreads supports only one mutex attribute: the mutex kind, which is
-either @code{PTHREAD_MUTEX_FAST_NP} for ``fast'' mutexes,
-@code{PTHREAD_MUTEX_RECURSIVE_NP} for ``recursive'' mutexes, or
+LinuxThreads supports only one mutex attribute: the mutex type, which is
+either @code{PTHREAD_MUTEX_ADAPTIVE_NP} for ``fast'' mutexes,
+@code{PTHREAD_MUTEX_RECURSIVE_NP} for ``recursive'' mutexes,
+@code{PTHREAD_MUTEX_TIMED_NP} for ``timed'' mutexes, or
@code{PTHREAD_MUTEX_ERRORCHECK_NP} for ``error checking'' mutexes. As
the @code{NP} suffix indicates, this is a non-portable extension to the
POSIX standard and should not be employed in portable programs.
-The mutex kind determines what happens if a thread attempts to lock a
+The mutex type determines what happens if a thread attempts to lock a
mutex it already owns with @code{pthread_mutex_lock}. If the mutex is of
-the ``fast'' kind, @code{pthread_mutex_lock} simply suspends the calling
-thread forever. If the mutex is of the ``error checking'' kind,
+the ``fast'' type, @code{pthread_mutex_lock} simply suspends the calling
+thread forever. If the mutex is of the ``error checking'' type,
@code{pthread_mutex_lock} returns immediately with the error code
-@code{EDEADLK}. If the mutex is of the ``recursive'' kind, the call to
+@code{EDEADLK}. If the mutex is of the ``recursive'' type, the call to
@code{pthread_mutex_lock} returns immediately with a success return
code. The number of times the thread owning the mutex has locked it is
recorded in the mutex. The owning thread must call
@code{pthread_mutex_unlock} the same number of times before the mutex
returns to the unlocked state.
-The default mutex kind is ``fast'', that is, @code{PTHREAD_MUTEX_FAST_NP}.
+The default mutex type is ``timed'', that is, @code{PTHREAD_MUTEX_TIMED_NP}.
+@c This doesn't describe how a ``timed'' mutex behaves. FIXME
@comment pthread.h
-@comment GNU
-@deftypefun int pthread_mutexattr_setkind_np (pthread_mutexattr_t *@var{attr}, int @var{kind})
-@code{pthread_mutexattr_setkind_np} sets the mutex kind attribute in
-@var{attr} to the value specified by @var{kind}.
+@comment POSIX
+@deftypefun int pthread_mutexattr_settype (pthread_mutexattr_t *@var{attr}, int @var{type})
+@code{pthread_mutexattr_settype} sets the mutex type attribute in
+@var{attr} to the value specified by @var{type}.
-If @var{kind} is not @code{PTHREAD_MUTEX_FAST_NP},
-@code{PTHREAD_MUTEX_RECURSIVE_NP}, or
+If @var{type} is not @code{PTHREAD_MUTEX_ADAPTIVE_NP},
+@code{PTHREAD_MUTEX_RECURSIVE_NP}, @code{PTHREAD_MUTEX_TIMED_NP}, or
@code{PTHREAD_MUTEX_ERRORCHECK_NP}, this function will return
@code{EINVAL} and leave @var{attr} unchanged.
+
+The standard Unix98 identifiers @code{PTHREAD_MUTEX_DEFAULT},
+@code{PTHREAD_MUTEX_NORMAL}, @code{PTHREAD_MUTEX_RECURSIVE},
+and @code{PTHREAD_MUTEX_ERRORCHECK} are also permitted.
+
@end deftypefun
@comment pthread.h
-@comment GNU
-@deftypefun int pthread_mutexattr_getkind_np (const pthread_mutexattr_t *@var{attr}, int *@var{kind})
-@code{pthread_mutexattr_getkind_np} retrieves the current value of the
-mutex kind attribute in @var{attr} and stores it in the location pointed
-to by @var{kind}.
+@comment POSIX
+@deftypefun int pthread_mutexattr_gettype (const pthread_mutexattr_t *@var{attr}, int *@var{type})
+@code{pthread_mutexattr_gettype} retrieves the current value of the
+mutex type attribute in @var{attr} and stores it in the location pointed
+to by @var{type}.
This function always returns 0.
@end deftypefun
@@ -820,7 +899,7 @@ nothing.
@end deftypefun
@code{pthread_cond_wait} and @code{pthread_cond_timedwait} are
-cancellation points. If a thread is cancelled while suspended in one of
+cancellation points. If a thread is canceled while suspended in one of
these functions, the thread immediately resumes execution, relocks the
mutex specified by @var{mutex}, and finally executes the cancellation.
Consequently, cleanup handlers are assured that @var{mutex} is locked
@@ -1237,6 +1316,141 @@ threads must not attach their own signal handlers to these signals, or
alternatively they should all block these signals (which is recommended
anyway).
+@node Threads and Fork
+@section Threads and Fork
+
+It's not intuitively obvious what should happen when a multi-threaded POSIX
+process calls @code{fork}. Not only are the semantics tricky, but you may
+need to write code that does the right thing at fork time even if that code
+doesn't use the @code{fork} function. Moreover, you need to be aware of
+interaction between @code{fork} and some library features like
+@code{pthread_once} and stdio streams.
+
+When @code{fork} is called by one of the threads of a process, it creates a new
+process which is copy of the calling process. Effectively, in addition to
+copying certain system objects, the function takes a snapshot of the memory
+areas of the parent process, and creates identical areas in the child.
+To make matters more complicated, with threads it's possible for two or more
+threads to concurrently call fork to create two or more child processes.
+
+The child process has a copy of the address space of the parent, but it does
+not inherit any of its threads. Execution of the child process is carried out
+by a new thread which returns from @code{fork} function with a return value of
+zero; it is the only thread in the child process. Because threads are not
+inherited across fork, issues arise. At the time of the call to @code{fork},
+threads in the parent process other than the one calling @code{fork} may have
+been executing critical regions of code. As a result, the child process may
+get a copy of objects that are not in a well-defined state. This potential
+problem affects all components of the program.
+
+Any program component which will continue being used in a child process must
+correctly handle its state during @code{fork}. For this purpose, the POSIX
+interface provides the special function @code{pthread_atfork} for installing
+pointers to handler functions which are called from within @code{fork}.
+
+@comment pthread.h
+@comment POSIX
+@deftypefun int pthread_atfork (void (*@var{prepare})(void), void (*@var{parent})(void), void (*@var{child})(void))
+
+@code{pthread_atfork} registers handler functions to be called just
+before and just after a new process is created with @code{fork}. The
+@var{prepare} handler will be called from the parent process, just
+before the new process is created. The @var{parent} handler will be
+called from the parent process, just before @code{fork} returns. The
+@var{child} handler will be called from the child process, just before
+@code{fork} returns.
+
+@code{pthread_atfork} returns 0 on success and a non-zero error code on
+error.
+
+One or more of the three handlers @var{prepare}, @var{parent} and
+@var{child} can be given as @code{NULL}, meaning that no handler needs
+to be called at the corresponding point.
+
+@code{pthread_atfork} can be called several times to install several
+sets of handlers. At @code{fork} time, the @var{prepare} handlers are
+called in LIFO order (last added with @code{pthread_atfork}, first
+called before @code{fork}), while the @var{parent} and @var{child}
+handlers are called in FIFO order (first added, first called).
+
+If there is insufficient memory available to register the handlers,
+@code{pthread_atfork} fails and returns @code{ENOMEM}. Otherwise it
+returns 0.
+
+The functions @code{fork} and @code{pthread_atfork} must not be regarded as
+reentrant from the context of the handlers. That is to say, if a
+@code{pthread_atfork} handler invoked from within @code{fork} calls
+@code{pthread_atfork} or @code{fork}, the behavior is undefined.
+
+Registering a triplet of handlers is an atomic operation with respect to fork.
+If new handlers are registered at about the same time as a fork occurs, either
+all three handlers will be called, or none of them will be called.
+
+The handlers are inherited by the child process, and there is no
+way to remove them, short of using @code{exec} to load a new
+pocess image.
+
+@end deftypefun
+
+To understand the purpose of @code{pthread_atfork}, recall that
+@code{fork} duplicates the whole memory space, including mutexes in
+their current locking state, but only the calling thread: other threads
+are not running in the child process. The mutexes are not usable after
+the @code{fork} and must be initialized with @code{pthread_mutex_init}
+in the child process. This is a limitation of the current
+implementation and might or might not be present in future versions.
+
+To avoid this, install handlers with @code{pthread_atfork} as follows: have the
+@var{prepare} handler lock the mutexes (in locking order), and the
+@var{parent} handler unlock the mutexes. The @var{child} handler should reset
+the mutexes using @code{pthread_mutex_init}, as well as any other
+synchronization objects such as condition variables.
+
+Locking the global mutexes before the fork ensures that all other threads are
+locked out of the critical regions of code protected by those mutexes. Thus
+when @code{fork} takes a snapshot of the parent's address space, that snapshot
+will copy valid, stable data. Resetting the synchronization objects in the
+child process will ensure they are properly cleansed of any artifacts from the
+threading subsystem of the parent process. For example, a mutex may inherit
+a wait queue of threads waiting for the lock; this wait queue makes no sense
+in the child process. Initializing the mutex takes care of this.
+
+@node Streams and Fork
+@section Streams and Fork
+
+The GNU standard I/O library has an internal mutex which guards the internal
+linked list of all standard C FILE objects. This mutex is properly taken care
+of during @code{fork} so that the child receives an intact copy of the list.
+This allows the @code{fopen} function, and related stream-creating functions,
+to work correctly in the child process, since these functions need to insert
+into the list.
+
+However, the individual stream locks are not completely taken care of. Thus
+unless the multithreaded application takes special precautions in its use of
+@code{fork}, the child process might not be able to safely use the streams that
+it inherited from the parent. In general, for any given open stream in the
+parent that is to be used by the child process, the application must ensure
+that that stream is not in use by another thread when @code{fork} is called.
+Otherwise an inconsistent copy of the stream object be produced. An easy way to
+ensure this is to use @code{flockfile} to lock the stream prior to calling
+@code{fork} and then unlock it with @code{funlockfile} inside the parent
+process, provided that the parent's threads properly honor these locks.
+Nothing special needs to be done in the child process, since the library
+internally resets all stream locks.
+
+Note that the stream locks are not shared between the parent and child.
+For example, even if you ensure that, say, the stream @code{stdout} is properly
+treated and can be safely used in the child, the stream locks do not provide
+an exclusion mechanism between the parent and child. If both processes write
+to @code{stdout}, strangely interleaved output may result regardless of
+the explicit use of @code{flockfile} or implicit locks.
+
+Also note that these provisions are a GNU extension; other systems might not
+provide any way for streams to be used in the child of a multithreaded process.
+POSIX requires that such a child process confines itself to calling only
+asynchronous safe functions, which excludes much of the library, including
+standard I/O.
+
@node Miscellaneous Thread Functions
@section Miscellaneous Thread Functions
@@ -1287,49 +1501,6 @@ The thread @var{th} is already in the detached state
@end deftypefun
@comment pthread.h
-@comment POSIX
-@deftypefun int pthread_atfork (void (*@var{prepare})(void), void (*@var{parent})(void), void (*@var{child})(void))
-
-@code{pthread_atfork} registers handler functions to be called just
-before and just after a new process is created with @code{fork}. The
-@var{prepare} handler will be called from the parent process, just
-before the new process is created. The @var{parent} handler will be
-called from the parent process, just before @code{fork} returns. The
-@var{child} handler will be called from the child process, just before
-@code{fork} returns.
-
-@code{pthread_atfork} returns 0 on success and a non-zero error code on
-error.
-
-One or more of the three handlers @var{prepare}, @var{parent} and
-@var{child} can be given as @code{NULL}, meaning that no handler needs
-to be called at the corresponding point.
-
-@code{pthread_atfork} can be called several times to install several
-sets of handlers. At @code{fork} time, the @var{prepare} handlers are
-called in LIFO order (last added with @code{pthread_atfork}, first
-called before @code{fork}), while the @var{parent} and @var{child}
-handlers are called in FIFO order (first added, first called).
-
-If there is insufficient memory available to register the handlers,
-@code{pthread_atfork} fails and returns @code{ENOMEM}. Otherwise it
-returns 0.
-@end deftypefun
-
-To understand the purpose of @code{pthread_atfork}, recall that
-@code{fork} duplicates the whole memory space, including mutexes in
-their current locking state, but only the calling thread: other threads
-are not running in the child process. Thus, if a mutex is locked by a
-thread other than the thread calling @code{fork}, that mutex will remain
-locked forever in the child process, possibly blocking the execution of
-the child process. To avoid this, install handlers with
-@code{pthread_atfork} as follows: the @var{prepare} handler locks the
-global mutexes (in locking order), and the @var{parent} and @var{child}
-handlers unlock them (in reverse order). Alternatively, @var{prepare}
-and @var{parent} can be set to @code{NULL} and @var{child} to a function
-that calls @code{pthread_mutex_init} on the global mutexes.
-
-@comment pthread.h
@comment GNU
@deftypefun void pthread_kill_other_threads_np (@var{void})
@code{pthread_kill_other_threads_np} is a non-portable LinuxThreads extension.
@@ -1368,6 +1539,15 @@ record that initialization has been performed. Subsequent calls to
@code{pthread_once} with the same @code{once_control} argument do
nothing.
+If a thread is cancelled while executing @var{init_routine}
+the state of the @var{once_control} variable is reset so that
+a future call to @code{pthread_once} will call the routine again.
+
+If the process forks while one or more threads are executing
+@code{pthread_once} initialization routines, the states of their respective
+@var{once_control} variables will appear to be reset in the child process so
+that if the child calls @code{pthread_once}, the routines will be executed.
+
@code{pthread_once} always returns 0.
@end deftypefun
@@ -1426,3 +1606,22 @@ The @var{target_thread} is invalid or has already terminated.
@end table
@end deftypefun
+
+@comment pthread.h
+@comment POSIX
+@deftypefun int pthread_setconcurrency (int @var{level})
+@code{pthread_setconcurrency} is unused in LinuxThreads due to the lack
+of a mapping of user threads to kernel threads. It exists for source
+compatibility. It does store the value @var{level} so that it can be
+returned by a subsequent call to @code{pthread_getconcurrency}. It takes
+no other action however.
+@end deftypefun
+
+@comment pthread.h
+@comment POSIX
+@deftypefun int pthread_getconcurrency ()
+@code{pthread_getconcurrency} is unused in LinuxThreads due to the lack
+of a mapping of user threads to kernel threads. It exists for source
+compatibility. However, it will return the value that was set by the
+last call to @code{pthread_setconcurrency}.
+@end deftypefun
diff --git a/libpthread/linuxthreads/lockfile.c b/libpthread/linuxthreads/lockfile.c
index d54377fc0..b0f41c98a 100644
--- a/libpthread/linuxthreads/lockfile.c
+++ b/libpthread/linuxthreads/lockfile.c
@@ -1,18 +1,18 @@
/* lockfile - Handle locking and unlocking of stream.
- Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
+ You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c
index 204344aef..a00c9b13e 100644
--- a/libpthread/linuxthreads/manager.c
+++ b/libpthread/linuxthreads/manager.c
@@ -14,9 +14,12 @@
/* The "thread manager" thread: manages creation and termination of threads */
-/* mods for uClibc: getpwd and getpagesize are the syscalls */
+/* mods for uClibc */
#define __getpid getpid
#define __getpagesize getpagesize
+#define __sched_get_priority_max sched_get_priority_max
+#define __sched_getscheduler sched_getscheduler
+#define __sched_getparam sched_getparam
#include <features.h>
#define __USE_GNU
@@ -81,8 +84,13 @@ volatile pthread_descr __pthread_last_event;
static inline pthread_descr thread_segment(int seg)
{
+# ifdef _STACK_GROWS_UP
+ return (pthread_descr)(THREAD_STACK_START_ADDRESS + (seg - 1) * STACK_SIZE)
+ + 1;
+# else
return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
- 1;
+# endif
}
/* Flag set in signal handler to record child termination */
@@ -107,13 +115,18 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
int report_events,
td_thr_events_t *event_maskp);
static void pthread_handle_free(pthread_t th_id);
-static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode);
+static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
+ __attribute__ ((noreturn));
static void pthread_reap_children(void);
static void pthread_kill_all_threads(int sig, int main_thread_also);
+static void pthread_for_each_thread(void *arg,
+ void (*fn)(void *, pthread_descr));
/* The server thread managing requests for thread creation and termination */
-int __pthread_manager(void *arg)
+int
+__attribute__ ((noreturn))
+__pthread_manager(void *arg)
{
int reqfd = (int) (long int) arg;
#ifdef USE_SELECT
@@ -144,7 +157,7 @@ int __pthread_manager(void *arg)
sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */
if (__pthread_threads_debug && __pthread_sig_debug > 0)
- sigdelset(&manager_mask, __pthread_sig_debug);
+ sigdelset(&manager_mask, __pthread_sig_debug);
sigprocmask(SIG_SETMASK, &manager_mask, NULL);
/* Raise our priority to match that of main thread */
__pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
@@ -240,14 +253,21 @@ int __pthread_manager(void *arg)
PDEBUG("got REQ_DEBUG\n");
/* Make gdb aware of new thread and gdb will restart the
new thread when it is ready to handle the new thread. */
- if (__pthread_threads_debug && __pthread_sig_debug > 0) {
- PDEBUG("about to call raise(__pthread_sig_debug)\n");
+ if (__pthread_threads_debug && __pthread_sig_debug > 0)
+ {
+ PDEBUG("about to call raise(__pthread_sig_debug)\n");
raise(__pthread_sig_debug);
}
+ break;
case REQ_KICK:
/* This is just a prod to get the manager to reap some
threads right away, avoiding a potential delay at shutdown. */
break;
+ case REQ_FOR_EACH_THREAD:
+ pthread_for_each_thread(request.req_args.for_each.arg,
+ request.req_args.for_each.fn);
+ restart(request.req_thread);
+ break;
}
}
}
@@ -269,6 +289,7 @@ int __pthread_manager_event(void *arg)
}
/* Process creation */
+
static int
__attribute__ ((noreturn))
pthread_start_thread(void *arg)
@@ -276,10 +297,17 @@ pthread_start_thread(void *arg)
pthread_descr self = (pthread_descr) arg;
struct pthread_request request;
void * outcome;
+#if HP_TIMING_AVAIL
+ hp_timing_t tmpclock;
+#endif
/* Initialize special thread_self processing, if any. */
#ifdef INIT_THREAD_SELF
INIT_THREAD_SELF(self, self->p_nr);
#endif
+#if HP_TIMING_AVAIL
+ HP_TIMING_NOW (tmpclock);
+ THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
+#endif
PDEBUG("\n");
/* Make sure our pid field is initialized, just in case we get there
before our father has initialized it. */
@@ -353,12 +381,39 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
if (attr != NULL && attr->__stackaddr_set)
{
+#ifdef _STACK_GROWS_UP
/* The user provided a stack. */
+# ifdef USE_TLS
+ /* This value is not needed. */
+ new_thread = (pthread_descr) attr->__stackaddr;
+ new_thread_bottom = (char *) new_thread;
+# else
+ new_thread = (pthread_descr) attr->__stackaddr;
+ new_thread_bottom = (char *) (new_thread + 1);
+# endif
+ guardaddr = attr->__stackaddr + attr->__stacksize;
+ guardsize = 0;
+#else
+ /* The user provided a stack. For now we interpret the supplied
+ address as 1 + the highest addr. in the stack segment. If a
+ separate register stack is needed, we place it at the low end
+ of the segment, relying on the associated stacksize to
+ determine the low end of the segment. This differs from many
+ (but not all) other pthreads implementations. The intent is
+ that on machines with a single stack growing toward higher
+ addresses, stackaddr would be the lowest address in the stack
+ segment, so that it is consistently close to the initial sp
+ value. */
+# ifdef USE_TLS
+ new_thread = (pthread_descr) attr->__stackaddr;
+# else
new_thread =
(pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
+# endif
new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
guardaddr = NULL;
guardsize = 0;
+#endif
__pthread_nonstandard_stacks = 1;
}
else
@@ -483,7 +538,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
/* First check whether we have to change the policy and if yes, whether
we can do this. Normally this should be done by examining the
- return value of the sched_setscheduler call in pthread_start_thread
+ return value of the __sched_setscheduler call in pthread_start_thread
but this is hard to implement. FIXME */
if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0)
return EPERM;
@@ -536,8 +591,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
sizeof (struct sched_param));
break;
case PTHREAD_INHERIT_SCHED:
- new_thread->p_start_args.schedpolicy = sched_getscheduler(father_pid);
- sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
+ new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
+ __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
break;
}
new_thread->p_priority =
@@ -578,17 +633,36 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
__pthread_lock(new_thread->p_lock, NULL);
/* We have to report this event. */
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ /* Perhaps this version should be used on all platforms. But
+ this requires that __clone2 be uniformly supported
+ everywhere.
+
+ And there is some argument for changing the __clone2
+ interface to pass sp and bsp instead, making it more IA64
+ specific, but allowing stacks to grow outward from each
+ other, to get less paging and fewer mmaps. */
+ pid = __clone2(pthread_start_thread_event,
+ (void **)new_thread_bottom,
+ (char *)stack_addr - new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+ pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#else
pid = clone(pthread_start_thread_event, (void **) new_thread,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
-
+#endif
saved_errno = errno;
if (pid != -1)
{
/* Now fill in the information about the new thread in
- the newly created thread's data structure. We cannot let
- the new thread do this since we don't know whether it was
- already scheduled when we send the event. */
+ the newly created thread's data structure. We cannot let
+ the new thread do this since we don't know whether it was
+ already scheduled when we send the event. */
new_thread->p_eventbuf.eventdata = new_thread;
new_thread->p_eventbuf.eventnum = TD_CREATE;
__pthread_last_event = new_thread;
@@ -609,9 +683,21 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
if (pid == 0)
{
PDEBUG("cloning new_thread = %p\n", new_thread);
+#ifdef NEED_SEPARATE_REGISTER_STACK
+ pid = __clone2(pthread_start_thread,
+ (void **)new_thread_bottom,
+ (char *)stack_addr - new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+ pid = __clone(pthread_start_thread, (void *) new_thread_bottom,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ __pthread_sig_cancel, new_thread);
+#else
pid = clone(pthread_start_thread, (void **) new_thread,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
__pthread_sig_cancel, new_thread);
+#endif /* !NEED_SEPARATE_REGISTER_STACK */
saved_errno = errno;
}
/* Check if cloning succeeded */
@@ -805,7 +891,7 @@ static void pthread_handle_free(pthread_t th_id)
pthread_descr th;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, th_id)) {
+ if (nonexisting_handle(handle, th_id)) {
/* pthread_reap_children has deallocated the thread already,
nothing needs to be done */
__pthread_unlock(&handle->h_lock);
@@ -839,6 +925,20 @@ static void pthread_kill_all_threads(int sig, int main_thread_also)
}
}
+static void pthread_for_each_thread(void *arg,
+ void (*fn)(void *, pthread_descr))
+{
+ pthread_descr th;
+
+ for (th = __pthread_main_thread->p_nextlive;
+ th != __pthread_main_thread;
+ th = th->p_nextlive) {
+ fn(arg, th);
+ }
+
+ fn(arg, __pthread_main_thread);
+}
+
/* Process-wide exit() */
static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
@@ -898,7 +998,7 @@ void __pthread_manager_adjust_prio(int thread_prio)
if (thread_prio <= __pthread_manager_thread.p_priority) return;
param.sched_priority =
- thread_prio < sched_get_priority_max(SCHED_FIFO)
+ thread_prio < __sched_get_priority_max(SCHED_FIFO)
? thread_prio + 1 : thread_prio;
sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, &param);
__pthread_manager_thread.p_priority = thread_prio;
diff --git a/libpthread/linuxthreads/mutex.c b/libpthread/linuxthreads/mutex.c
index 7cc344fac..25f6f98c2 100644
--- a/libpthread/linuxthreads/mutex.c
+++ b/libpthread/linuxthreads/mutex.c
@@ -24,6 +24,9 @@
#include "queue.h"
#include "restart.h"
+#undef hidden_def
+#define hidden_def(sym)
+
int __pthread_mutex_init(pthread_mutex_t * mutex,
const pthread_mutexattr_t * mutex_attr)
{
@@ -35,6 +38,7 @@ int __pthread_mutex_init(pthread_mutex_t * mutex,
return 0;
}
strong_alias (__pthread_mutex_init, pthread_mutex_init)
+hidden_def (__pthread_mutex_init)
int __pthread_mutex_destroy(pthread_mutex_t * mutex)
{
@@ -54,6 +58,7 @@ int __pthread_mutex_destroy(pthread_mutex_t * mutex)
}
}
strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
+hidden_def (__pthread_mutex_destroy)
int __pthread_mutex_trylock(pthread_mutex_t * mutex)
{
@@ -90,6 +95,7 @@ int __pthread_mutex_trylock(pthread_mutex_t * mutex)
}
}
strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
+hidden_def (__pthread_mutex_trylock)
int __pthread_mutex_lock(pthread_mutex_t * mutex)
{
@@ -123,6 +129,7 @@ int __pthread_mutex_lock(pthread_mutex_t * mutex)
}
}
strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
+hidden_def (__pthread_mutex_lock)
int __pthread_mutex_timedlock (pthread_mutex_t *mutex,
const struct timespec *abstime)
@@ -198,6 +205,7 @@ int __pthread_mutex_unlock(pthread_mutex_t * mutex)
}
}
strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
+hidden_def (__pthread_mutex_unlock)
int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
diff --git a/libpthread/linuxthreads/oldsemaphore.c b/libpthread/linuxthreads/oldsemaphore.c
index 3a3b3d186..ecf7d7019 100644
--- a/libpthread/linuxthreads/oldsemaphore.c
+++ b/libpthread/linuxthreads/oldsemaphore.c
@@ -32,9 +32,6 @@ typedef struct {
int sem_spinlock;
} old_sem_t;
-/* Maximum value the semaphore can have. */
-#define SEM_VALUE_MAX ((int) ((~0u) >> 1))
-
static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval)
{
return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock);
@@ -63,7 +60,7 @@ int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value)
errno = ENOSYS;
return -1;
}
- sem->sem_spinlock = 0;
+ sem->sem_spinlock = __LT_SPINLOCK_INIT;
sem->sem_status = ((long)value << 1) + 1;
return 0;
}
@@ -90,7 +87,7 @@ int __old_sem_wait(old_sem_t * sem)
while (1) {
/* Register extrication interface */
- __pthread_set_own_extricate_if(self, &extr);
+ __pthread_set_own_extricate_if(self, &extr);
do {
oldstatus = sem->sem_status;
if ((oldstatus & 1) && (oldstatus != 1))
@@ -103,12 +100,13 @@ int __old_sem_wait(old_sem_t * sem)
while (! sem_compare_and_swap(sem, oldstatus, newstatus));
if (newstatus & 1) {
/* We got the semaphore. */
- __pthread_set_own_extricate_if(self, 0);
+ __pthread_set_own_extricate_if(self, 0);
+ self->p_nextwaiting = NULL;
return 0;
}
/* Wait for sem_post or cancellation */
suspend(self);
- __pthread_set_own_extricate_if(self, 0);
+ __pthread_set_own_extricate_if(self, 0);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
diff --git a/libpthread/linuxthreads/pt-machine.c b/libpthread/linuxthreads/pt-machine.c
index 438008d5d..5cd477ce9 100644
--- a/libpthread/linuxthreads/pt-machine.c
+++ b/libpthread/linuxthreads/pt-machine.c
@@ -3,20 +3,23 @@
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
+ You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#define PT_EI
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
#include <pt-machine.h>
diff --git a/libpthread/linuxthreads/pthread.c b/libpthread/linuxthreads/pthread.c
index fed3d8c72..5b038acb8 100644
--- a/libpthread/linuxthreads/pthread.c
+++ b/libpthread/linuxthreads/pthread.c
@@ -54,55 +54,63 @@ extern int _h_errno;
/* Descriptor of the initial thread */
struct _pthread_descr_struct __pthread_initial_thread = {
- &__pthread_initial_thread, /* pthread_descr p_nextlive */
- &__pthread_initial_thread, /* pthread_descr p_prevlive */
- NULL, /* pthread_descr p_nextwaiting */
- NULL, /* pthread_descr p_nextlock */
- PTHREAD_THREADS_MAX, /* pthread_t p_tid */
- 0, /* int p_pid */
- 0, /* int p_priority */
- &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */
- 0, /* int p_signal */
- NULL, /* sigjmp_buf * p_signal_buf */
- NULL, /* sigjmp_buf * p_cancel_buf */
- 0, /* char p_terminated */
- 0, /* char p_detached */
- 0, /* char p_exited */
- NULL, /* void * p_retval */
- 0, /* int p_retval */
- NULL, /* pthread_descr p_joining */
- NULL, /* struct _pthread_cleanup_buffer * p_cleanup */
- 0, /* char p_cancelstate */
- 0, /* char p_canceltype */
- 0, /* char p_canceled */
- &_errno, /* int *p_errnop */
- 0, /* int p_errno */
- &_h_errno, /* int *p_h_errnop */
- 0, /* int p_h_errno */
- NULL, /* char * p_in_sighandler */
- 0, /* char p_sigwaiting */
- PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
- {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */
- {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */
- 0, /* int p_userstack */
- NULL, /* void * p_guardaddr */
- 0, /* size_t p_guardsize */
- &__pthread_initial_thread, /* pthread_descr p_self */
- 0, /* Always index 0 */
- 0, /* int p_report_events */
- {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */
- __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */
- 0, /* char p_woken_by_cancel */
- 0, /* char p_condvar_avail */
- 0, /* char p_sem_avail */
- NULL, /* struct pthread_extricate_if *p_extricate */
- NULL, /* pthread_readlock_info *p_readlock_list; */
- NULL, /* pthread_readlock_info *p_readlock_free; */
- 0 /* int p_untracked_readlock_count; */
+ .p_nextlive = &__pthread_initial_thread,
+ .p_prevlive = &__pthread_initial_thread,
+ .p_nextwaiting = NULL,
+ .p_nextlock = NULL,
+ .p_tid = PTHREAD_THREADS_MAX,
+ .p_pid = 0,
+ .p_priority = 0,
+ .p_lock = &__pthread_handles[0].h_lock,
+ .p_signal = 0,
+ .p_signal_jmp = NULL,
+ .p_cancel_jmp = NULL,
+ .p_terminated = 0,
+ .p_detached = 0,
+ .p_exited = 0,
+ .p_retval = NULL,
+ .p_retcode = 0,
+ .p_joining = NULL,
+ .p_cleanup = NULL,
+ .p_cancelstate = 0,
+ .p_canceltype = 0,
+ .p_canceled = 0,
+ .p_errnop = &_errno,
+ .p_errno = 0,
+ .p_h_errnop = &_h_errno,
+ .p_h_errno = 0,
+ .p_in_sighandler = NULL,
+ .p_sigwaiting = 0,
+ .p_start_args = PTHREAD_START_ARGS_INITIALIZER(NULL),
+ .p_specific = {NULL},
+ .p_libc_specific = {NULL},
+ .p_userstack = 0,
+ .p_guardaddr = NULL,
+ .p_guardsize = 0,
+ .p_self = &__pthread_initial_thread,
+ .p_nr = 0,
+ .p_report_events = 0,
+ .p_eventbuf = {{{0, }}, 0, NULL},
+ .p_resume_count = __ATOMIC_INITIALIZER,
+ .p_woken_by_cancel = 0,
+ .p_condvar_avail = 0,
+ .p_sem_avail = 0,
+ .p_extricate = NULL,
+ .p_readlock_list = NULL,
+ .p_readlock_free = NULL,
+ .p_untracked_readlock_count = 0,
+ .p_inheritsched = 0,
+#if HP_TIMING_AVAIL
+ .p_cpuclock_offset = 0,
+#endif
+#ifdef USE_TLS
+ .p_stackaddr = NULL,
+#endif
+ .p_alloca_cutoff = 0
#ifdef __UCLIBC_HAS_XLOCALE__
,
- &__global_locale_data, /* __locale_t locale; */
-#endif /* __UCLIBC_HAS_XLOCALE__ */
+ .locale = &__global_locale_data
+#endif
};
/* Descriptor of the manager thread; none of this is used but the error
@@ -110,55 +118,63 @@ struct _pthread_descr_struct __pthread_initial_thread = {
and the address for identification. */
#define manager_thread (&__pthread_manager_thread)
struct _pthread_descr_struct __pthread_manager_thread = {
- NULL, /* pthread_descr p_nextlive */
- NULL, /* pthread_descr p_prevlive */
- NULL, /* pthread_descr p_nextwaiting */
- NULL, /* pthread_descr p_nextlock */
- 0, /* int p_tid */
- 0, /* int p_pid */
- 0, /* int p_priority */
- &__pthread_handles[1].h_lock, /* struct _pthread_fastlock * p_lock */
- 0, /* int p_signal */
- NULL, /* sigjmp_buf * p_signal_buf */
- NULL, /* sigjmp_buf * p_cancel_buf */
- 0, /* char p_terminated */
- 0, /* char p_detached */
- 0, /* char p_exited */
- NULL, /* void * p_retval */
- 0, /* int p_retval */
- NULL, /* pthread_descr p_joining */
- NULL, /* struct _pthread_cleanup_buffer * p_cleanup */
- 0, /* char p_cancelstate */
- 0, /* char p_canceltype */
- 0, /* char p_canceled */
- &__pthread_manager_thread.p_errno, /* int *p_errnop */
- 0, /* int p_errno */
- NULL, /* int *p_h_errnop */
- 0, /* int p_h_errno */
- NULL, /* char * p_in_sighandler */
- 0, /* char p_sigwaiting */
- PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
- {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */
- {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */
- 0, /* int p_userstack */
- NULL, /* void * p_guardaddr */
- 0, /* size_t p_guardsize */
- &__pthread_manager_thread, /* pthread_descr p_self */
- 1, /* Always index 1 */
- 0, /* int p_report_events */
- {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */
- __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */
- 0, /* char p_woken_by_cancel */
- 0, /* char p_condvar_avail */
- 0, /* char p_sem_avail */
- NULL, /* struct pthread_extricate_if *p_extricate */
- NULL, /* pthread_readlock_info *p_readlock_list; */
- NULL, /* pthread_readlock_info *p_readlock_free; */
- 0 /* int p_untracked_readlock_count; */
+ .p_nextlive = NULL,
+ .p_prevlive = NULL,
+ .p_nextwaiting = NULL,
+ .p_nextlock = NULL,
+ .p_tid = 0,
+ .p_pid = 0,
+ .p_priority = 0,
+ .p_lock = &__pthread_handles[1].h_lock,
+ .p_signal = 0,
+ .p_signal_jmp = NULL,
+ .p_cancel_jmp = NULL,
+ .p_terminated = 0,
+ .p_detached = 0,
+ .p_exited = 0,
+ .p_retval = NULL,
+ .p_retcode = 0,
+ .p_joining = NULL,
+ .p_cleanup = NULL,
+ .p_cancelstate = 0,
+ .p_canceltype = 0,
+ .p_canceled = 0,
+ .p_errnop = &__pthread_manager_thread.p_errno,
+ .p_errno = 0,
+ .p_h_errnop = NULL,
+ .p_h_errno = 0,
+ .p_in_sighandler = NULL,
+ .p_sigwaiting = 0,
+ .p_start_args = PTHREAD_START_ARGS_INITIALIZER(__pthread_manager),
+ .p_specific = {NULL},
+ .p_libc_specific = {NULL},
+ .p_userstack = 0,
+ .p_guardaddr = NULL,
+ .p_guardsize = 0,
+ .p_self = &__pthread_manager_thread,
+ .p_nr = 1,
+ .p_report_events = 0,
+ .p_eventbuf = {{{0, }}, 0, NULL},
+ .p_resume_count = __ATOMIC_INITIALIZER,
+ .p_woken_by_cancel = 0,
+ .p_condvar_avail = 0,
+ .p_sem_avail = 0,
+ .p_extricate = NULL,
+ .p_readlock_list = NULL,
+ .p_readlock_free = NULL,
+ .p_untracked_readlock_count = 0,
+ .p_inheritsched = 0,
+#if HP_TIMING_AVAIL
+ .p_cpuclock_offset = 0,
+#endif
+#ifdef USE_TLS
+ .p_stackaddr = NULL,
+#endif
+ .p_alloca_cutoff = 0
#ifdef __UCLIBC_HAS_XLOCALE__
,
- &__global_locale_data, /* __locale_t locale; */
-#endif /* __UCLIBC_HAS_XLOCALE__ */
+ &__global_locale_data
+#endif
};
/* Pointer to the main thread (the father of the thread manager thread) */
@@ -616,7 +632,7 @@ int pthread_setschedparam(pthread_t thread, int policy,
pthread_descr th;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, thread)) {
+ if (nonexisting_handle(handle, thread)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
@@ -639,7 +655,7 @@ int pthread_getschedparam(pthread_t thread, int *policy,
int pid, pol;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, thread)) {
+ if (nonexisting_handle(handle, thread)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
diff --git a/libpthread/linuxthreads/restart.h b/libpthread/linuxthreads/restart.h
index f72fb709f..687d92fae 100644
--- a/libpthread/linuxthreads/restart.h
+++ b/libpthread/linuxthreads/restart.h
@@ -14,13 +14,14 @@
#include <signal.h>
#include <sys/syscall.h>
+#define __ASSUME_REALTIME_SIGNALS defined(__NR_rt_sigaction)
/* Primitives for controlling thread execution */
static inline void restart(pthread_descr th)
{
/* See pthread.c */
-#ifdef __NR_rt_sigaction
+#if __ASSUME_REALTIME_SIGNALS
__pthread_restart_new(th);
#else
__pthread_restart(th);
@@ -30,7 +31,7 @@ static inline void restart(pthread_descr th)
static inline void suspend(pthread_descr self)
{
/* See pthread.c */
-#ifdef __NR_rt_sigaction
+#if __ASSUME_REALTIME_SIGNALS
__pthread_wait_for_restart_signal(self);
#else
__pthread_suspend(self);
@@ -41,7 +42,7 @@ static inline int timedsuspend(pthread_descr self,
const struct timespec *abstime)
{
/* See pthread.c */
-#ifdef __NR_rt_sigaction
+#if __ASSUME_REALTIME_SIGNALS
return __pthread_timedsuspend_new(self, abstime);
#else
return __pthread_timedsuspend(self, abstime);
diff --git a/libpthread/linuxthreads/rwlock.c b/libpthread/linuxthreads/rwlock.c
index 977fd88af..4a0fb1bba 100644
--- a/libpthread/linuxthreads/rwlock.c
+++ b/libpthread/linuxthreads/rwlock.c
@@ -1,20 +1,20 @@
/* Read-write lock implementation.
- Copyright (C) 1998 Free Software Foundation, Inc.
+ Copyright (C) 1998, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Xavier Leroy <Xavier.Leroy@inria.fr>
and Ulrich Drepper <drepper@cygnus.com>, 1998.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
+ You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
@@ -27,6 +27,33 @@
#include "spinlock.h"
#include "restart.h"
+/* Function called by pthread_cancel to remove the thread from
+ waiting inside pthread_rwlock_timedrdlock or pthread_rwlock_timedwrlock. */
+
+static int rwlock_rd_extricate_func(void *obj, pthread_descr th)
+{
+ pthread_rwlock_t *rwlock = obj;
+ int did_remove = 0;
+
+ __pthread_lock(&rwlock->__rw_lock, NULL);
+ did_remove = remove_from_queue(&rwlock->__rw_read_waiting, th);
+ __pthread_unlock(&rwlock->__rw_lock);
+
+ return did_remove;
+}
+
+static int rwlock_wr_extricate_func(void *obj, pthread_descr th)
+{
+ pthread_rwlock_t *rwlock = obj;
+ int did_remove = 0;
+
+ __pthread_lock(&rwlock->__rw_lock, NULL);
+ did_remove = remove_from_queue(&rwlock->__rw_write_waiting, th);
+ __pthread_unlock(&rwlock->__rw_lock);
+
+ return did_remove;
+}
+
/*
* Check whether the calling thread already owns one or more read locks on the
* specified lock. If so, return a pointer to the read lock info structure
@@ -38,7 +65,8 @@ rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock)
{
pthread_readlock_info *info;
- for (info = self->p_readlock_list; info != NULL; info = info->pr_next)
+ for (info = THREAD_GETMEM (self, p_readlock_list); info != NULL;
+ info = info->pr_next)
{
if (info->pr_lock == rwlock)
return info;
@@ -58,10 +86,10 @@ rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock)
static pthread_readlock_info *
rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock)
{
- pthread_readlock_info *info = self->p_readlock_free;
+ pthread_readlock_info *info = THREAD_GETMEM (self, p_readlock_free);
- if (info != NULL)
- self->p_readlock_free = info->pr_next;
+ if (info != NULL)
+ THREAD_SETMEM (self, p_readlock_free, info->pr_next);
else
info = malloc(sizeof *info);
@@ -70,8 +98,8 @@ rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock)
info->pr_lock_count = 1;
info->pr_lock = rwlock;
- info->pr_next = self->p_readlock_list;
- self->p_readlock_list = info;
+ info->pr_next = THREAD_GETMEM (self, p_readlock_list);
+ THREAD_SETMEM (self, p_readlock_list, info);
return info;
}
@@ -100,7 +128,7 @@ rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock)
return info;
}
}
-
+
return NULL;
}
@@ -137,7 +165,7 @@ rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already)
* This function helps support brain-damaged recursive read locking
* semantics required by Unix 98, while maintaining write priority.
* This basically determines whether this thread already holds a read lock
- * already. It returns 1 if so, otherwise it returns 0.
+ * already. It returns 1 if so, otherwise it returns 0.
*
* If the thread has any ``untracked read locks'' then it just assumes
* that this lock is among them, just to be safe, and returns 1.
@@ -161,11 +189,12 @@ rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
{
if (!self)
- self = thread_self();
+ *pself = self = thread_self();
existing = rwlock_is_in_list(self, rwlock);
- if (existing != NULL || self->p_untracked_readlock_count > 0)
+ if (existing != NULL
+ || THREAD_GETMEM (self, p_untracked_readlock_count) > 0)
have_lock_already = 1;
else
{
@@ -177,7 +206,6 @@ rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
*pout_of_mem = out_of_mem;
*pexisting = existing;
- *pself = self;
return have_lock_already;
}
@@ -207,6 +235,7 @@ pthread_rwlock_init (pthread_rwlock_t *rwlock,
}
+
int
pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
{
@@ -224,6 +253,7 @@ pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
return 0;
}
+
int
pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
{
@@ -232,13 +262,13 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
int out_of_mem, have_lock_already;
have_lock_already = rwlock_have_already(&self, rwlock,
- &existing, &out_of_mem);
+ &existing, &out_of_mem);
+
+ if (self == NULL)
+ self = thread_self ();
for (;;)
{
- if (self == NULL)
- self = thread_self ();
-
__pthread_lock (&rwlock->__rw_lock, self);
if (rwlock_can_rdlock(rwlock, have_lock_already))
@@ -255,14 +285,86 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
if (have_lock_already || out_of_mem)
{
if (existing != NULL)
- existing->pr_lock_count++;
+ ++existing->pr_lock_count;
else
- self->p_untracked_readlock_count++;
+ ++self->p_untracked_readlock_count;
}
-
+
return 0;
}
+
+int
+pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ pthread_descr self = NULL;
+ pthread_readlock_info *existing;
+ int out_of_mem, have_lock_already;
+ pthread_extricate_if extr;
+
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ return EINVAL;
+
+ have_lock_already = rwlock_have_already(&self, rwlock,
+ &existing, &out_of_mem);
+
+ if (self == NULL)
+ self = thread_self ();
+
+ /* Set up extrication interface */
+ extr.pu_object = rwlock;
+ extr.pu_extricate_func = rwlock_rd_extricate_func;
+
+ /* Register extrication interface */
+ __pthread_set_own_extricate_if (self, &extr);
+
+ for (;;)
+ {
+ __pthread_lock (&rwlock->__rw_lock, self);
+
+ if (rwlock_can_rdlock(rwlock, have_lock_already))
+ break;
+
+ enqueue (&rwlock->__rw_read_waiting, self);
+ __pthread_unlock (&rwlock->__rw_lock);
+ /* This is not a cancellation point */
+ if (timedsuspend (self, abstime) == 0)
+ {
+ int was_on_queue;
+
+ __pthread_lock (&rwlock->__rw_lock, self);
+ was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self);
+ __pthread_unlock (&rwlock->__rw_lock);
+
+ if (was_on_queue)
+ {
+ __pthread_set_own_extricate_if (self, 0);
+ return ETIMEDOUT;
+ }
+
+ /* Eat the outstanding restart() from the signaller */
+ suspend (self);
+ }
+ }
+
+ __pthread_set_own_extricate_if (self, 0);
+
+ ++rwlock->__rw_readers;
+ __pthread_unlock (&rwlock->__rw_lock);
+
+ if (have_lock_already || out_of_mem)
+ {
+ if (existing != NULL)
+ ++existing->pr_lock_count;
+ else
+ ++self->p_untracked_readlock_count;
+ }
+
+ return 0;
+}
+
+
int
pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
{
@@ -277,7 +379,7 @@ pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
__pthread_lock (&rwlock->__rw_lock, self);
/* 0 is passed to here instead of have_lock_already.
- This is to meet Single Unix Spec requirements:
+ This is to meet Single Unix Spec requirements:
if writers are waiting, pthread_rwlock_tryrdlock
does not acquire a read lock, even if the caller has
one or more read locks already. */
@@ -295,16 +397,17 @@ pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
if (have_lock_already || out_of_mem)
{
if (existing != NULL)
- existing->pr_lock_count++;
+ ++existing->pr_lock_count;
else
- self->p_untracked_readlock_count++;
+ ++self->p_untracked_readlock_count;
}
}
-
+
return retval;
}
+
int
pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
{
@@ -328,6 +431,64 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
}
+
+int
+pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+ const struct timespec *abstime)
+{
+ pthread_descr self;
+ pthread_extricate_if extr;
+
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ return EINVAL;
+
+ self = thread_self ();
+
+ /* Set up extrication interface */
+ extr.pu_object = rwlock;
+ extr.pu_extricate_func = rwlock_wr_extricate_func;
+
+ /* Register extrication interface */
+ __pthread_set_own_extricate_if (self, &extr);
+
+ while(1)
+ {
+ __pthread_lock (&rwlock->__rw_lock, self);
+
+ if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
+ {
+ rwlock->__rw_writer = self;
+ __pthread_set_own_extricate_if (self, 0);
+ __pthread_unlock (&rwlock->__rw_lock);
+ return 0;
+ }
+
+ /* Suspend ourselves, then try again */
+ enqueue (&rwlock->__rw_write_waiting, self);
+ __pthread_unlock (&rwlock->__rw_lock);
+ /* This is not a cancellation point */
+ if (timedsuspend (self, abstime) == 0)
+ {
+ int was_on_queue;
+
+ __pthread_lock (&rwlock->__rw_lock, self);
+ was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self);
+ __pthread_unlock (&rwlock->__rw_lock);
+
+ if (was_on_queue)
+ {
+ __pthread_set_own_extricate_if (self, 0);
+ return ETIMEDOUT;
+ }
+
+ /* Eat the outstanding restart() from the signaller */
+ suspend (self);
+ }
+ }
+}
+
+
+
int
pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
{
@@ -345,6 +506,7 @@ pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
}
+
int
pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
{
@@ -362,8 +524,9 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
}
rwlock->__rw_writer = NULL;
- if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
- || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL)
+ if ((rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
+ && !queue_is_empty(&rwlock->__rw_read_waiting))
+ || (th = dequeue(&rwlock->__rw_write_waiting)) == NULL)
{
/* Restart all waiting readers. */
torestart = rwlock->__rw_read_waiting;
@@ -410,14 +573,15 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
{
if (victim->pr_lock_count == 0)
{
- victim->pr_next = self->p_readlock_free;
- self->p_readlock_free = victim;
+ victim->pr_next = THREAD_GETMEM (self, p_readlock_free);
+ THREAD_SETMEM (self, p_readlock_free, victim);
}
}
else
{
- if (self->p_untracked_readlock_count > 0)
- self->p_untracked_readlock_count--;
+ int val = THREAD_GETMEM (self, p_untracked_readlock_count);
+ if (val > 0)
+ THREAD_SETMEM (self, p_untracked_readlock_count, val - 1);
}
}
}
@@ -427,11 +591,12 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+
int
pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
{
attr->__lockkind = 0;
- attr->__pshared = 0;
+ attr->__pshared = PTHREAD_PROCESS_PRIVATE;
return 0;
}
@@ -444,6 +609,7 @@ pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
}
+
int
pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
{
@@ -458,6 +624,10 @@ pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
return EINVAL;
+ /* For now it is not possible to shared a conditional variable. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return ENOSYS;
+
attr->__pshared = pshared;
return 0;
@@ -477,6 +647,7 @@ pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref)
{
if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
&& pref != PTHREAD_RWLOCK_PREFER_WRITER_NP
+ && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
&& pref != PTHREAD_RWLOCK_DEFAULT_NP)
return EINVAL;
diff --git a/libpthread/linuxthreads/semaphore.h b/libpthread/linuxthreads/semaphore.h
index 9c283c864..7b09ea931 100644
--- a/libpthread/linuxthreads/semaphore.h
+++ b/libpthread/linuxthreads/semaphore.h
@@ -64,13 +64,12 @@ extern int sem_close (sem_t *__sem) __THROW;
extern int sem_unlink (__const char *__name) __THROW;
/* Wait for SEM being posted. */
-extern int sem_wait (sem_t *__sem) __THROW;
+extern int sem_wait (sem_t *__sem);
#ifdef __USE_XOPEN2K
/* Similar to `sem_wait' but wait only until ABSTIME. */
extern int sem_timedwait (sem_t *__restrict __sem,
- __const struct timespec *__restrict __abstime)
- __THROW;
+ __const struct timespec *__restrict __abstime);
#endif
/* Test whether SEM is posted. */
diff --git a/libpthread/linuxthreads/signals.c b/libpthread/linuxthreads/signals.c
index df15b884e..90beaae9b 100644
--- a/libpthread/linuxthreads/signals.c
+++ b/libpthread/linuxthreads/signals.c
@@ -21,6 +21,7 @@
#include "internals.h"
#include "spinlock.h"
#include <ucontext.h>
+#include "debug.h"
#include <bits/sigcontextinfo.h>
/* mods for uClibc: __libc_sigaction is not in any standard headers */
@@ -64,7 +65,7 @@ int pthread_kill(pthread_t thread, int signo)
int pid;
__pthread_lock(&handle->h_lock, NULL);
- if (invalid_handle(handle, thread)) {
+ if (nonexisting_handle(handle, thread)) {
__pthread_unlock(&handle->h_lock);
return ESRCH;
}
@@ -76,16 +77,11 @@ int pthread_kill(pthread_t thread, int signo)
return 0;
}
-/* User-provided signal handlers */
-typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT));
-static union
-{
- arch_sighandler_t old;
- void (*rt) (int, struct siginfo *, struct ucontext *);
-} sighandler[NSIG];
+union sighandler __sighandler[NSIG] =
+ { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
/* The wrapper around user-provided signal handlers */
-static void pthread_sighandler(int signo, SIGCONTEXT ctx)
+static void __pthread_sighandler(int signo, SIGCONTEXT ctx)
{
pthread_descr self = thread_self();
char * in_sighandler;
@@ -101,13 +97,13 @@ static void pthread_sighandler(int signo, SIGCONTEXT ctx)
in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
if (in_sighandler == NULL)
THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
- sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx);
+ __sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx);
if (in_sighandler == NULL)
THREAD_SETMEM(self, p_in_sighandler, NULL);
}
/* The same, this time for real-time signals. */
-static void pthread_sighandler_rt(int signo, struct siginfo *si,
+static void __pthread_sighandler_rt(int signo, struct siginfo *si,
struct ucontext *uc)
{
pthread_descr self = thread_self();
@@ -124,7 +120,7 @@ static void pthread_sighandler_rt(int signo, struct siginfo *si,
in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
if (in_sighandler == NULL)
THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
- sighandler[signo].rt(signo, si, uc);
+ __sighandler[signo].rt(signo, si, uc);
if (in_sighandler == NULL)
THREAD_SETMEM(self, p_in_sighandler, NULL);
}
@@ -136,14 +132,18 @@ int __sigaction(int sig, const struct sigaction * act,
{
struct sigaction newact;
struct sigaction *newactp;
+ __sighandler_t old = SIG_DFL;
-#ifdef DEBUG_PT
-printf(__FUNCTION__": pthreads wrapper!\n");
-#endif
+ PDEBUG("pthreads wrapper!\n");
if (sig == __pthread_sig_restart ||
sig == __pthread_sig_cancel ||
(sig == __pthread_sig_debug && __pthread_sig_debug > 0))
- return EINVAL;
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ if (sig > 0 && sig < NSIG)
+ old = (__sighandler_t) __sighandler[sig].old;
if (act)
{
newact = *act;
@@ -151,27 +151,35 @@ printf(__FUNCTION__": pthreads wrapper!\n");
&& sig > 0 && sig < NSIG)
{
if (act->sa_flags & SA_SIGINFO)
- newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
+ newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
else
- newact.sa_handler = (__sighandler_t) pthread_sighandler;
+ newact.sa_handler = (__sighandler_t) __pthread_sighandler;
+ if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
+ __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
}
newactp = &newact;
}
else
newactp = NULL;
if (__libc_sigaction(sig, newactp, oact) == -1)
- return -1;
-#ifdef DEBUG_PT
-printf(__FUNCTION__": signahdler installed, __sigaction successful\n");
-#endif
+ {
+ if (act)
+ __sighandler[sig].old = (arch_sighandler_t) old;
+ return -1;
+ }
+ PDEBUG("signahdler installed, __sigaction successful\n");
if (sig > 0 && sig < NSIG)
{
- if (oact != NULL)
- oact->sa_handler = (__sighandler_t) sighandler[sig].old;
+ if (oact != NULL
+ /* We may have inherited SIG_IGN from the parent, so return the
+ kernel's idea of the signal handler the first time
+ through. */
+ && old != SIG_ERR)
+ oact->sa_handler = old;
if (act)
- /* For the assignment is does not matter whether it's a normal
+ /* For the assignment it does not matter whether it's a normal
or real-time signal. */
- sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
+ __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
}
return 0;
}
@@ -197,17 +205,17 @@ int sigwait(const sigset_t * set, int * sig)
signals in set is unspecified." */
sigfillset(&mask);
sigdelset(&mask, __pthread_sig_cancel);
- for (s = 1; s <= NSIG; s++) {
+ for (s = 1; s < NSIG; s++) {
if (sigismember(set, s) &&
s != __pthread_sig_restart &&
s != __pthread_sig_cancel &&
s != __pthread_sig_debug) {
sigdelset(&mask, s);
- if (sighandler[s].old == NULL ||
- sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
- sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
+ if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
+ __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
+ __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
sa.sa_handler = pthread_null_sighandler;
- sigemptyset(&sa.sa_mask);
+ sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(s, &sa, NULL);
}
diff --git a/libpthread/linuxthreads/specific.c b/libpthread/linuxthreads/specific.c
index d8b5bb0b3..e63a51721 100644
--- a/libpthread/linuxthreads/specific.c
+++ b/libpthread/linuxthreads/specific.c
@@ -42,40 +42,41 @@ static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_key_create(pthread_key_t * key, destr_function destr)
{
- int i;
-
- pthread_mutex_lock(&pthread_keys_mutex);
- for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
- if (! pthread_keys[i].in_use) {
- /* Mark key in use */
- pthread_keys[i].in_use = 1;
- pthread_keys[i].destr = destr;
- pthread_mutex_unlock(&pthread_keys_mutex);
- *key = i;
- return 0;
- }
+ int i;
+
+ pthread_mutex_lock(&pthread_keys_mutex);
+ for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+ if (! pthread_keys[i].in_use) {
+ /* Mark key in use */
+ pthread_keys[i].in_use = 1;
+ pthread_keys[i].destr = destr;
+ pthread_mutex_unlock(&pthread_keys_mutex);
+ *key = i;
+ return 0;
}
- pthread_mutex_unlock(&pthread_keys_mutex);
- return EAGAIN;
+ }
+ pthread_mutex_unlock(&pthread_keys_mutex);
+ return EAGAIN;
}
/* Delete a key */
int pthread_key_delete(pthread_key_t key)
{
- pthread_descr self = thread_self();
+ pthread_descr self = thread_self();
- pthread_mutex_lock(&pthread_keys_mutex);
- if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
- pthread_mutex_unlock(&pthread_keys_mutex);
- return EINVAL;
- }
- pthread_keys[key].in_use = 0;
- pthread_keys[key].destr = NULL;
+ pthread_mutex_lock(&pthread_keys_mutex);
+ if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
+ pthread_mutex_unlock(&pthread_keys_mutex);
+ return EINVAL;
+ }
+ pthread_keys[key].in_use = 0;
+ pthread_keys[key].destr = NULL;
+
+ /* Set the value of the key to NULL in all running threads, so
+ that if the key is reallocated later by pthread_key_create, its
+ associated values will be NULL in all threads.
+ Do nothing if no threads have been created yet. */
- /* Set the value of the key to NULL in all running threads, so
- that if the key is reallocated later by pthread_key_create, its
- associated values will be NULL in all threads.
- Do nothing if no threads have been created yet. */
if (__pthread_manager_request != -1)
{
pthread_descr th;
@@ -87,98 +88,101 @@ int pthread_key_delete(pthread_key_t key)
do {
/* If the thread already is terminated don't modify the memory. */
if (!th->p_terminated && th->p_specific[idx1st] != NULL)
- th->p_specific[idx1st][idx2nd] = NULL;
- th = th->p_nextlive;
- } while (th != self);
- }
+ th->p_specific[idx1st][idx2nd] = NULL;
+ th = th->p_nextlive;
+ } while (th != self);
+ }
- pthread_mutex_unlock(&pthread_keys_mutex);
- return 0;
+ pthread_mutex_unlock(&pthread_keys_mutex);
+ return 0;
}
/* Set the value of a key */
int pthread_setspecific(pthread_key_t key, const void * pointer)
{
- pthread_descr self = thread_self();
- unsigned int idx1st, idx2nd;
-
- if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
- return EINVAL;
- idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
- idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
- if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
- void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
- if (newp == NULL)
- return ENOMEM;
- THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
- }
- THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
- return 0;
+ pthread_descr self = thread_self();
+ unsigned int idx1st, idx2nd;
+
+ if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
+ return EINVAL;
+ idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+ idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+ if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
+ void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
+ if (newp == NULL)
+ return ENOMEM;
+ THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
+ }
+ THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
+ return 0;
}
+
/* Get the value of a key */
void * pthread_getspecific(pthread_key_t key)
{
- pthread_descr self = thread_self();
- unsigned int idx1st, idx2nd;
-
- if (key >= PTHREAD_KEYS_MAX)
- return NULL;
- idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
- idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
- if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
- || !pthread_keys[key].in_use)
- return NULL;
- return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
+ pthread_descr self = thread_self();
+ unsigned int idx1st, idx2nd;
+
+ if (key >= PTHREAD_KEYS_MAX)
+ return NULL;
+ idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+ idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+ if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
+ || !pthread_keys[key].in_use)
+ return NULL;
+ return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
}
+
/* Call the destruction routines on all keys */
void __pthread_destroy_specifics()
{
- pthread_descr self = thread_self();
- int i, j, round, found_nonzero;
- destr_function destr;
- void * data;
-
- for (round = 0, found_nonzero = 1;
- found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
- round++) {
- found_nonzero = 0;
- for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
- if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
- for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
- destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
- data = THREAD_GETMEM_NC(self, p_specific[i])[j];
- if (destr != NULL && data != NULL) {
- THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
- destr(data);
- found_nonzero = 1;
- }
- }
- }
- __pthread_lock(THREAD_GETMEM(self, p_lock), self);
- for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
- if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
- free(THREAD_GETMEM_NC(self, p_specific[i]));
- THREAD_SETMEM_NC(self, p_specific[i], NULL);
- }
+ pthread_descr self = thread_self();
+ int i, j, round, found_nonzero;
+ destr_function destr;
+ void * data;
+
+ for (round = 0, found_nonzero = 1;
+ found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
+ round++) {
+ found_nonzero = 0;
+ for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
+ if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
+ for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
+ destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
+ data = THREAD_GETMEM_NC(self, p_specific[i])[j];
+ if (destr != NULL && data != NULL) {
+ THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
+ destr(data);
+ found_nonzero = 1;
+ }
+ }
+ }
+ __pthread_lock(THREAD_GETMEM(self, p_lock), self);
+ for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
+ if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
+ free(THREAD_GETMEM_NC(self, p_specific[i]));
+ THREAD_SETMEM_NC(self, p_specific[i], NULL);
}
- __pthread_unlock(THREAD_GETMEM(self, p_lock));
+ }
+ __pthread_unlock(THREAD_GETMEM(self, p_lock));
}
+#if !(USE_TLS && HAVE___THREAD)
/* Thread-specific data for libc. */
-#if !(USE_TLS && HAVE___THREAD)
+
static int
libc_internal_tsd_set(enum __libc_tsd_key_t key, const void * pointer)
{
- pthread_descr self = thread_self();
+ pthread_descr self = thread_self();
- THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
- return 0;
+ THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
+ return 0;
}
int (*__libc_internal_tsd_set)(enum __libc_tsd_key_t key, const void * pointer)
= libc_internal_tsd_set;
@@ -186,9 +190,9 @@ int (*__libc_internal_tsd_set)(enum __libc_tsd_key_t key, const void * pointer)
static void *
libc_internal_tsd_get(enum __libc_tsd_key_t key)
{
- pthread_descr self = thread_self();
+ pthread_descr self = thread_self();
- return THREAD_GETMEM_NC(self, p_libc_specific[key]);
+ return THREAD_GETMEM_NC(self, p_libc_specific[key]);
}
void * (*__libc_internal_tsd_get)(enum __libc_tsd_key_t key)
= libc_internal_tsd_get;
@@ -196,8 +200,8 @@ void * (*__libc_internal_tsd_get)(enum __libc_tsd_key_t key)
static void ** __attribute__ ((__const__))
libc_internal_tsd_address (enum __libc_tsd_key_t key)
{
- pthread_descr self = thread_self();
- return &self->p_libc_specific[key];
+ pthread_descr self = thread_self();
+ return &self->p_libc_specific[key];
}
void **(*const __libc_internal_tsd_address) (enum __libc_tsd_key_t key)
__THROW __attribute__ ((__const__)) = libc_internal_tsd_address;
diff --git a/libpthread/linuxthreads/spinlock.c b/libpthread/linuxthreads/spinlock.c
index c0e7a368f..cdf45f195 100644
--- a/libpthread/linuxthreads/spinlock.c
+++ b/libpthread/linuxthreads/spinlock.c
@@ -108,7 +108,7 @@ void internal_function __pthread_lock(struct _pthread_fastlock * lock,
#ifdef BUSY_WAIT_NOP
BUSY_WAIT_NOP;
#endif
- __asm __volatile ("" : "=m" (lock->__status) : "0" (lock->__status));
+ __asm __volatile ("" : "=m" (lock->__status) : "m" (lock->__status));
}
lock->__spinlock += (spin_count - lock->__spinlock) / 8;
diff --git a/libpthread/linuxthreads/spinlock.h b/libpthread/linuxthreads/spinlock.h
index 0ec40c57c..ff96fc336 100644
--- a/libpthread/linuxthreads/spinlock.h
+++ b/libpthread/linuxthreads/spinlock.h
@@ -196,7 +196,7 @@ static inline long atomic_decrement(struct pthread_atomic *pa)
}
-static inline void
+static inline __attribute__((always_inline)) void
__pthread_set_own_extricate_if (pthread_descr self, pthread_extricate_if *peif)
{
/* Only store a non-null peif if the thread has cancellation enabled.
diff --git a/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h b/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h
index fa0374bc5..853ac6f04 100644
--- a/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h
@@ -1,6 +1,7 @@
/* Machine-dependent pthreads configuration and inline functions.
Alpha version.
- Copyright (C) 1996, 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Richard Henderson <rth@tamu.edu>.
@@ -23,7 +24,7 @@
#define _PT_MACHINE_H 1
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
#ifdef __linux__
diff --git a/libpthread/linuxthreads/sysdeps/cris/pt-machine.h b/libpthread/linuxthreads/sysdeps/cris/pt-machine.h
index eaead3058..431da7101 100644
--- a/libpthread/linuxthreads/sysdeps/cris/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/cris/pt-machine.h
@@ -1,6 +1,6 @@
/* Machine-dependent pthreads configuration and inline functions.
CRIS version.
- Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -22,7 +22,7 @@
#define _PT_MACHINE_H 1
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
extern long int testandset (int *spinlock);
diff --git a/libpthread/linuxthreads/sysdeps/i386/pt-machine.h b/libpthread/linuxthreads/sysdeps/i386/pt-machine.h
index e8a9b4e67..af1818d7b 100644
--- a/libpthread/linuxthreads/sysdeps/i386/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/i386/pt-machine.h
@@ -1,6 +1,6 @@
/* Machine-dependent pthreads configuration and inline functions.
i386 version.
- Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Richard Henderson <rth@tamu.edu>.
@@ -24,7 +24,7 @@
#ifndef __ASSEMBLER__
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
extern long int testandset (int *spinlock);
@@ -36,7 +36,9 @@ extern int __compare_and_swap (long int *p, long int oldval, long int newval);
/* See if we can optimize for newer cpus... */
-#if defined __GNUC__ && __GNUC__ >= 2 && defined __i486__ || defined __pentium__ || defined __pentiumpro__
+#if defined __GNUC__ && __GNUC__ >= 2 && \
+ (defined __i486__ || defined __pentium__ || defined __pentiumpro__ || defined __pentium4__ || \
+ defined __athlon__ || defined __k8__)
/* Spinlock implementation; required. */
PT_EI long int
diff --git a/libpthread/linuxthreads/sysdeps/i386/tls.h b/libpthread/linuxthreads/sysdeps/i386/tls.h
index 5d1551e57..e4f007ee3 100644
--- a/libpthread/linuxthreads/sysdeps/i386/tls.h
+++ b/libpthread/linuxthreads/sysdeps/i386/tls.h
@@ -1,5 +1,5 @@
/* Definition for thread-local data handling. linuxthreads/i386 version.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -23,7 +23,9 @@
# include <pt-machine.h>
#ifndef __ASSEMBLER__
+# include <stdbool.h>
# include <stddef.h>
+# include <stdint.h>
/* Type for the dtv. */
typedef union dtv
diff --git a/libpthread/linuxthreads/sysdeps/i386/useldt.h b/libpthread/linuxthreads/sysdeps/i386/useldt.h
index 16aee9989..a5e8e6f18 100644
--- a/libpthread/linuxthreads/sysdeps/i386/useldt.h
+++ b/libpthread/linuxthreads/sysdeps/i386/useldt.h
@@ -24,6 +24,7 @@
#include <stdlib.h> /* For abort(). */
+
/* We don't want to include the kernel header. So duplicate the
information. */
@@ -76,7 +77,7 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
#ifdef __PIC__
# define USETLS_EBX_ARG "r"
-# define USETLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+# define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
#else
# define USETLS_EBX_ARG "b"
# define USETLS_LOAD_EBX
@@ -108,8 +109,10 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
"movl %2, %%eax\n\t" \
"int $0x80\n\t" \
USETLS_LOAD_EBX \
- : "&a" (__result) \
- : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \
+ : "=&a" (__result) \
+ : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
+ "m" (ldt_entry) \
+ : "memory"); \
if (__result == 0) \
asm ("movw %w0, %%gs" :: "q" (__gs)); \
else \
@@ -126,8 +129,10 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
"movl %2, %%eax\n\t" \
"int $0x80\n\t" \
USETLS_LOAD_EBX \
- : "&a" (__result) \
- : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \
+ : "=&a" (__result) \
+ : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
+ "m" (ldt_entry) \
+ : "memory"); \
if (__result == 0) \
{ \
__gs = (ldt_entry.entry_number << 3) + 3; \
diff --git a/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h b/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h
index 0504ae179..4670ae3c4 100644
--- a/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h
@@ -1,6 +1,6 @@
/* Machine-dependent pthreads configuration and inline functions.
m68k version.
- Copyright (C) 1996, 1998, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Richard Henderson <rth@tamu.edu>.
@@ -23,7 +23,7 @@
#define _PT_MACHINE_H 1
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
extern long int testandset (int *spinlock);
diff --git a/libpthread/linuxthreads/sysdeps/mips/pt-machine.h b/libpthread/linuxthreads/sysdeps/mips/pt-machine.h
index 93d862774..f7efc881d 100644
--- a/libpthread/linuxthreads/sysdeps/mips/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/mips/pt-machine.h
@@ -1,6 +1,7 @@
/* Machine-dependent pthreads configuration and inline functions.
- Copyright (C) 1996, 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ralf Baechle <ralf@gnu.org>.
Based on the Alpha version by Richard Henderson <rth@tamu.edu>.
@@ -55,7 +56,7 @@ _test_and_set (int *p, int v) __THROW
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
extern long int testandset (int *spinlock);
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
index 4e884a030..e2b267d32 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
@@ -1,5 +1,6 @@
/* libc-internal interface for mutex locks. LinuxThreads version.
- Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+ Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
index 35a6a19a6..efd0c83be 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
@@ -1,5 +1,5 @@
/* libc-internal interface for thread-specific data. LinuxThreads version.
- Copyright (C) 1997,98,99,2001,02 Free Software Foundation, Inc.
+ Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
index db4c3790c..faec63b06 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
@@ -25,8 +25,9 @@
/* Fast locks (not abstract because mutexes and conditions aren't abstract). */
struct _pthread_fastlock
{
- long int __status; /* "Free" or "taken" or head of waiting list */
- int __spinlock; /* For compare-and-swap emulation */
+ long int __status; /* "Free" or "taken" or head of waiting list */
+ int __spinlock; /* Used by compare_and_swap emulation. Also,
+ adaptive SMP lock stores spin count here. */
};
#ifndef _PTHREAD_DESCR_DEFINED
@@ -37,7 +38,7 @@ typedef struct _pthread_descr_struct *_pthread_descr;
/* Attributes for threads. */
-typedef struct
+typedef struct __pthread_attr_s
{
int __detachstate;
int __schedpolicy;
@@ -93,7 +94,7 @@ typedef struct
typedef int pthread_once_t;
-#ifdef __USE_UNIX98
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
/* Read-write locks. */
typedef struct _pthread_rwlock_t
{
@@ -115,6 +116,25 @@ typedef struct
} pthread_rwlockattr_t;
#endif
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+/* POSIX barrier. */
+typedef struct {
+ struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */
+ int __ba_required; /* Threads needed for completion */
+ int __ba_present; /* Threads waiting */
+ _pthread_descr __ba_waiting; /* Queue of waiting threads */
+} pthread_barrier_t;
+
+/* barrier attribute */
+typedef struct {
+ int __pshared;
+} pthread_barrierattr_t;
+
+#endif
+
/* Thread identifiers */
typedef unsigned long int pthread_t;
diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread.h b/libpthread/linuxthreads/sysdeps/pthread/pthread.h
index 8c01172e5..6613cab88 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/pthread.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/pthread.h
@@ -46,7 +46,7 @@ __BEGIN_DECLS
#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
-#ifdef __USE_UNIX98
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
# define PTHREAD_RWLOCK_INITIALIZER \
{ __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \
PTHREAD_RWLOCK_DEFAULT_NP, PTHREAD_PROCESS_PRIVATE }
@@ -110,7 +110,7 @@ enum
#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED
};
-#ifdef __USE_UNIX98
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
enum
{
PTHREAD_RWLOCK_PREFER_READER_NP,
@@ -163,7 +163,7 @@ enum
/* Create a thread with given attributes ATTR (or default attributes
if ATTR is NULL), and call function START_ROUTINE with given
arguments ARG. */
-extern int pthread_create (pthread_t *__restrict __thread_id,
+extern int pthread_create (pthread_t *__restrict __threadp,
__const pthread_attr_t *__restrict __attr,
void *(*__start_routine) (void *),
void *__restrict __arg) __THROW;
@@ -175,13 +175,12 @@ extern pthread_t pthread_self (void) __THROW;
extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW;
/* Terminate calling thread. */
-extern void pthread_exit (void *__retval)
- __THROW __attribute__ ((__noreturn__));
+extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));
/* Make calling thread wait for termination of the thread TH. The
exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
is not NULL. */
-extern int pthread_join (pthread_t __th, void **__thread_return) __THROW;
+extern int pthread_join (pthread_t __th, void **__thread_return);
/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
The resources of TH will therefore be freed immediately when it
@@ -268,9 +267,6 @@ extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
__attr, void **__restrict __stackaddr)
__THROW;
-#if 0
-/* Not yet implemented in uClibc! */
-
#ifdef __USE_XOPEN2K
/* The following two interfaces are intended to replace the last two. They
require setting the address as well as the size since only setting the
@@ -283,7 +279,6 @@ extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
void **__restrict __stackaddr,
size_t *__restrict __stacksize) __THROW;
#endif
-#endif
/* Add information about the minimum stack size needed for the thread
to be started. This size must never be less than PTHREAD_STACK_SIZE
@@ -300,7 +295,9 @@ extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict
/* Not yet implemented in uClibc! */
#ifdef __USE_GNU
-/* Get thread attributes corresponding to the already running thread TH. */
+/* Initialize thread attribute *ATTR with attributes corresponding to the
+ already running thread TH. It shall be called on unitialized ATTR
+ and destroyed with pthread_attr_destroy when no longer needed. */
extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW;
#endif
#endif
@@ -418,7 +415,7 @@ extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW;
/* Wait for condition variable COND to be signaled or broadcast.
MUTEX is assumed to be locked before. */
extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
- pthread_mutex_t *__restrict __mutex) __THROW;
+ pthread_mutex_t *__restrict __mutex);
/* Wait for condition variable COND to be signaled or broadcast until
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
@@ -427,7 +424,7 @@ extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
__const struct timespec *__restrict
- __abstime) __THROW;
+ __abstime);
/* Functions for handling condition variable attributes. */
@@ -447,7 +444,7 @@ extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,
int __pshared) __THROW;
-#ifdef __USE_UNIX98
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
/* Functions for handling read-write locks. */
/* Initialize read-write lock RWLOCK using attributes ATTR, or use
@@ -465,27 +462,25 @@ extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW;
/* Try to acquire read lock for RWLOCK. */
extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW;
+# ifdef __USE_XOPEN2K
+/* Try to acquire read lock for RWLOCK or return after specfied time. */
+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
+ __const struct timespec *__restrict
+ __abstime) __THROW;
+# endif
+
/* Acquire write lock for RWLOCK. */
extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW;
/* Try to acquire write lock for RWLOCK. */
extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW;
-#if 0
-/* Not yet implemented in uClibc! */
-
-#ifdef __USE_XOPEN2K
-/* Try to acquire read lock for RWLOCK or return after specfied time. */
-extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
- __const struct timespec *__restrict
- __abstime) __THROW;
+# ifdef __USE_XOPEN2K
/* Try to acquire write lock for RWLOCK or return after specfied time. */
extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
__const struct timespec *__restrict
__abstime) __THROW;
-#endif
-#endif
-
+# endif
/* Unlock RWLOCK. */
extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW;
@@ -593,28 +588,31 @@ extern void *pthread_getspecific (pthread_key_t __key) __THROW;
/* Guarantee that the initialization function INIT_ROUTINE will be called
only once, even if pthread_once is executed several times with the
same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or
- extern variable initialized to PTHREAD_ONCE_INIT. */
+ extern variable initialized to PTHREAD_ONCE_INIT.
+
+ The initialization functions might throw exception which is why
+ this function is not marked with __THROW. */
extern int pthread_once (pthread_once_t *__once_control,
- void (*__init_routine) (void)) __THROW;
+ void (*__init_routine) (void));
/* Functions for handling cancellation. */
/* Set cancelability state of current thread to STATE, returning old
state in *OLDSTATE if OLDSTATE is not NULL. */
-extern int pthread_setcancelstate (int __state, int *__oldstate) __THROW;
+extern int pthread_setcancelstate (int __state, int *__oldstate);
/* Set cancellation state of current thread to TYPE, returning the old
type in *OLDTYPE if OLDTYPE is not NULL. */
-extern int pthread_setcanceltype (int __type, int *__oldtype) __THROW;
+extern int pthread_setcanceltype (int __type, int *__oldtype);
/* Cancel THREAD immediately or at the next possibility. */
-extern int pthread_cancel (pthread_t __thread_id) __THROW;
+extern int pthread_cancel (pthread_t __cancelthread);
/* Test for pending cancellation for the current thread and terminate
the thread as per pthread_exit(PTHREAD_CANCELED) if it has been
cancelled. */
-extern void pthread_testcancel (void) __THROW;
+extern void pthread_testcancel (void);
/* Install a cleanup handler: ROUTINE will be called with arguments ARG
diff --git a/libpthread/linuxthreads/sysdeps/sh/pt-machine.h b/libpthread/linuxthreads/sysdeps/sh/pt-machine.h
index cc3a4f2ce..c735ab22a 100644
--- a/libpthread/linuxthreads/sysdeps/sh/pt-machine.h
+++ b/libpthread/linuxthreads/sysdeps/sh/pt-machine.h
@@ -1,6 +1,6 @@
/* Machine-dependent pthreads configuration and inline functions.
SuperH version.
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Niibe Yutaka <gniibe@m17n.org>.
@@ -24,7 +24,7 @@
#ifndef __ASSEMBLER__
#ifndef PT_EI
-# define PT_EI extern inline
+# define PT_EI extern inline __attribute__ ((always_inline))
#endif
extern long int testandset (int *spinlock);
diff --git a/libpthread/linuxthreads/sysdeps/sh/tls.h b/libpthread/linuxthreads/sysdeps/sh/tls.h
index ee3db5ae8..75326d8e1 100644
--- a/libpthread/linuxthreads/sysdeps/sh/tls.h
+++ b/libpthread/linuxthreads/sysdeps/sh/tls.h
@@ -1,5 +1,5 @@
/* Definition for thread-local data handling. linuxthreads/SH version.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -20,10 +20,12 @@
#ifndef _TLS_H
#define _TLS_H
-#ifndef __ASSEMBLER__
-#include <stddef.h>
+# include <pt-machine.h>
-#include <pt-machine.h>
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
/* Type for the dtv. */
typedef union dtv
diff --git a/libpthread/linuxthreads/wrapsyscall.c b/libpthread/linuxthreads/wrapsyscall.c
deleted file mode 100644
index 6b8a00bb5..000000000
--- a/libpthread/linuxthreads/wrapsyscall.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/* Wrapper arpund system calls to provide cancelation points.
- Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-#define __FORCE_GLIBC
-#include <features.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-
-
-#ifndef __PIC__
-/* We need a hook to force this file to be linked in when static
- libpthread is used. */
-const int __pthread_provide_wrappers = 0;
-#endif
-
-
-#define CANCELABLE_SYSCALL(res_type, name, param_list, params) \
-res_type __libc_##name param_list; \
-res_type \
-__attribute__ ((weak)) \
-name param_list \
-{ \
- res_type result; \
- int oldtype; \
- pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \
- result = __libc_##name params; \
- pthread_setcanceltype (oldtype, NULL); \
- return result; \
-}
-
-#define CANCELABLE_SYSCALL_VA(res_type, name, param_list, params, last_arg) \
-res_type __libc_##name param_list; \
-res_type \
-__attribute__ ((weak)) \
-name param_list \
-{ \
- res_type result; \
- int oldtype; \
- va_list ap; \
- pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \
- va_start (ap, last_arg); \
- result = __libc_##name params; \
- va_end (ap); \
- pthread_setcanceltype (oldtype, NULL); \
- return result; \
-}
-
-
-/* close(2). */
-CANCELABLE_SYSCALL (int, close, (int fd), (fd))
-
-
-/* fcntl(2). */
-CANCELABLE_SYSCALL_VA (int, fcntl, (int fd, int cmd, ...),
- (fd, cmd, va_arg (ap, long int)), cmd)
-
-
-/* fsync(2). */
-CANCELABLE_SYSCALL (int, fsync, (int fd), (fd))
-
-
-/* lseek(2). */
-CANCELABLE_SYSCALL (off_t, lseek, (int fd, off_t offset, int whence),
- (fd, offset, whence))
-
-#ifdef __UCLIBC_HAS_LFS__
-/* lseek64(2). */
-CANCELABLE_SYSCALL (off64_t, lseek64, (int fd, off64_t offset, int whence),
- (fd, offset, whence))
-#endif
-
-/* msync(2). */
-CANCELABLE_SYSCALL (int, msync, (__ptr_t addr, size_t length, int flags),
- (addr, length, flags))
-
-
-/* nanosleep(2). */
-CANCELABLE_SYSCALL (int, nanosleep, (const struct timespec *requested_time,
- struct timespec *remaining),
- (requested_time, remaining))
-
-
-/* open(2). */
-CANCELABLE_SYSCALL_VA (int, open, (const char *pathname, int flags, ...),
- (pathname, flags, va_arg (ap, mode_t)), flags)
-
-
-#ifdef __UCLIBC_HAS_LFS__
-/* open64(3). */
-CANCELABLE_SYSCALL_VA (int, open64, (const char *pathname, int flags, ...),
- (pathname, flags, va_arg (ap, mode_t)), flags)
-#endif
-
-/* pause(2). */
-CANCELABLE_SYSCALL (int, pause, (void), ())
-
-
-/* Enable this if enabling these in syscalls.c */
-/* pread(3). */
-CANCELABLE_SYSCALL (ssize_t, pread, (int fd, void *buf, size_t count,
- off_t offset),
- (fd, buf, count, offset))
-
-
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_pread64
-/* pread64(3). */
-CANCELABLE_SYSCALL (ssize_t, pread64, (int fd, void *buf, size_t count,
- off64_t offset),
- (fd, buf, count, offset))
-#endif
-
-/* pwrite(3). */
-CANCELABLE_SYSCALL (ssize_t, pwrite, (int fd, const void *buf, size_t n,
- off_t offset),
- (fd, buf, n, offset))
-
-
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_pwrited64
-/* pwrite64(3). */
-CANCELABLE_SYSCALL (ssize_t, pwrite64, (int fd, const void *buf, size_t n,
- off64_t offset),
- (fd, buf, n, offset))
-#endif
-
-/* read(2). */
-CANCELABLE_SYSCALL (ssize_t, read, (int fd, void *buf, size_t count),
- (fd, buf, count))
-
-
-/* system(3). */
-CANCELABLE_SYSCALL (int, system, (const char *line), (line))
-
-
-/* tcdrain(2). */
-CANCELABLE_SYSCALL (int, tcdrain, (int fd), (fd))
-
-
-/* wait(2). */
-CANCELABLE_SYSCALL (__pid_t, wait, (__WAIT_STATUS_DEFN stat_loc), (stat_loc))
-
-
-/* waitpid(2). */
-CANCELABLE_SYSCALL (__pid_t, waitpid, (__pid_t pid, int *stat_loc,
- int options),
- (pid, stat_loc, options))
-
-
-/* write(2). */
-CANCELABLE_SYSCALL (ssize_t, write, (int fd, const void *buf, size_t n),
- (fd, buf, n))
-
-
-/* The following system calls are thread cancellation points specified
- in XNS. */
-
-/* accept(2). */
-CANCELABLE_SYSCALL (int, accept, (int fd, __SOCKADDR_ARG addr,
- socklen_t *addr_len),
- (fd, addr, addr_len))
-
-/* connect(2). */
-CANCELABLE_SYSCALL (int, connect, (int fd, __CONST_SOCKADDR_ARG addr,
- socklen_t len),
- (fd, addr, len))
-
-/* recv(2). */
-CANCELABLE_SYSCALL (ssize_t, recv, (int fd, __ptr_t buf, size_t n, int flags),
- (fd, buf, n, flags))
-
-/* recvfrom(2). */
-CANCELABLE_SYSCALL (ssize_t, recvfrom, (int fd, __ptr_t buf, size_t n, int flags,
- __SOCKADDR_ARG addr, socklen_t *addr_len),
- (fd, buf, n, flags, addr, addr_len))
-
-/* recvmsg(2). */
-CANCELABLE_SYSCALL (ssize_t, recvmsg, (int fd, struct msghdr *message, int flags),
- (fd, message, flags))
-
-/* send(2). */
-CANCELABLE_SYSCALL (ssize_t, send, (int fd, const __ptr_t buf, size_t n,
- int flags),
- (fd, buf, n, flags))
-
-/* sendmsg(2). */
-CANCELABLE_SYSCALL (ssize_t, sendmsg, (int fd, const struct msghdr *message,
- int flags),
- (fd, message, flags))
-
-/* sendto(2). */
-CANCELABLE_SYSCALL (ssize_t, sendto, (int fd, const __ptr_t buf, size_t n,
- int flags, __CONST_SOCKADDR_ARG addr,
- socklen_t addr_len),
- (fd, buf, n, flags, addr, addr_len))
diff --git a/test/mmap/mmap.c b/test/mmap/mmap.c
index 3649461ac..8b29737a0 100644
--- a/test/mmap/mmap.c
+++ b/test/mmap/mmap.c
@@ -5,23 +5,69 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
+#define SIZEOF_ARRAY(type) (sizeof(type)/sizeof(*type))
+
+struct mmap_test {
+ void *ret;
+ int err;
+ struct {
+ void *start;
+ size_t length;
+ int prot;
+ int flags;
+ int fd;
+ off_t offset;
+ } args;
+};
+
+struct mmap_test tests[] = {
+ [0] {
+ .err = 0,
+ .args.start = NULL,
+ .args.length = 4096,
+ .args.prot = PROT_READ|PROT_WRITE,
+ .args.flags = MAP_PRIVATE|MAP_ANONYMOUS,
+ .args.fd = 0,
+ .args.offset = 0
+ },
+};
+
+#define err(fmt, args...) \
+ do { \
+ fprintf(stderr, fmt "\n" , ## args); \
+ exit(1); \
+ } while (0)
+#define errp(fmt, args...) err(fmt ": %s" , ## args , strerror(errno))
int main(int argc, char **argv)
{
- void *ptr;
+ int i;
+ struct mmap_test *t;
+ for (i=0; i<SIZEOF_ARRAY(tests); ++i) {
+ t = tests + i;
- ptr = mmap(NULL, 4096, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ errno = 0;
+ t->ret = mmap(t->args.start, t->args.length, t->args.prot,
+ t->args.flags, t->args.fd, t->args.offset);
- if(ptr==MAP_FAILED){
- perror("mmap");
- exit(1);
+ if (t->err) {
+ if (t->ret != MAP_FAILED)
+ err("mmap test %i should have failed, but gave us %p", i, t->ret);
+ else if (t->err != errno)
+ errp("mmap test %i failed, but gave us wrong errno (got %i instead of %i)", i, errno, t->err);
+ } else {
+ if (t->ret == MAP_FAILED)
+ errp("mmap test %i failed", i);
+ else if (munmap(t->ret, t->args.length) != 0)
+ errp("munmap test %i failed", i);
+ }
}
- printf("mmap returned %p\n",ptr);
+
exit(0);
}
-
diff --git a/test/mmap/mmap64.c b/test/mmap/mmap64.c
index 066d03c24..7886ccd29 100644
--- a/test/mmap/mmap64.c
+++ b/test/mmap/mmap64.c
@@ -10,6 +10,7 @@
int main(int argc, char **argv)
{
+#ifdef __NR_mmap64
void *ptr;
ptr = mmap64(NULL, 4096, PROT_READ|PROT_WRITE,
@@ -21,4 +22,7 @@ int main(int argc, char **argv)
}
printf("mmap returned %p\n", ptr);
exit(0);
+#else
+ exit(0);
+#endif
}