summaryrefslogtreecommitdiff
path: root/libpthread/linuxthreads/sysdeps/pthread
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/linuxthreads/sysdeps/pthread')
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h27
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h65
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h14
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h12
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h65
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/errno-loc.c44
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/flockfile.c32
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c32
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/funlockfile.c32
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c116
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c44
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/list.h113
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h66
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/not-cancel.h4
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/posix-timer.h203
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c123
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h14
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/pthread.h46
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c32
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/res-state.c46
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/semaphore.h1
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/sigaction.c56
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h1
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_create.c169
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_delete.c69
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c44
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c76
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_routines.c572
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/timer_settime.c136
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/tls.h80
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/tst-timer.c113
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h47
32 files changed, 2311 insertions, 183 deletions
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h b/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h
new file mode 100644
index 000000000..b9e4acf30
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h
@@ -0,0 +1,27 @@
+/* Generic definitions for spinlock initializers.
+ Copyright (C) 2000, 2001 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 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* Initial value of a spinlock. Most platforms should use zero,
+ unless they only implement a "test and clear" operation instead of
+ the usual "test and set". */
+#define __LT_SPINLOCK_INIT 0
+
+/* Macros for lock initializers, using the above definition. */
+#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT }
+#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT }
+#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT }
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
index 8833e343d..855efff12 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h
@@ -1,5 +1,5 @@
/* libc-internal interface for mutex locks. LinuxThreads version.
- Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
+ Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -23,13 +23,13 @@
#include <pthread.h>
#if defined _LIBC && !defined NOT_IN_libc
-#include <linuxthreads.old/internals.h>
+#include <linuxthreads/internals.h>
#endif
/* Mutex type. */
#if defined(_LIBC) || defined(_IO_MTSAFE_IO)
typedef pthread_mutex_t __libc_lock_t;
-typedef pthread_mutex_t __libc_lock_recursive_t;
+typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
# ifdef __USE_UNIX98
typedef pthread_rwlock_t __libc_rwlock_t;
# else
@@ -131,39 +131,15 @@ typedef pthread_key_t __libc_key_t;
#define __libc_rwlock_init(NAME) \
(__libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0));
-/* Same as last but this time we initialize an adaptive mutex. */
-#if defined _LIBC && !defined NOT_IN_libc && defined SHARED
-#define __libc_lock_init_adaptive(NAME) \
- ({ \
- (NAME).__m_count = 0; \
- (NAME).__m_owner = NULL; \
- (NAME).__m_kind = PTHREAD_MUTEX_ADAPTIVE_NP; \
- (NAME).__m_lock.__status = 0; \
- (NAME).__m_lock.__spinlock = __LT_SPINLOCK_INIT; \
- 0; })
-#else
-#define __libc_lock_init_adaptive(NAME) \
- do { \
- if (__pthread_mutex_init != NULL) \
- { \
- pthread_mutexattr_t __attr; \
- __pthread_mutexattr_init (&__attr); \
- __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_ADAPTIVE_NP); \
- __pthread_mutex_init (&(NAME), &__attr); \
- __pthread_mutexattr_destroy (&__attr); \
- } \
- } while (0);
-#endif
-
/* Same as last but this time we initialize a recursive mutex. */
#if defined _LIBC && !defined NOT_IN_libc && defined SHARED
#define __libc_lock_init_recursive(NAME) \
({ \
- (NAME).__m_count = 0; \
- (NAME).__m_owner = NULL; \
- (NAME).__m_kind = PTHREAD_MUTEX_RECURSIVE_NP; \
- (NAME).__m_lock.__status = 0; \
- (NAME).__m_lock.__spinlock = __LT_SPINLOCK_INIT; \
+ (NAME).mutex.__m_count = 0; \
+ (NAME).mutex.__m_owner = NULL; \
+ (NAME).mutex.__m_kind = PTHREAD_MUTEX_RECURSIVE_NP; \
+ (NAME).mutex.__m_lock.__status = 0; \
+ (NAME).mutex.__m_lock.__spinlock = __LT_SPINLOCK_INIT; \
0; })
#else
#define __libc_lock_init_recursive(NAME) \
@@ -173,7 +149,7 @@ typedef pthread_key_t __libc_key_t;
pthread_mutexattr_t __attr; \
__pthread_mutexattr_init (&__attr); \
__pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \
- __pthread_mutex_init (&(NAME), &__attr); \
+ __pthread_mutex_init (&(NAME).mutex, &__attr); \
__pthread_mutexattr_destroy (&__attr); \
} \
} while (0);
@@ -226,6 +202,23 @@ typedef pthread_key_t __libc_key_t;
/* Unlock the recursive named lock variable. */
#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex)
+#if defined _LIBC && defined SHARED
+# define __rtld_lock_default_lock_recursive(lock) \
+ ++((pthread_mutex_t *)(lock))->__m_count;
+
+# define __rtld_lock_default_unlock_recursive(lock) \
+ --((pthread_mutex_t *)(lock))->__m_count;
+
+# define __rtld_lock_lock_recursive(NAME) \
+ GL(dl_rtld_lock_recursive) (&(NAME).mutex)
+
+# define __rtld_lock_unlock_recursive(NAME) \
+ GL(dl_rtld_unlock_recursive) (&(NAME).mutex)
+#else
+#define __rtld_lock_lock_recursive(NAME) __libc_lock_lock_recursive (NAME)
+#define __rtld_lock_unlock_recursive(NAME) __libc_lock_unlock_recursive (NAME)
+#endif
+
/* Define once control variable. */
#if PTHREAD_ONCE_INIT == 0
/* Special case for static variables where we can avoid the initialization
@@ -244,7 +237,7 @@ typedef pthread_key_t __libc_key_t;
__pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \
else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \
INIT_FUNCTION (); \
- (ONCE_CONTROL) = !PTHREAD_ONCE_INIT; \
+ (ONCE_CONTROL) = 2; \
} \
} while (0)
@@ -270,7 +263,6 @@ typedef pthread_key_t __libc_key_t;
_pthread_cleanup_pop_restore (&_buffer, (DOIT)); \
}
-#if 0
#define __libc_cleanup_push(fct, arg) \
{ struct _pthread_cleanup_buffer _buffer; \
__libc_maybe_call (_pthread_cleanup_push, (&_buffer, (fct), (arg)), 0)
@@ -278,7 +270,6 @@ typedef pthread_key_t __libc_key_t;
#define __libc_cleanup_pop(execute) \
__libc_maybe_call (_pthread_cleanup_pop, (&_buffer, execute), 0); \
}
-#endif
/* Create thread-specific key. */
#define __libc_key_create(KEY, DESTRUCTOR) \
@@ -376,6 +367,7 @@ weak_extern (BP_SYM (__pthread_key_create))
weak_extern (BP_SYM (__pthread_setspecific))
weak_extern (BP_SYM (__pthread_getspecific))
weak_extern (BP_SYM (__pthread_once))
+weak_extern (__pthread_initialize)
weak_extern (__pthread_atfork)
weak_extern (BP_SYM (_pthread_cleanup_push))
weak_extern (BP_SYM (_pthread_cleanup_pop))
@@ -400,6 +392,7 @@ weak_extern (BP_SYM (_pthread_cleanup_pop_restore))
# pragma weak __pthread_setspecific
# pragma weak __pthread_getspecific
# pragma weak __pthread_once
+# pragma weak __pthread_initialize
# pragma weak __pthread_atfork
# pragma weak _pthread_cleanup_push_defer
# pragma weak _pthread_cleanup_pop_restore
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
index 97af75ebf..7cc5f9cf6 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h
@@ -19,19 +19,7 @@
#ifndef _BITS_LIBC_TSD_H
#define _BITS_LIBC_TSD_H 1
-/* 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 };
-
-#include <features.h>
-#include <linuxthreads.old/internals.h>
-
+#include <linuxthreads/descr.h>
#ifdef __UCLIBC_HAS_TLS__
#include <tls.h>
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
index 3eb592919..8d01c8908 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
@@ -56,10 +56,20 @@ typedef struct __pthread_attr_s
/* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */
+
+#ifdef __GLIBC_HAVE_LONG_LONG
+__extension__ typedef long long __pthread_cond_align_t;
+#else
+typedef long __pthread_cond_align_t;
+#endif
+
typedef struct
{
struct _pthread_fastlock __c_lock; /* Protect against concurrent access */
_pthread_descr __c_waiting; /* Threads waiting on this condition */
+ char __padding[48 - sizeof (struct _pthread_fastlock)
+ - sizeof (_pthread_descr) - sizeof (__pthread_cond_align_t)];
+ __pthread_cond_align_t __align;
} pthread_cond_t;
@@ -121,7 +131,7 @@ typedef struct
#ifdef __USE_XOPEN2K
/* POSIX spinlock data type. */
-typedef volatile int pthread_spinlock_t;
+typedef __volatile__ int pthread_spinlock_t;
/* POSIX barrier. */
typedef struct {
diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h
new file mode 100644
index 000000000..0e900d2d5
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h
@@ -0,0 +1,65 @@
+/* bits/typesizes.h -- underlying types for *_t. Generic version.
+ Copyright (C) 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
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _BITS_TYPES_H
+# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef _BITS_TYPESIZES_H
+#define _BITS_TYPESIZES_H 1
+
+/* See <bits/types.h> for the meaning of these macros. This file exists so
+ that <bits/types.h> need not vary across different GNU platforms. */
+
+#define __DEV_T_TYPE __UQUAD_TYPE
+#define __UID_T_TYPE __U32_TYPE
+#define __GID_T_TYPE __U32_TYPE
+#define __INO_T_TYPE __ULONGWORD_TYPE
+#define __INO64_T_TYPE __UQUAD_TYPE
+#define __MODE_T_TYPE __U32_TYPE
+#define __NLINK_T_TYPE __UWORD_TYPE
+#define __OFF_T_TYPE __SLONGWORD_TYPE
+#define __OFF64_T_TYPE __SQUAD_TYPE
+#define __PID_T_TYPE __S32_TYPE
+#define __RLIM_T_TYPE __ULONGWORD_TYPE
+#define __RLIM64_T_TYPE __UQUAD_TYPE
+#define __BLKCNT_T_TYPE __SLONGWORD_TYPE
+#define __BLKCNT64_T_TYPE __SQUAD_TYPE
+#define __FSBLKCNT_T_TYPE __ULONGWORD_TYPE
+#define __FSBLKCNT64_T_TYPE __UQUAD_TYPE
+#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE
+#define __FSFILCNT64_T_TYPE __UQUAD_TYPE
+#define __ID_T_TYPE __U32_TYPE
+#define __CLOCK_T_TYPE __SLONGWORD_TYPE
+#define __TIME_T_TYPE __SLONGWORD_TYPE
+#define __USECONDS_T_TYPE __U32_TYPE
+#define __SUSECONDS_T_TYPE __SLONGWORD_TYPE
+#define __DADDR_T_TYPE __S32_TYPE
+#define __SWBLK_T_TYPE __SLONGWORD_TYPE
+#define __KEY_T_TYPE __S32_TYPE
+#define __CLOCKID_T_TYPE __S32_TYPE
+#define __TIMER_T_TYPE __S32_TYPE
+#define __BLKSIZE_T_TYPE __SLONGWORD_TYPE
+#define __FSID_T_TYPE struct { int __val[2]; }
+#define __SSIZE_T_TYPE __SWORD_TYPE
+
+/* Number of descriptors that can fit in an `fd_set'. */
+#define __FD_SETSIZE 1024
+
+
+#endif /* bits/typesizes.h */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c b/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c
new file mode 100644
index 000000000..8bdfff485
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c
@@ -0,0 +1,44 @@
+/* MT support function to get address of `errno' variable, linuxthreads
+ version.
+ Copyright (C) 1996, 1998, 2002, 2003, 2004 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 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <linuxthreads/internals.h>
+#include <sysdep-cancel.h>
+
+#if !defined __UCLIBC_HAS_TLS__ && !RTLD_PRIVATE_ERRNO
+#undef errno
+extern int errno;
+#endif
+
+int *
+#ifndef __UCLIBC_HAS_TLS__
+weak_const_function
+#endif
+__errno_location (void)
+{
+#if !defined __UCLIBC_HAS_TLS__ && !defined NOT_IN_libc
+ if (! SINGLE_THREAD_P)
+ {
+ pthread_descr self = thread_self();
+ return LIBC_THREAD_GETMEM (self, p_errnop);
+ }
+#endif
+ return &errno;
+}
+libc_hidden_def (__errno_location)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/flockfile.c b/libpthread/linuxthreads/sysdeps/pthread/flockfile.c
new file mode 100644
index 000000000..538e368a0
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/flockfile.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+#include <bits/stdio-lock.h>
+
+
+void
+__flockfile (stream)
+ FILE *stream;
+{
+ _IO_lock_lock (*stream->_lock);
+}
+strong_alias (__flockfile, _IO_flockfile)
+weak_alias (__flockfile, flockfile)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c b/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c
new file mode 100644
index 000000000..d814258d8
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <bits/stdio-lock.h>
+
+
+int
+__ftrylockfile (stream)
+ FILE *stream;
+{
+ return _IO_lock_trylock (*stream->_lock);
+}
+strong_alias (__ftrylockfile, _IO_ftrylockfile)
+weak_alias (__ftrylockfile, ftrylockfile)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c b/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c
new file mode 100644
index 000000000..f45479936
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+#include <bits/stdio-lock.h>
+
+
+void
+__funlockfile (stream)
+ FILE *stream;
+{
+ _IO_lock_unlock (*stream->_lock);
+}
+strong_alias (__funlockfile, _IO_funlockfile)
+weak_alias (__funlockfile, funlockfile)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c b/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c
new file mode 100644
index 000000000..6acb179c5
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c
@@ -0,0 +1,116 @@
+/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version
+ Copyright (C) 2000, 2001, 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
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <time.h>
+#include <internals.h>
+#include <spinlock.h>
+#include <bits/kernel-features.h>
+#include <kernel-posix-cpu-timers.h>
+
+
+#if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+int __libc_missing_posix_cpu_timers attribute_hidden;
+#endif
+#if !(__ASSUME_POSIX_TIMERS > 0)
+int __libc_missing_posix_timers attribute_hidden;
+#endif
+
+int
+pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id)
+{
+#ifdef __NR_clock_getres
+ pthread_handle handle = thread_handle(thread_id);
+ int pid;
+
+ __pthread_lock (&handle->h_lock, NULL);
+ if (nonexisting_handle (handle, thread_id))
+ {
+ __pthread_unlock (&handle->h_lock);
+ return ESRCH;
+ }
+ pid = handle->h_descr->p_pid;
+ __pthread_unlock (&handle->h_lock);
+
+ /* The clockid_t value is a simple computation from the PID.
+ But we do a clock_getres call to validate it if we aren't
+ yet sure we have the kernel support. */
+
+ const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, CPUCLOCK_SCHED);
+
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+# if !(__ASSUME_POSIX_TIMERS > 0)
+ if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers)
+ __libc_missing_posix_cpu_timers = 1;
+# endif
+ if (!__libc_missing_posix_cpu_timers)
+ {
+ INTERNAL_SYSCALL_DECL (err);
+ int r = INTERNAL_SYSCALL (clock_getres, err, 2, pidclock, NULL);
+ if (!INTERNAL_SYSCALL_ERROR_P (r, err))
+# endif
+ {
+ *clock_id = pidclock;
+ return 0;
+ }
+
+# if !(__ASSUME_POSIX_CPU_TIMERS > 0)
+# if !(__ASSUME_POSIX_TIMERS > 0)
+ if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS)
+ {
+ /* The kernel doesn't support these calls at all. */
+ __libc_missing_posix_timers = 1;
+ __libc_missing_posix_cpu_timers = 1;
+ }
+ else
+# endif
+ if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL)
+ {
+ /* The kernel doesn't support these clocks at all. */
+ __libc_missing_posix_cpu_timers = 1;
+ }
+ else
+ return INTERNAL_SYSCALL_ERRNO (r, err);
+ }
+# endif
+#endif
+
+#ifdef CLOCK_THREAD_CPUTIME_ID
+ /* We need to store the thread ID in the CLOCKID variable together
+ with a number identifying the clock. We reserve the low 3 bits
+ for the clock ID and the rest for the thread ID. This is
+ problematic if the thread ID is too large. But 29 bits should be
+ fine.
+
+ If some day more clock IDs are needed the ID part can be
+ enlarged. The IDs are entirely internal. */
+ if (2 * PTHREAD_THREADS_MAX
+ >= 1 << (8 * sizeof (*clock_id) - CLOCK_IDFIELD_SIZE))
+ return ERANGE;
+
+ /* Store the number. */
+ *clock_id = CLOCK_THREAD_CPUTIME_ID | (thread_id << CLOCK_IDFIELD_SIZE);
+
+ return 0;
+#else
+ /* We don't have a timer for that. */
+ return ENOENT;
+#endif
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c b/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c
new file mode 100644
index 000000000..634c75245
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1996, 97, 98, 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
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#ifdef __UCLIBC_HAS_TLS__
+#include <tls.h>
+#endif
+#include <linuxthreads/internals.h>
+#include <sysdep-cancel.h>
+
+#ifndef __UCLIBC_HAS_TLS__
+# undef h_errno
+extern int h_errno;
+#endif
+
+/* When threaded, h_errno may be a per-thread variable. */
+int *
+weak_const_function
+__h_errno_location (void)
+{
+#ifndef __UCLIBC_HAS_TLS__
+ if (! SINGLE_THREAD_P)
+ {
+ pthread_descr self = thread_self();
+ return LIBC_THREAD_GETMEM (self, p_h_errnop);
+ }
+#endif
+ return &h_errno;
+}
+libc_hidden_def (__h_errno_location)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/list.h b/libpthread/linuxthreads/sysdeps/pthread/list.h
new file mode 100644
index 000000000..232988fd6
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/list.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIST_H
+#define _LIST_H 1
+
+/* The definitions of this file are adopted from those which can be
+ found in the Linux kernel headers to enable people familiar with
+ the latter find their way in these sources as well. */
+
+
+/* Basic type for the double-link list. */
+typedef struct list_head
+{
+ struct list_head *next;
+ struct list_head *prev;
+} list_t;
+
+
+/* Define a variable with the head and tail of the list. */
+#define LIST_HEAD(name) \
+ list_t name = { &(name), &(name) }
+
+/* Initialize a new list head. */
+#define INIT_LIST_HEAD(ptr) \
+ (ptr)->next = (ptr)->prev = (ptr)
+
+
+/* Add new element at the head of the list. */
+static __inline__ void
+list_add (list_t *newp, list_t *head)
+{
+ head->next->prev = newp;
+ newp->next = head->next;
+ newp->prev = head;
+ head->next = newp;
+}
+
+
+/* Add new element at the tail of the list. */
+static __inline__ void
+list_add_tail (list_t *newp, list_t *head)
+{
+ head->prev->next = newp;
+ newp->next = head;
+ newp->prev = head->prev;
+ head->prev = newp;
+}
+
+
+/* Remove element from list. */
+static __inline__ void
+list_del (list_t *elem)
+{
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+}
+
+
+/* Join two lists. */
+static __inline__ void
+list_splice (list_t *add, list_t *head)
+{
+ /* Do nothing if the list which gets added is empty. */
+ if (add != add->next)
+ {
+ add->next->prev = head;
+ add->prev->next = head->next;
+ head->next->prev = add->prev;
+ head->next = add->next;
+ }
+}
+
+
+/* Get typed element from list at a given position. */
+#define list_entry(ptr, type, member) \
+ ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
+
+
+
+/* Iterate forward over the elements of the list. */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+
+/* Iterate forward over the elements of the list. */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+
+/* Iterate backwards over the elements list. The list elements can be
+ removed from the list while doing this. */
+#define list_for_each_prev_safe(pos, p, head) \
+ for (pos = (head)->prev, p = pos->prev; \
+ pos != (head); \
+ pos = p, p = pos->prev)
+
+#endif /* list.h */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h b/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h
new file mode 100644
index 000000000..f70729fd7
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h
@@ -0,0 +1,66 @@
+/* Basic platform-independent macro definitions for mutexes,
+ thread-specific data and parameters for malloc.
+ Copyright (C) 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
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _MALLOC_MACHINE_H
+#define _MALLOC_MACHINE_H
+
+#undef thread_atfork_static
+
+#include <atomic.h>
+#include <bits/libc-lock.h>
+
+__libc_lock_define (typedef, mutex_t)
+
+#define mutex_init(m) \
+ __libc_maybe_call2 (pthread_mutex_init, (m, NULL), (*(int *)(m) = 0))
+#define mutex_lock(m) \
+ __libc_maybe_call2 (pthread_mutex_lock, (m), ((*(int *)(m) = 1), 0))
+#define mutex_trylock(m) \
+ __libc_maybe_call2 (pthread_mutex_trylock, (m), \
+ (*(int *)(m) ? 1 : ((*(int *)(m) = 1), 0)))
+#define mutex_unlock(m) \
+ __libc_maybe_call2 (pthread_mutex_unlock, (m), (*(int *)(m) = 0))
+
+/* This is defined by newer gcc version unique for each module. */
+extern void *__dso_handle __attribute__ ((__weak__));
+
+#include <fork.h>
+
+#ifdef SHARED
+# define thread_atfork(prepare, parent, child) \
+ __register_atfork (prepare, parent, child, __dso_handle)
+#else
+# define thread_atfork(prepare, parent, child) \
+ __register_atfork (prepare, parent, child, \
+ &__dso_handle == NULL ? NULL : __dso_handle)
+#endif
+
+/* thread specific data for glibc */
+
+#include <bits/libc-tsd.h>
+
+typedef int tsd_key_t[1]; /* no key data structure, libc magic does it */
+__libc_tsd_define (static, MALLOC) /* declaration/common definition */
+#define tsd_key_create(key, destr) ((void) (key))
+#define tsd_setspecific(key, data) __libc_tsd_set (MALLOC, (data))
+#define tsd_getspecific(key, vptr) ((vptr) = __libc_tsd_get (MALLOC))
+
+#include <sysdeps/generic/malloc-machine.h>
+
+#endif /* !defined(_MALLOC_MACHINE_H) */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h
index bbdb0739c..b46d2ab49 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h
@@ -23,10 +23,10 @@
/* Uncancelable open. */
#if defined __NR_openat && !defined __NR_open
#define open_not_cancel(name, flags, mode) \
- INLINE_SYSCALL (openat, 4, AT_FDCWD, (const char *) (name), \
+ INLINE_SYSCALL (openat, 4, (int) (AT_FDCWD), (const char *) (name), \
(flags), (mode))
#define open_not_cancel_2(name, flags) \
- INLINE_SYSCALL (openat, 3, AT_FDCWD, (const char *) (name), \
+ INLINE_SYSCALL (openat, 3, (int) (AT_FDCWD), (const char *) (name), \
(flags))
#else
#define open_not_cancel(name, flags, mode) \
diff --git a/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h b/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h
new file mode 100644
index 000000000..4ac64d9ac
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h
@@ -0,0 +1,203 @@
+/* Definitions for POSIX timer implementation on top of LinuxThreads.
+ Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <limits.h>
+#include <signal.h>
+
+/* Double linked list. */
+struct list_links
+{
+ struct list_links *next;
+ struct list_links *prev;
+};
+
+
+/* Forward declaration. */
+struct timer_node;
+
+
+/* Definitions for an internal thread of the POSIX timer implementation. */
+struct thread_node
+{
+ struct list_links links;
+ pthread_attr_t attr;
+ pthread_t id;
+ unsigned int exists;
+ struct list_links timer_queue;
+ pthread_cond_t cond;
+ struct timer_node *current_timer;
+ pthread_t captured;
+ clockid_t clock_id;
+};
+
+
+/* Internal representation of a timer. */
+struct timer_node
+{
+ struct list_links links;
+ struct sigevent event;
+ clockid_t clock;
+ struct itimerspec value;
+ struct timespec expirytime;
+ pthread_attr_t attr;
+ unsigned int abstime;
+ unsigned int armed;
+ enum {
+ TIMER_FREE, TIMER_INUSE, TIMER_DELETED
+ } inuse;
+ struct thread_node *thread;
+ pid_t creator_pid;
+ int refcount;
+ int overrun_count;
+};
+
+
+/* Static array with the structures for all the timers. */
+extern struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists. */
+extern pthread_mutex_t __timer_mutex;
+
+/* Variable to protext initialization. */
+extern pthread_once_t __timer_init_once_control;
+
+/* Nonzero if initialization of timer implementation failed. */
+extern int __timer_init_failed;
+
+/* Nodes for the threads used to deliver signals. */
+/* A distinct thread is used for each clock type. */
+
+extern struct thread_node __timer_signal_thread_rclk;
+
+
+/* Return pointer to timer structure corresponding to ID. */
+static __inline__ struct timer_node *
+timer_id2ptr (timer_t timerid)
+{
+ if (timerid >= 0 && timerid < TIMER_MAX)
+ return &__timer_array[timerid];
+
+ return NULL;
+}
+
+/* Return ID of TIMER. */
+static __inline__ int
+timer_ptr2id (struct timer_node *timer)
+{
+ return timer - __timer_array;
+}
+
+/* Check whether timer is valid; global mutex must be held. */
+static __inline__ int
+timer_valid (struct timer_node *timer)
+{
+ return timer && timer->inuse == TIMER_INUSE;
+}
+
+/* Timer refcount functions; need global mutex. */
+extern void __timer_dealloc (struct timer_node *timer);
+
+static __inline__ void
+timer_addref (struct timer_node *timer)
+{
+ timer->refcount++;
+}
+
+static __inline__ void
+timer_delref (struct timer_node *timer)
+{
+ if (--timer->refcount == 0)
+ __timer_dealloc (timer);
+}
+
+/* Timespec helper routines. */
+static __inline__ int
+timespec_compare (const struct timespec *left, const struct timespec *right)
+{
+ if (left->tv_sec < right->tv_sec)
+ return -1;
+ if (left->tv_sec > right->tv_sec)
+ return 1;
+
+ if (left->tv_nsec < right->tv_nsec)
+ return -1;
+ if (left->tv_nsec > right->tv_nsec)
+ return 1;
+
+ return 0;
+}
+
+static __inline__ void
+timespec_add (struct timespec *sum, const struct timespec *left,
+ const struct timespec *right)
+{
+ sum->tv_sec = left->tv_sec + right->tv_sec;
+ sum->tv_nsec = left->tv_nsec + right->tv_nsec;
+
+ if (sum->tv_nsec >= 1000000000)
+ {
+ ++sum->tv_sec;
+ sum->tv_nsec -= 1000000000;
+ }
+}
+
+static __inline__ void
+timespec_sub (struct timespec *diff, const struct timespec *left,
+ const struct timespec *right)
+{
+ diff->tv_sec = left->tv_sec - right->tv_sec;
+ diff->tv_nsec = left->tv_nsec - right->tv_nsec;
+
+ if (diff->tv_nsec < 0)
+ {
+ --diff->tv_sec;
+ diff->tv_nsec += 1000000000;
+ }
+}
+
+
+/* We need one of the list functions in the other modules. */
+static __inline__ void
+list_unlink_ip (struct list_links *list)
+{
+ struct list_links *lnext = list->next, *lprev = list->prev;
+
+ lnext->prev = lprev;
+ lprev->next = lnext;
+
+ /* The suffix ip means idempotent; list_unlink_ip can be called
+ * two or more times on the same node.
+ */
+
+ list->next = list;
+ list->prev = list;
+}
+
+
+/* Functions in the helper file. */
+extern void __timer_mutex_cancel_handler (void *arg);
+extern void __timer_init_once (void);
+extern struct timer_node *__timer_alloc (void);
+extern int __timer_thread_start (struct thread_node *thread);
+extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
+extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
+extern void __timer_thread_dealloc (struct thread_node *thread);
+extern int __timer_thread_queue_timer (struct thread_node *thread,
+ struct timer_node *insert);
+extern void __timer_thread_wakeup (struct thread_node *thread);
diff --git a/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c b/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c
new file mode 100644
index 000000000..86d4c84e9
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c
@@ -0,0 +1,123 @@
+/* Special .init and .fini section support. Linuxthread version.
+ Copyright (C) 1995, 1996, 1997, 2000, 2001 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 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.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ 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 Lesser General Public License for more details.
+
+ 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,
+ see <http://www.gnu.org/licenses/>. */
+
+/* This file is compiled into assembly code which is then munged by a sed
+ script into two files: crti.s and crtn.s.
+
+ * crti.s puts a function prologue at the beginning of the
+ .init and .fini sections and defines global symbols for
+ those addresses, so they can be called as functions.
+
+ * crtn.s puts the corresponding function epilogues
+ in the .init and .fini sections. */
+
+#include <stdlib.h>
+
+/* We use embedded asm for .section unconditionally, as this makes it
+ easier to insert the necessary directives into crtn.S. */
+#define SECTION(x) __asm__ (".section " x )
+
+/* Embed an #include to pull in the alignment and .end directives. */
+__asm__ ("\n#include \"defs.h\"");
+
+/* The initial common code ends here. */
+__asm__ ("\n/*@HEADER_ENDS*/");
+
+/* To determine whether we need .end and .align: */
+__asm__ ("\n/*@TESTS_BEGIN*/");
+extern void dummy (void (*foo) (void));
+void
+dummy (void (*foo) (void))
+{
+ if (foo)
+ (*foo) ();
+}
+__asm__ ("\n/*@TESTS_END*/");
+
+/* The beginning of _init: */
+__asm__ ("\n/*@_init_PROLOG_BEGINS*/");
+
+static void
+call_initialize_minimal (void)
+{
+ extern void __pthread_initialize_minimal (void);
+
+ __pthread_initialize_minimal ();
+}
+
+SECTION (".init");
+extern void _init (void);
+void
+_init (void)
+{
+ /* The very first thing we must do is to set up the registers. */
+ call_initialize_minimal ();
+
+ __asm__ ("ALIGN");
+ __asm__("END_INIT");
+ /* Now the epilog. */
+ __asm__ ("\n/*@_init_PROLOG_ENDS*/");
+ __asm__ ("\n/*@_init_EPILOG_BEGINS*/");
+ SECTION(".init");
+}
+__asm__ ("END_INIT");
+
+/* End of the _init epilog, beginning of the _fini prolog. */
+__asm__ ("\n/*@_init_EPILOG_ENDS*/");
+__asm__ ("\n/*@_fini_PROLOG_BEGINS*/");
+
+SECTION (".fini");
+extern void _fini (void);
+void
+_fini (void)
+{
+
+ /* End of the _fini prolog. */
+ __asm__ ("ALIGN");
+ __asm__ ("END_FINI");
+ __asm__ ("\n/*@_fini_PROLOG_ENDS*/");
+
+ {
+ /* Let GCC know that _fini is not a leaf function by having a dummy
+ function call here. We arrange for this call to be omitted from
+ either crt file. */
+ extern void i_am_not_a_leaf (void);
+ i_am_not_a_leaf ();
+ }
+
+ /* Beginning of the _fini epilog. */
+ __asm__ ("\n/*@_fini_EPILOG_BEGINS*/");
+ SECTION (".fini");
+}
+__asm__ ("END_FINI");
+
+/* End of the _fini epilog. Any further generated assembly (e.g. .ident)
+ is shared between both crt files. */
+__asm__ ("\n/*@_fini_EPILOG_ENDS*/");
+__asm__ ("\n/*@TRAILER_BEGINS*/");
+
+/* End of file. */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h b/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h
index 2afaa52e8..6d8663dcb 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h
@@ -20,21 +20,17 @@
#define _PTHREAD_FUNCTIONS_H 1
#include <pthread.h>
-#if 0
#include <setjmp.h>
-#include <linuxthreads.old/internals.h>
+#include <linuxthreads/descr.h>
struct fork_block;
-#endif
/* Data type shared with libc. The libc uses it to pass on calls to
the thread functions. Wine pokes directly into this structure,
so if possible avoid breaking it and append new hooks to the end. */
struct pthread_functions
{
-#if 0
pid_t (*ptr_pthread_fork) (struct fork_block *);
-#endif
int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
int (*ptr_pthread_attr_init) (pthread_attr_t *);
int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *);
@@ -71,36 +67,28 @@ struct pthread_functions
pthread_t (*ptr_pthread_self) (void);
int (*ptr_pthread_setcancelstate) (int, int *);
int (*ptr_pthread_setcanceltype) (int, int *);
-#if 0
void (*ptr_pthread_do_exit) (void *retval, char *currentframe);
void (*ptr_pthread_cleanup_upto) (__jmp_buf target,
char *targetframe);
pthread_descr (*ptr_pthread_thread_self) (void);
-#endif
#if !defined __UCLIBC_HAS_TLS__ && defined __UCLIBC_HAS_RPC__
int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer);
void * (*ptr_pthread_internal_tsd_get) (int key);
void ** __attribute__ ((__const__))
(*ptr_pthread_internal_tsd_address) (int key);
#endif
-#if 0
int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act,
struct sigaction *oact);
int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig);
int (*ptr_pthread_raise) (int sig);
-#endif
int (*ptr_pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *,
const struct timespec *);
-#if 0
void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer,
void (*routine)(void *), void * arg);
-#endif
void (*ptr__pthread_cleanup_push_defer) (struct _pthread_cleanup_buffer * buffer,
void (*routine)(void *), void * arg);
-#if 0
void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer,
int execute);
-#endif
void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer * buffer,
int execute);
};
diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread.h b/libpthread/linuxthreads/sysdeps/pthread/pthread.h
index 46c1010c6..94ed95c99 100644
--- a/libpthread/linuxthreads/sysdeps/pthread/pthread.h
+++ b/libpthread/linuxthreads/sysdeps/pthread/pthread.h
@@ -31,7 +31,7 @@ __BEGIN_DECLS
/* Initializers. */
#define PTHREAD_MUTEX_INITIALIZER \
- {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
+ {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER}
#ifdef __USE_GNU
# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
{0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
@@ -41,7 +41,7 @@ __BEGIN_DECLS
{0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER}
#endif
-#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0}
+#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0, "", 0}
#if defined __USE_UNIX98 || defined __USE_XOPEN2K
# define PTHREAD_RWLOCK_INITIALIZER \
@@ -82,13 +82,13 @@ enum
enum
{
- PTHREAD_MUTEX_ADAPTIVE_NP,
+ PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
- PTHREAD_MUTEX_TIMED_NP
+ PTHREAD_MUTEX_ADAPTIVE_NP
#ifdef __USE_UNIX98
,
- PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_ADAPTIVE_NP,
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
@@ -256,7 +256,7 @@ extern int pthread_attr_getguardsize (const pthread_attr_t *__restrict
/* Set the starting address of the stack of the thread to be created.
Depending on whether the stack grows up or down the value must either
be higher or lower than all the address in the memory block. The
- minimal size of the block must be PTHREAD_STACK_SIZE. */
+ minimal size of the block must be PTHREAD_STACK_MIN. */
extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,
void *__stackaddr) __THROW;
@@ -280,7 +280,7 @@ extern int pthread_attr_getstack (const pthread_attr_t *__restrict __attr,
#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
+ to be started. This size must never be less than PTHREAD_STACK_MIN
and must also not exceed the system limits. */
extern int pthread_attr_setstacksize (pthread_attr_t *__attr,
size_t __stacksize) __THROW;
@@ -290,16 +290,12 @@ extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict
__attr, size_t *__restrict __stacksize)
__THROW;
-#if 0
-/* Not yet implemented in uClibc! */
-
#ifdef __USE_GNU
/* Initialize thread attribute *ATTR with attributes corresponding to the
already running thread TH. It shall be called on uninitialized 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
/* Functions for scheduling control. */
@@ -323,11 +319,6 @@ extern int pthread_getconcurrency (void) __THROW;
extern int pthread_setconcurrency (int __level) __THROW;
#endif
-#ifdef __USE_GNU
-/* Same thing, different name */
-#define pthread_yield() sched_yield()
-#endif
-
/* Functions for mutex handling. */
/* Initialize MUTEX using attributes in *MUTEX_ATTR, or use the
@@ -394,25 +385,20 @@ extern int pthread_mutexattr_gettype (const pthread_mutexattr_t *__restrict
extern int pthread_cond_init (pthread_cond_t *__restrict __cond,
const pthread_condattr_t *__restrict
__cond_attr) __THROW;
-libpthread_hidden_proto(pthread_cond_init)
/* Destroy condition variable COND. */
extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW;
-libpthread_hidden_proto(pthread_cond_destroy)
/* Wake up one thread waiting for condition variable COND. */
extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW;
-libpthread_hidden_proto(pthread_cond_signal)
/* Wake up all threads waiting for condition variables COND. */
extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW;
-libpthread_hidden_proto(pthread_cond_broadcast)
/* 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);
-libpthread_hidden_proto(pthread_cond_wait)
/* Wait for condition variable COND to be signaled or broadcast until
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
@@ -422,17 +408,14 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict
__abstime);
-libpthread_hidden_proto(pthread_cond_timedwait)
/* Functions for handling condition variable attributes. */
/* Initialize condition variable attribute ATTR. */
extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW;
-libpthread_hidden_proto(pthread_condattr_init)
/* Destroy condition variable attribute ATTR. */
extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW;
-libpthread_hidden_proto(pthread_condattr_destroy)
/* Get the process-shared flag of the condition variable attribute ATTR. */
extern int pthread_condattr_getpshared (const pthread_condattr_t *
@@ -512,9 +495,6 @@ extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr,
int __pref) __THROW;
#endif
-#if 0
-/* Not yet implemented in uClibc! */
-
#ifdef __USE_XOPEN2K
/* The IEEE Std. 1003.1j-2000 introduces functions to implement
spinlocks. */
@@ -558,7 +538,6 @@ extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr,
extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW;
#endif
-#endif
/* Functions for handling thread-specific data. */
@@ -650,9 +629,6 @@ extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
void (*__routine) (void *),
void *__arg) __THROW;
-extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
- void (*__routine) (void *),
- void *__arg) __THROW;
/* Remove a cleanup handler as pthread_cleanup_pop does, but also
restores the cancellation type that was in effect when the matching
@@ -663,19 +639,13 @@ extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buff
extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
int __execute) __THROW;
-extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
- int __execute) __THROW;
#endif
-#if 0
-/* Not yet implemented in uClibc! */
-
#ifdef __USE_XOPEN2K
/* Get ID of CPU-time clock for thread THREAD_ID. */
extern int pthread_getcpuclockid (pthread_t __thread_id,
- clockid_t *__clock_id) __THROW;
-#endif
+ __clockid_t *__clock_id) __THROW;
#endif
diff --git a/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c b/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c
new file mode 100644
index 000000000..ee5522036
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c
@@ -0,0 +1,32 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix */
+/* threads for Linux. */
+/* Copyright (C) 1998 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. */
+
+/* Redefine siglongjmp and longjmp so that they interact correctly
+ with cleanup handlers */
+
+#include <setjmp.h>
+#include "pthread.h"
+#include "internals.h"
+
+#ifdef SHARED
+void siglongjmp (sigjmp_buf env, int val)
+{
+ __libc_siglongjmp (env, val);
+}
+
+void longjmp (jmp_buf env, int val)
+{
+ __libc_longjmp (env, val);
+}
+#endif
diff --git a/libpthread/linuxthreads/sysdeps/pthread/res-state.c b/libpthread/linuxthreads/sysdeps/pthread/res-state.c
new file mode 100644
index 000000000..6b4354972
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/res-state.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1996, 97, 98, 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
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <resolv.h>
+#include <tls.h>
+#include <linuxthreads/internals.h>
+#include <sysdep-cancel.h>
+
+#ifndef __UCLIBC_HAS_TLS__
+# undef _res
+extern struct __res_state _res;
+#endif
+
+/* When threaded, _res may be a per-thread variable. */
+struct __res_state *
+#ifndef __UCLIBC_HAS_TLS__
+weak_const_function
+#endif
+__res_state (void)
+{
+#ifndef __UCLIBC_HAS_TLS__
+ if (! SINGLE_THREAD_P)
+ {
+ pthread_descr self = thread_self();
+ return LIBC_THREAD_GETMEM (self, p_resp);
+ }
+ return &_res;
+#else
+ return __resp;
+#endif
+}
+libc_hidden_def (__res_state)
diff --git a/libpthread/linuxthreads/sysdeps/pthread/semaphore.h b/libpthread/linuxthreads/sysdeps/pthread/semaphore.h
new file mode 100644
index 000000000..8793768a8
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/semaphore.h
@@ -0,0 +1 @@
+#include <linuxthreads/semaphore.h>
diff --git a/libpthread/linuxthreads/sysdeps/pthread/sigaction.c b/libpthread/linuxthreads/sysdeps/pthread/sigaction.c
new file mode 100644
index 000000000..eecb8c395
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/sigaction.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Somebody please explain what's going on here. --vda */
+
+/* This is tricky. GCC doesn't like #include_next in the primary
+ source file and even if it did, the first #include_next is this
+ exact file anyway. */
+#ifndef LIBC_SIGACTION
+
+# include <bits/libc-lock.h>
+
+# define LIBC_SIGACTION 1
+
+# include "sigaction.c"
+
+# ifndef NOT_IN_libc
+# ifndef SHARED
+weak_extern (__pthread_sigaction)
+# endif
+
+int
+__sigaction (sig, act, oact)
+ int sig;
+ const struct sigaction *act;
+ struct sigaction *oact;
+{
+ return __libc_maybe_call2 (pthread_sigaction, (sig, act, oact),
+ __libc_sigaction (sig, act, oact));
+}
+# else
+weak_alias (__libc_sigaction, __sigaction)
+# endif
+libc_hidden_weak (__sigaction)
+weak_alias (__sigaction, sigaction)
+
+#else
+
+# include_next <sigaction.c>
+
+#endif /* LIBC_SIGACTION */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h b/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h
new file mode 100644
index 000000000..3fe13702e
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h
@@ -0,0 +1 @@
+/* This is overridden by generated tcb-offsets.h on arches which need it. */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_create.c b/libpthread/linuxthreads/sysdeps/pthread/timer_create.c
new file mode 100644
index 000000000..36fce3567
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_create.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "posix-timer.h"
+
+
+/* Create new per-process timer using CLOCK. */
+int
+timer_create (clock_id, evp, timerid)
+ clockid_t clock_id;
+ struct sigevent *evp;
+ timer_t *timerid;
+{
+ int retval = -1;
+ struct timer_node *newtimer = NULL;
+ struct thread_node *thread = NULL;
+
+ if (0
+#ifdef _POSIX_CPUTIME
+ || clock_id == CLOCK_PROCESS_CPUTIME_ID
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+ || clock_id == CLOCK_THREAD_CPUTIME_ID
+#endif
+ )
+ {
+ /* We don't allow timers for CPU clocks. At least not in the
+ moment. */
+ __set_errno (ENOTSUP);
+ return -1;
+ }
+
+ if (clock_id != CLOCK_REALTIME)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ pthread_once (&__timer_init_once_control, __timer_init_once);
+
+ if (__timer_init_failed)
+ {
+ __set_errno (ENOMEM);
+ return -1;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ newtimer = __timer_alloc ();
+ if (__builtin_expect (newtimer == NULL, 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+
+ if (evp != NULL)
+ newtimer->event = *evp;
+ else
+ {
+ newtimer->event.sigev_notify = SIGEV_SIGNAL;
+ newtimer->event.sigev_signo = SIGALRM;
+ newtimer->event.sigev_value.sival_int = timer_ptr2id (newtimer);
+ newtimer->event.sigev_notify_function = 0;
+ }
+
+ newtimer->event.sigev_notify_attributes = &newtimer->attr;
+ newtimer->creator_pid = getpid ();
+
+ switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
+ {
+ case SIGEV_NONE:
+ case SIGEV_SIGNAL:
+ /* We have a global thread for delivering timed signals.
+ If it is not running, try to start it up. */
+ thread = &__timer_signal_thread_rclk;
+ if (! thread->exists)
+ {
+ if (__builtin_expect (__timer_thread_start (thread),
+ 1) < 0)
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+ }
+ break;
+
+ case SIGEV_THREAD:
+ /* Copy over thread attributes or set up default ones. */
+ if (evp->sigev_notify_attributes)
+ newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
+ else
+ pthread_attr_init (&newtimer->attr);
+
+ /* Ensure thread attributes call for deatched thread. */
+ pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
+
+ /* Try to find existing thread having the right attributes. */
+ thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
+
+ /* If no existing thread has these attributes, try to allocate one. */
+ if (thread == NULL)
+ thread = __timer_thread_alloc (&newtimer->attr, clock_id);
+
+ /* Out of luck; no threads are available. */
+ if (__builtin_expect (thread == NULL, 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+
+ /* If the thread is not running already, try to start it. */
+ if (! thread->exists
+ && __builtin_expect (! __timer_thread_start (thread), 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+ break;
+
+ default:
+ __set_errno (EINVAL);
+ goto unlock_bail;
+ }
+
+ newtimer->clock = clock_id;
+ newtimer->abstime = 0;
+ newtimer->armed = 0;
+ newtimer->thread = thread;
+
+ *timerid = timer_ptr2id (newtimer);
+ retval = 0;
+
+ if (__builtin_expect (retval, 0) == -1)
+ {
+ unlock_bail:
+ if (thread != NULL)
+ __timer_thread_dealloc (thread);
+ if (newtimer != NULL)
+ {
+ timer_delref (newtimer);
+ __timer_dealloc (newtimer);
+ }
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c b/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c
new file mode 100644
index 000000000..a529d7392
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Delete timer TIMERID. */
+int
+timer_delete (timerid)
+ timer_t timerid;
+{
+ struct timer_node *timer;
+ int retval = -1;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ timer = timer_id2ptr (timerid);
+ if (! timer_valid (timer))
+ /* Invalid timer ID or the timer is not in use. */
+ __set_errno (EINVAL);
+ else
+ {
+ if (timer->armed && timer->thread != NULL)
+ {
+ struct thread_node *thread = timer->thread;
+ assert (thread != NULL);
+
+ /* If thread is cancelled while waiting for handler to terminate,
+ the mutex is unlocked and timer_delete is aborted. */
+ pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex);
+
+ /* If timer is currently being serviced, wait for it to finish. */
+ while (thread->current_timer == timer)
+ pthread_cond_wait (&thread->cond, &__timer_mutex);
+
+ pthread_cleanup_pop (0);
+ }
+
+ /* Remove timer from whatever queue it may be on and deallocate it. */
+ timer->inuse = TIMER_DELETED;
+ list_unlink_ip (&timer->links);
+ timer_delref (timer);
+ retval = 0;
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c b/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c
new file mode 100644
index 000000000..6d753e30d
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get expiration overrun for timer TIMERID. */
+int
+timer_getoverrun (timerid)
+ timer_t timerid;
+{
+ struct timer_node *timer;
+ int retval = -1;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ if (! timer_valid (timer = timer_id2ptr (timerid)))
+ __set_errno (EINVAL);
+ else
+ retval = timer->overrun_count;
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c b/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c
new file mode 100644
index 000000000..6bd2b84e2
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c
@@ -0,0 +1,76 @@
+/* Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get current value of timer TIMERID and store it in VLAUE. */
+int
+timer_gettime (timerid, value)
+ timer_t timerid;
+ struct itimerspec *value;
+{
+ struct timer_node *timer;
+ struct timespec now, expiry;
+ int retval = -1, armed = 0, valid;
+ clock_t clock = 0;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ timer = timer_id2ptr (timerid);
+ valid = timer_valid (timer);
+
+ if (valid) {
+ armed = timer->armed;
+ expiry = timer->expirytime;
+ clock = timer->clock;
+ value->it_interval = timer->value.it_interval;
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ if (valid)
+ {
+ if (armed)
+ {
+ clock_gettime (clock, &now);
+ if (timespec_compare (&now, &expiry) < 0)
+ timespec_sub (&value->it_value, &expiry, &now);
+ else
+ {
+ value->it_value.tv_sec = 0;
+ value->it_value.tv_nsec = 0;
+ }
+ }
+ else
+ {
+ value->it_value.tv_sec = 0;
+ value->it_value.tv_nsec = 0;
+ }
+
+ retval = 0;
+ }
+ else
+ __set_errno (EINVAL);
+
+ return retval;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c b/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c
new file mode 100644
index 000000000..9f6096ba5
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c
@@ -0,0 +1,572 @@
+/* Helper code for POSIX timer implementation on LinuxThreads.
+ Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "posix-timer.h"
+
+
+/* Number of threads used. */
+#define THREAD_MAXNODES 16
+
+/* Array containing the descriptors for the used threads. */
+static struct thread_node thread_array[THREAD_MAXNODES];
+
+/* Static array with the structures for all the timers. */
+struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists. */
+pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Variable to protext initialization. */
+pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
+
+/* Nonzero if initialization of timer implementation failed. */
+int __timer_init_failed;
+
+/* Node for the thread used to deliver signals. */
+struct thread_node __timer_signal_thread_rclk;
+
+/* Lists to keep free and used timers and threads. */
+struct list_links timer_free_list;
+struct list_links thread_free_list;
+struct list_links thread_active_list;
+
+
+#ifdef __NR_rt_sigqueueinfo
+extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *);
+#endif
+
+
+/* List handling functions. */
+static __inline__ void
+list_init (struct list_links *list)
+{
+ list->next = list->prev = list;
+}
+
+static __inline__ void
+list_append (struct list_links *list, struct list_links *newp)
+{
+ newp->prev = list->prev;
+ newp->next = list;
+ list->prev->next = newp;
+ list->prev = newp;
+}
+
+static __inline__ void
+list_insbefore (struct list_links *list, struct list_links *newp)
+{
+ list_append (list, newp);
+}
+
+/*
+ * Like list_unlink_ip, except that calling it on a node that
+ * is already unlinked is disastrous rather than a noop.
+ */
+
+static __inline__ void
+list_unlink (struct list_links *list)
+{
+ struct list_links *lnext = list->next, *lprev = list->prev;
+
+ lnext->prev = lprev;
+ lprev->next = lnext;
+}
+
+static __inline__ struct list_links *
+list_first (struct list_links *list)
+{
+ return list->next;
+}
+
+static __inline__ struct list_links *
+list_null (struct list_links *list)
+{
+ return list;
+}
+
+static __inline__ struct list_links *
+list_next (struct list_links *list)
+{
+ return list->next;
+}
+
+static __inline__ int
+list_isempty (struct list_links *list)
+{
+ return list->next == list;
+}
+
+
+/* Functions build on top of the list functions. */
+static __inline__ struct thread_node *
+thread_links2ptr (struct list_links *list)
+{
+ return (struct thread_node *) ((char *) list
+ - offsetof (struct thread_node, links));
+}
+
+static __inline__ struct timer_node *
+timer_links2ptr (struct list_links *list)
+{
+ return (struct timer_node *) ((char *) list
+ - offsetof (struct timer_node, links));
+}
+
+
+/* Initialize a newly allocated thread structure. */
+static void
+thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
+{
+ if (attr != NULL)
+ thread->attr = *attr;
+ else
+ {
+ pthread_attr_init (&thread->attr);
+ pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
+ }
+
+ thread->exists = 0;
+ list_init (&thread->timer_queue);
+ pthread_cond_init (&thread->cond, 0);
+ thread->current_timer = 0;
+ thread->captured = pthread_self ();
+ thread->clock_id = clock_id;
+}
+
+
+/* Initialize the global lists, and acquire global resources. Error
+ reporting is done by storing a non-zero value to the global variable
+ timer_init_failed. */
+static void
+init_module (void)
+{
+ int i;
+
+ list_init (&timer_free_list);
+ list_init (&thread_free_list);
+ list_init (&thread_active_list);
+
+ for (i = 0; i < TIMER_MAX; ++i)
+ {
+ list_append (&timer_free_list, &__timer_array[i].links);
+ __timer_array[i].inuse = TIMER_FREE;
+ }
+
+ for (i = 0; i < THREAD_MAXNODES; ++i)
+ list_append (&thread_free_list, &thread_array[i].links);
+
+ thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
+}
+
+
+/* This is a handler executed in a child process after a fork()
+ occurs. It reinitializes the module, resetting all of the data
+ structures to their initial state. The mutex is initialized in
+ case it was locked in the parent process. */
+static void
+reinit_after_fork (void)
+{
+ init_module ();
+ pthread_mutex_init (&__timer_mutex, 0);
+}
+
+
+/* Called once form pthread_once in timer_init. This initializes the
+ module and ensures that reinit_after_fork will be executed in any
+ child process. */
+void
+__timer_init_once (void)
+{
+ init_module ();
+ pthread_atfork (0, 0, reinit_after_fork);
+}
+
+
+/* Deinitialize a thread that is about to be deallocated. */
+static void
+thread_deinit (struct thread_node *thread)
+{
+ assert (list_isempty (&thread->timer_queue));
+ pthread_cond_destroy (&thread->cond);
+}
+
+
+/* Allocate a thread structure from the global free list. Global
+ mutex lock must be held by caller. The thread is moved to
+ the active list. */
+struct thread_node *
+__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
+{
+ struct list_links *node = list_first (&thread_free_list);
+
+ if (node != list_null (&thread_free_list))
+ {
+ struct thread_node *thread = thread_links2ptr (node);
+ list_unlink (node);
+ thread_init (thread, desired_attr, clock_id);
+ list_append (&thread_active_list, node);
+ return thread;
+ }
+
+ return 0;
+}
+
+
+/* Return a thread structure to the global free list. Global lock
+ must be held by caller. */
+void
+__timer_thread_dealloc (struct thread_node *thread)
+{
+ thread_deinit (thread);
+ list_unlink (&thread->links);
+ list_append (&thread_free_list, &thread->links);
+}
+
+
+/* Each of our threads which terminates executes this cleanup
+ handler. We never terminate threads ourselves; if a thread gets here
+ it means that the evil application has killed it. If the thread has
+ timers, these require servicing and so we must hire a replacement
+ thread right away. We must also unblock another thread that may
+ have been waiting for this thread to finish servicing a timer (see
+ timer_delete()). */
+
+static void
+thread_cleanup (void *val)
+{
+ if (val != NULL)
+ {
+ struct thread_node *thread = val;
+
+ /* How did the signal thread get killed? */
+ assert (thread != &__timer_signal_thread_rclk);
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ thread->exists = 0;
+
+ /* We are no longer processing a timer event. */
+ thread->current_timer = 0;
+
+ if (list_isempty (&thread->timer_queue))
+ __timer_thread_dealloc (thread);
+ else
+ (void) __timer_thread_start (thread);
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ /* Unblock potentially blocked timer_delete(). */
+ pthread_cond_broadcast (&thread->cond);
+ }
+}
+
+
+/* Handle a timer which is supposed to go off now. */
+static void
+thread_expire_timer (struct thread_node *self, struct timer_node *timer)
+{
+ self->current_timer = timer; /* Lets timer_delete know timer is running. */
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL))
+ {
+ case SIGEV_NONE:
+ break;
+
+ case SIGEV_SIGNAL:
+#ifdef __NR_rt_sigqueueinfo
+ {
+ siginfo_t info;
+
+ /* First, clear the siginfo_t structure, so that we don't pass our
+ stack content to other tasks. */
+ memset (&info, 0, sizeof (siginfo_t));
+ /* We must pass the information about the data in a siginfo_t
+ value. */
+ info.si_signo = timer->event.sigev_signo;
+ info.si_code = SI_TIMER;
+ info.si_pid = timer->creator_pid;
+ info.si_uid = getuid ();
+ info.si_value = timer->event.sigev_value;
+
+ INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info);
+ }
+#else
+ if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
+ {
+ if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
+ abort ();
+ }
+#endif
+ break;
+
+ case SIGEV_THREAD:
+ timer->event.sigev_notify_function (timer->event.sigev_value);
+ break;
+
+ default:
+ assert (! "unknown event");
+ break;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ self->current_timer = 0;
+
+ pthread_cond_broadcast (&self->cond);
+}
+
+
+/* Thread function; executed by each timer thread. The job of this
+ function is to wait on the thread's timer queue and expire the
+ timers in chronological order as close to their scheduled time as
+ possible. */
+static void
+__attribute__ ((noreturn))
+thread_func (void *arg)
+{
+ struct thread_node *self = arg;
+
+ /* Register cleanup handler, in case rogue application terminates
+ this thread. (This cannot happen to __timer_signal_thread, which
+ doesn't invoke application callbacks). */
+
+ pthread_cleanup_push (thread_cleanup, self);
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ while (1)
+ {
+ struct list_links *first;
+ struct timer_node *timer = NULL;
+
+ /* While the timer queue is not empty, inspect the first node. */
+ first = list_first (&self->timer_queue);
+ if (first != list_null (&self->timer_queue))
+ {
+ struct timespec now;
+
+ timer = timer_links2ptr (first);
+
+ /* This assumes that the elements of the list of one thread
+ are all for the same clock. */
+ clock_gettime (timer->clock, &now);
+
+ while (1)
+ {
+ /* If the timer is due or overdue, remove it from the queue.
+ If it's a periodic timer, re-compute its new time and
+ requeue it. Either way, perform the timer expiry. */
+ if (timespec_compare (&now, &timer->expirytime) < 0)
+ break;
+
+ list_unlink_ip (first);
+
+ if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0
+ || timer->value.it_interval.tv_nsec != 0)
+ {
+ timer->overrun_count = 0;
+ timespec_add (&timer->expirytime, &timer->expirytime,
+ &timer->value.it_interval);
+ while (timespec_compare (&timer->expirytime, &now) < 0)
+ {
+ timespec_add (&timer->expirytime, &timer->expirytime,
+ &timer->value.it_interval);
+ if (timer->overrun_count < DELAYTIMER_MAX)
+ ++timer->overrun_count;
+ }
+ __timer_thread_queue_timer (self, timer);
+ }
+
+ thread_expire_timer (self, timer);
+
+ first = list_first (&self->timer_queue);
+ if (first == list_null (&self->timer_queue))
+ break;
+
+ timer = timer_links2ptr (first);
+ }
+ }
+
+ /* If the queue is not empty, wait until the expiry time of the
+ first node. Otherwise wait indefinitely. Insertions at the
+ head of the queue must wake up the thread by broadcasting
+ this condition variable. */
+ if (timer != NULL)
+ pthread_cond_timedwait (&self->cond, &__timer_mutex,
+ &timer->expirytime);
+ else
+ pthread_cond_wait (&self->cond, &__timer_mutex);
+ }
+ /* This macro will never be executed since the while loop loops
+ forever - but we have to add it for proper nesting. */
+ pthread_cleanup_pop (1);
+}
+
+
+/* Enqueue a timer in wakeup order in the thread's timer queue.
+ Returns 1 if the timer was inserted at the head of the queue,
+ causing the queue's next wakeup time to change. */
+
+int
+__timer_thread_queue_timer (struct thread_node *thread,
+ struct timer_node *insert)
+{
+ struct list_links *iter;
+ int athead = 1;
+
+ for (iter = list_first (&thread->timer_queue);
+ iter != list_null (&thread->timer_queue);
+ iter = list_next (iter))
+ {
+ struct timer_node *timer = timer_links2ptr (iter);
+
+ if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
+ break;
+ athead = 0;
+ }
+
+ list_insbefore (iter, &insert->links);
+ return athead;
+}
+
+
+/* Start a thread and associate it with the given thread node. Global
+ lock must be held by caller. */
+int
+__timer_thread_start (struct thread_node *thread)
+{
+ int retval = 1;
+
+ assert (!thread->exists);
+ thread->exists = 1;
+
+ if (pthread_create (&thread->id, &thread->attr,
+ (void *(*) (void *)) thread_func, thread) != 0)
+ {
+ thread->exists = 0;
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+void
+__timer_thread_wakeup (struct thread_node *thread)
+{
+ pthread_cond_broadcast (&thread->cond);
+}
+
+
+/* Compare two pthread_attr_t thread attributes for exact equality.
+ Returns 1 if they are equal, otherwise zero if they are not equal or
+ contain illegal values. This version is LinuxThreads-specific for
+ performance reason. One could use the access functions to get the
+ values of all the fields of the attribute structure. */
+static int
+thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
+{
+ return (left->__detachstate == right->__detachstate
+ && left->__schedpolicy == right->__schedpolicy
+ && left->__guardsize == right->__guardsize
+ && (left->__schedparam.sched_priority
+ == right->__schedparam.sched_priority)
+ && left->__inheritsched == right->__inheritsched
+ && left->__scope == right->__scope
+ && left->__stacksize == right->__stacksize
+ && left->__stackaddr_set == right->__stackaddr_set
+ && (left->__stackaddr_set
+ || left->__stackaddr == right->__stackaddr));
+}
+
+
+/* Search the list of active threads and find one which has matching
+ attributes. Global mutex lock must be held by caller. */
+struct thread_node *
+__timer_thread_find_matching (const pthread_attr_t *desired_attr,
+ clockid_t desired_clock_id)
+{
+ struct list_links *iter = list_first (&thread_active_list);
+
+ while (iter != list_null (&thread_active_list))
+ {
+ struct thread_node *candidate = thread_links2ptr (iter);
+
+ if (thread_attr_compare (desired_attr, &candidate->attr)
+ && desired_clock_id == candidate->clock_id)
+ return candidate;
+
+ iter = list_next (iter);
+ }
+
+ return NULL;
+}
+
+
+/* Grab a free timer structure from the global free list. The global
+ lock must be held by the caller. */
+struct timer_node *
+__timer_alloc (void)
+{
+ struct list_links *node = list_first (&timer_free_list);
+
+ if (node != list_null (&timer_free_list))
+ {
+ struct timer_node *timer = timer_links2ptr (node);
+ list_unlink_ip (node);
+ timer->inuse = TIMER_INUSE;
+ timer->refcount = 1;
+ return timer;
+ }
+
+ return NULL;
+}
+
+
+/* Return a timer structure to the global free list. The global lock
+ must be held by the caller. */
+void
+__timer_dealloc (struct timer_node *timer)
+{
+ assert (timer->refcount == 0);
+ timer->thread = NULL; /* Break association between timer and thread. */
+ timer->inuse = TIMER_FREE;
+ list_append (&timer_free_list, &timer->links);
+}
+
+
+/* Thread cancellation handler which unlocks a mutex. */
+void
+__timer_mutex_cancel_handler (void *arg)
+{
+ pthread_mutex_unlock (arg);
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c b/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c
new file mode 100644
index 000000000..da0908b0b
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c
@@ -0,0 +1,136 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */
+int
+timer_settime (timerid, flags, value, ovalue)
+ timer_t timerid;
+ int flags;
+ const struct itimerspec *value;
+ struct itimerspec *ovalue;
+{
+ struct timer_node *timer;
+ struct thread_node *thread = NULL;
+ struct timespec now;
+ int have_now = 0, need_wakeup = 0;
+ int retval = -1;
+
+ timer = timer_id2ptr (timerid);
+ if (timer == NULL)
+ {
+ __set_errno (EINVAL);
+ goto bail;
+ }
+
+ if (value->it_interval.tv_nsec < 0
+ || value->it_interval.tv_nsec >= 1000000000
+ || value->it_value.tv_nsec < 0
+ || value->it_value.tv_nsec >= 1000000000)
+ {
+ __set_errno (EINVAL);
+ goto bail;
+ }
+
+ /* Will need to know current time since this is a relative timer;
+ might as well make the system call outside of the lock now! */
+
+ if ((flags & TIMER_ABSTIME) == 0)
+ {
+ clock_gettime (timer->clock, &now);
+ have_now = 1;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
+
+ /* One final check of timer validity; this one is possible only
+ until we have the mutex, because it accesses the inuse flag. */
+
+ if (! timer_valid(timer))
+ {
+ __set_errno (EINVAL);
+ goto unlock_bail;
+ }
+
+ if (ovalue != NULL)
+ {
+ ovalue->it_interval = timer->value.it_interval;
+
+ if (timer->armed)
+ {
+ if (! have_now)
+ {
+ pthread_mutex_unlock (&__timer_mutex);
+ clock_gettime (timer->clock, &now);
+ have_now = 1;
+ pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
+ }
+
+ timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
+ }
+ else
+ {
+ ovalue->it_value.tv_sec = 0;
+ ovalue->it_value.tv_nsec = 0;
+ }
+ }
+
+ timer->value = *value;
+
+ list_unlink_ip (&timer->links);
+ timer->armed = 0;
+
+ thread = timer->thread;
+
+ /* A value of { 0, 0 } causes the timer to be stopped. */
+ if (value->it_value.tv_sec != 0
+ || __builtin_expect (value->it_value.tv_nsec != 0, 1))
+ {
+ if ((flags & TIMER_ABSTIME) != 0)
+ /* The user specified the expiration time. */
+ timer->expirytime = value->it_value;
+ else
+ timespec_add (&timer->expirytime, &now, &value->it_value);
+
+ /* Only need to wake up the thread if timer is inserted
+ at the head of the queue. */
+ if (thread != NULL)
+ need_wakeup = __timer_thread_queue_timer (thread, timer);
+ timer->armed = 1;
+ }
+
+ retval = 0;
+
+unlock_bail:
+ timer_delref (timer);
+ pthread_mutex_unlock (&__timer_mutex);
+
+bail:
+ if (thread != NULL && need_wakeup)
+ __timer_thread_wakeup (thread);
+
+ return retval;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/tls.h b/libpthread/linuxthreads/sysdeps/pthread/tls.h
deleted file mode 100644
index 2068f1e77..000000000
--- a/libpthread/linuxthreads/sysdeps/pthread/tls.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Definition for thread-local data handling. Generic version.
- Copyright (C) 2002 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 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-/* By default no TLS support is available. This is signaled by the
- absence of the symbol USE_TLS. */
-#undef USE_TLS
-
-
-/* An architecture-specific version of this file has to defined a
- number of symbols:
-
- TLS_TCB_AT_TP or TLS_DTV_AT_TP
-
- The presence of one of these symbols signals which variant of
- the TLS ABI is used. There are in the moment two variants
- available:
-
- * the thread pointer points to a thread control block
-
- * the thread pointer points to the dynamic thread vector
-
-
- TLS_TCB_SIZE
-
- This is the size of the thread control block structure. How
- this is actually defined depends on the ABI. The thread control
- block could be internal descriptor of the thread library or
- just a data structure which allows finding the DTV.
-
- TLS_INIT_TCB_SIZE
-
- Similarly, but this value is only used at startup and in the
- dynamic linker itself. There are no threads in use at that time.
-
-
- TLS_TCB_ALIGN
-
- Alignment requirements for the TCB structure.
-
- TLS_INIT_TCB_ALIGN
-
- Similarly, but for the structure used at startup time.
-
-
- INSTALL_DTV(tcb, init_dtv)
-
- This macro must install the given initial DTV into the thread control
- block TCB. The normal runtime functionality must then be able to
- use the value.
-
-
- TLS_INIT_TP(tcb, firstcall)
-
- This macro must initialize the thread pointer to enable normal TLS
- operation. The first parameter is a pointer to the thread control
- block. The second parameter specifies whether this is the first
- call for the TCB. ld.so calls this macro more than once.
-
-
- THREAD_DTV()
-
- This macro returns the address of the DTV of the current thread.
- This normally is done using the the thread register which points
- to the dtv or the TCB (from which the DTV can found).
- */
diff --git a/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c b/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c
new file mode 100644
index 000000000..0a679d9c6
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c
@@ -0,0 +1,113 @@
+/* Tests for POSIX timer implementation.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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
+ Lesser General Public License for more details.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+
+static void
+notify_func (union sigval sigval)
+{
+ puts ("notify_func");
+}
+
+
+static void
+signal_func (int sig)
+{
+ static const char text[] = "signal_func\n";
+ signal (sig, signal_func);
+ write (STDOUT_FILENO, text, sizeof text - 1);
+}
+
+static void
+intr_sleep (int sec)
+{
+ struct timespec ts;
+
+ ts.tv_sec = sec;
+ ts.tv_nsec = 0;
+
+ while (nanosleep (&ts, &ts) == -1 && errno == EINTR)
+ ;
+}
+
+#define ZSIGALRM 14
+
+
+int
+main (void)
+{
+ struct timespec ts;
+ timer_t timer_sig, timer_thr1, timer_thr2;
+ int retval;
+ struct sigevent sigev1 =
+ {
+ .sigev_notify = SIGEV_SIGNAL,
+ .sigev_signo = ZSIGALRM
+ };
+ struct sigevent sigev2;
+ struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } };
+ struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } };
+ struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } };
+ struct itimerspec old;
+
+ retval = clock_gettime (CLOCK_REALTIME, &ts);
+
+ sigev2.sigev_notify = SIGEV_THREAD;
+ sigev2.sigev_notify_function = notify_func;
+ sigev2.sigev_notify_attributes = NULL;
+
+ setvbuf (stdout, 0, _IOLBF, 0);
+
+ printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n",
+ retval, ts.tv_sec, ts.tv_nsec);
+
+ retval = clock_getres (CLOCK_REALTIME, &ts);
+
+ printf ("clock_getres returned %d, timespec = { %ld, %ld }\n",
+ retval, ts.tv_sec, ts.tv_nsec);
+
+ timer_create (CLOCK_REALTIME, &sigev1, &timer_sig);
+ timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1);
+ timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2);
+
+ timer_settime (timer_thr1, 0, &itimer2, &old);
+ timer_settime (timer_thr2, 0, &itimer3, &old);
+
+ signal (ZSIGALRM, signal_func);
+
+ timer_settime (timer_sig, 0, &itimer1, &old);
+
+ timer_delete (-1);
+
+ intr_sleep (3);
+
+ timer_delete (timer_sig);
+ timer_delete (timer_thr1);
+
+ intr_sleep (3);
+
+ timer_delete (timer_thr2);
+
+ return 0;
+}
diff --git a/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h b/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h
new file mode 100644
index 000000000..b957dedc9
--- /dev/null
+++ b/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h
@@ -0,0 +1,47 @@
+#ifndef _UCLIBC_GLUE_H
+#define _UCLIBC_GLUE_H 1
+
+#include <features.h>
+#include <sys/cdefs.h>
+#include <bits/uClibc_page.h>
+
+#ifdef IS_IN_libpthread
+#include <bits/kernel-features.h>
+
+#ifndef __GLIBC_HAVE_LONG_LONG
+# define __GLIBC_HAVE_LONG_LONG
+#endif
+
+#define __getpagesize getpagesize
+#define __sched_get_priority_max sched_get_priority_max
+#define __sched_get_priority_min sched_get_priority_min
+#define __sched_getscheduler sched_getscheduler
+#define __sched_setscheduler sched_setscheduler
+#define __sched_getparam sched_getparam
+#define __getpid getpid
+#define __gettimeofday gettimeofday
+#define __poll poll
+#define __sysctl sysctl
+#define __open open
+#define __read read
+#define __close close
+#define __on_exit on_exit
+#define __libc_current_sigrtmin_private __libc_current_sigrtmin
+#define __clone clone
+
+extern void *__libc_stack_end;
+extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
+
+#endif /* IS_IN_libpthread */
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+# define __uselocale(x) uselocale(x)
+#else
+# define __uselocale(x) ((void)0)
+#endif
+
+/* Use a funky version in a probably vein attempt at preventing gdb
+ * from dlopen()'ing glibc's libthread_db library... */
+#define VERSION __stringify(__UCLIBC_MAJOR__) "." __stringify(__UCLIBC_MINOR__) "." __stringify(__UCLIBC_SUBLEVEL__)
+
+#endif