# i586-linuxaout is mangled into i586-pc-linux-gnuaout
linux*ecoff* | linux*aout* | gnu*aout* | gnu*ecoff*)
;;
-gnu* | linux* | freebsd* | netbsd* | sysv4* | solaris2* | irix6* | opensolaris*-gnu*)
+gnu* | linux* | freebsd* | netbsd* | sysv4* | solaris2* | irix6* | kopensolaris*-gnu*)
# These systems (almost) always use the ELF format.
elf=yes
;;
###
if test -z "$enable_hacker_mode" && test x"$libc_config_ok" != xyes; then
case "$machine-$host_os" in
- *-linux* | *-gnu* | arm*-none* | powerpc-aix4.3.* | opensolaris*-gnu*)
+ *-linux* | *-gnu* | arm*-none* | powerpc-aix4.3.* | kopensolaris*-gnu*)
;;
*)
echo "*** The GNU C library is currently not available for this platform."
base_os=unix/sysv/hpux/$os ;;
aix4.3*)
base_os=unix/sysv/aix/aix4.3 ;;
-opensolaris*-gnu*)
- base_os=unix/sysv/solaris2/opensolaris-gnu ;;
+kopensolaris*-gnu*)
+ base_os=unix/sysv/solaris2/kopensolaris-gnu ;;
none)
base_os=standalone ;;
*)
# i586-linuxaout is mangled into i586-pc-linux-gnuaout
linux*ecoff* | linux*aout* | gnu*aout* | gnu*ecoff*)
;;
-gnu* | linux* | freebsd* | netbsd* | sysv4* | solaris2* | irix6* | opensolaris*-gnu* )
+gnu* | linux* | freebsd* | netbsd* | sysv4* | solaris2* | irix6* | kopensolaris*-gnu* )
# These systems (almost) always use the ELF format.
elf=yes
;;
###
if test -z "$enable_hacker_mode" && test x"$libc_config_ok" != xyes; then
case "$machine-$host_os" in
- *-linux* | *-gnu* | arm*-none* | powerpc-aix4.3.* | opensolaris*-gnu* )
+ *-linux* | *-gnu* | arm*-none* | powerpc-aix4.3.* | kopensolaris*-gnu* )
;;
*)
echo "*** The GNU C library is currently not available for this platform."
base_os=unix/sysv/hpux/$os ;;
aix4.3*)
base_os=unix/sysv/aix/aix4.3 ;;
-opensolaris*-gnu*)
- base_os=unix/sysv/solaris2/opensolaris-gnu ;;
+kopensolaris*-gnu*)
+ base_os=unix/sysv/solaris2/kopensolaris-gnu ;;
none)
base_os=standalone ;;
*)
--- /dev/null
+ifeq ($(subdir),nptl)
+headers += bits/synch.h thread.h sys/synch.h
+sysdep_routines += register-atfork unregister-atfork libc_pthread_init \
+ libc_multiple_threads fastlock
+libpthread-sysdep_routines += pt-fork fastlock clock_gettime \
+ sys_lwp_mutex_timedlock sys_lwp_mutex_trylock sys_lwp_mutex_unlock \
+ sys_lwp_mutex_register sys_lwp_cond_wait sys_lwp_cond_signal \
+ sys_lwp_cond_broadcast sys_lwp_sema_post sys_lwp_sema_trywait \
+ sys_lwp_sema_timedwait sys_lwp_create sys_lwp_wait sys_lwp_exit \
+ sys_lwp_kill sys_lwp_suspend sys_lwp_continue sys_write sys_lwp_sigmask
+libpthread-routines += sys_lwp_self
+
+# solaris threads/synch
+libpthread-routines += mutex_init mutex_lock mutex_trylock mutex_unlock \
+ mutex_destroy mutex_timedlock mutex_consistent cond_init cond_wait \
+ cond_timedwait cond_reltimedwait cond_signal cond_broadcast cond_destroy \
+ rwlock_init rwlock_destroy rw_rdlock rw_wrlock rw_unlock rw_tryrdlock \
+ rw_trywrlock rw_timedrdlock rw_timedwrlock sema_init sema_destroy \
+ sema_wait sema_trywait sema_post sema_timedwait
+endif
+
+ifeq ($(subdir),posix)
+CFLAGS-fork.c = -D_IO_MTSAFE_IO
+sysdep_routines += sys_lwp_self sys_forkx
+endif
+
+# Needed in both the signal and nptl subdir.
+CFLAGS-sigaction.c = -DWRAPPER_INCLUDE='<nptl/sigaction.c>'
--- /dev/null
+libc {
+ GLIBC_2.3.2 {
+ __register_atfork;
+ }
+ GLIBC_PRIVATE {
+ __libc_pthread_init;
+ __libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
+ __libc_allocate_rtsig_private;
+ __resp;
+ }
+}
+libpthread {
+ GLIBC_2.0 {
+ fork; __fork;
+ }
+ GLIBC_2.7 {
+ # c
+ cond_init; cond_destroy; cond_wait; cond_timedwait; cond_reltimedwait;
+ cond_signal; cond_broadcast;
+
+ # m
+ mutex_init; mutex_destroy; mutex_consistent; mutex_lock; mutex_trylock;
+ mutex_unlock;
+
+ # r
+ rwlock_init; rwlock_destroy; rw_rdlock; rw_wrlock; rw_unlock; rw_tryrdlock;
+ rw_trywrlock;
+
+ # s
+ sema_init; sema_destroy; sema_wait; sema_timedwait; sema_reltimedwait;
+ sema_post; sema_trywait;
+
+ # t
+ thr_create; thr_join; thr_exit; thr_suspend; thr_continue; thr_self;
+ thr_setconcurrency; thr_getconcurrency; thr_main; thr_kill; thr_yield;
+ thr_setprio; thr_getprio; thr_keycreate; thr_keycreate_once; thr_min_stack;
+ thr_setspecific; thr_sigsetmask; thr_stksegment; thr_main;
+ }
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <time.h>
+#include <stddef.h>
+
+static inline struct timespec * abstime_to_reltime (
+ const struct timespec *abstime, struct timespec *reltime)
+{
+ if(!abstime)
+ return NULL;
+
+ struct timespec now;
+ clock_gettime (CLOCK_REALTIME, &now);
+ reltime->tv_sec = abstime->tv_sec - now.tv_sec;
+ reltime->tv_nsec = abstime->tv_nsec - now.tv_nsec;
+ if (reltime->tv_nsec < 0)
+ {
+ reltime->tv_nsec += 1000000000;
+ --reltime->tv_sec;
+ }
+ return reltime;
+}
--- /dev/null
+/* XXX: we waste the lowest two realtime signals */
+#include <sysdeps/unix/sysv/linux/allocrtsig.c>
--- /dev/null
+/* libc-internal interface for mutex locks. OpenSolaris NPTL version.
+ Copyright (C) 1996-2003, 2005, 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_LIBC_LOCK_H
+#define _BITS_LIBC_LOCK_H 1
+
+#include <pthread.h>
+#define __need_NULL
+#include <stddef.h>
+#include <sys/synch.h>
+#include <synch_priv.h>
+
+
+#ifdef _LIBC
+# include <tls.h>
+# include <pthread-functions.h>
+#endif
+
+/* Mutex type. */
+#if defined _LIBC || defined _IO_MTSAFE_IO
+typedef pthread_mutex_t __libc_lock_t;
+typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
+typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
+# ifdef __USE_UNIX98
+typedef pthread_rwlock_t __libc_rwlock_t;
+# else
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+# endif
+#else
+typedef struct __libc_lock_opaque__ __libc_lock_t;
+typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+#endif
+
+/* Type for key to thread-specific data. */
+typedef pthread_key_t __libc_key_t;
+
+/* Define a lock variable NAME with storage class CLASS. The lock must be
+ initialized with __libc_lock_init before it can be used (or define it
+ with __libc_lock_define_initialized, below). Use `extern' for CLASS to
+ declare a lock defined in another module. In public structure
+ definitions you must use a pointer to the lock structure (i.e., NAME
+ begins with a `*'), because its storage size will not be known outside
+ of libc. */
+#define __libc_lock_define(CLASS,NAME) \
+ CLASS __libc_lock_t NAME;
+#define __libc_rwlock_define(CLASS,NAME) \
+ CLASS __libc_rwlock_t NAME;
+#define __libc_lock_define_recursive(CLASS,NAME) \
+ CLASS __libc_lock_recursive_t NAME;
+#define __rtld_lock_define_recursive(CLASS,NAME) \
+ CLASS __rtld_lock_recursive_t NAME;
+
+/* Define an initialized lock variable NAME with storage class CLASS. */
+
+#define __libc_lock_define_initialized(CLASS,NAME) \
+ CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER;
+#define __libc_rwlock_define_initialized(CLASS,NAME) \
+ CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER;
+
+/* Define an initialized recursive lock variable NAME with storage
+ class CLASS. */
+#define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+ CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
+#define _LIBC_LOCK_RECURSIVE_INITIALIZER \
+ {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
+
+#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
+ CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER;
+#define _RTLD_LOCK_RECURSIVE_INITIALIZER \
+ {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
+
+#define __rtld_lock_initialize(NAME) \
+ (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
+
+#define __rtld_lock_recursive_reinitialize(NAME) \
+ ({ \
+ unsigned int ___rtld_lock_count = (NAME).mutex.mutex_rcount; \
+ memset (&(NAME).mutex, 0, sizeof (pthread_mutex_t)); \
+ (NAME).mutex.mutex_type = LOCK_RECURSIVE; \
+ (NAME).mutex.mutex_flag = LOCK_INITED; \
+ (NAME).mutex.mutex_magic = MUTEX_MAGIC; \
+ ___rtld_lock_count; \
+ })
+
+/* If we check for a weakly referenced symbol and then perform a
+ normal jump to it te code generated for some platforms in case of
+ PIC is unnecessarily slow. What would happen is that the function
+ is first referenced as data and then it is called indirectly
+ through the PLT. We can make this a direct jump. */
+#ifdef __PIC__
+# define __libc_maybe_call(FUNC, ARGS, ELSE) \
+ (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
+ _fn != NULL ? (*_fn) ARGS : ELSE; }))
+#else
+# define __libc_maybe_call(FUNC, ARGS, ELSE) \
+ (FUNC != NULL ? FUNC ARGS : ELSE)
+#endif
+
+/* Call thread functions through the function pointer table. */
+#if defined SHARED && !defined NOT_IN_libc
+# define PTFAVAIL(NAME) __libc_pthread_functions_init
+# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+ (__libc_pthread_functions_init ? PTHFCT_CALL (ptr_##FUNC, ARGS) : ELSE)
+# define __libc_ptf_call_always(FUNC, ARGS) \
+ PTHFCT_CALL (ptr_##FUNC, ARGS)
+#else
+# define PTFAVAIL(NAME) (NAME != NULL)
+# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+ __libc_maybe_call (FUNC, ARGS, ELSE)
+# define __libc_ptf_call_always(FUNC, ARGS) \
+ FUNC ARGS
+#endif
+
+
+/* Initialize the named lock variable, leaving it in a consistent, unlocked
+ state. */
+#define __libc_lock_init(NAME) \
+ __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0)
+#define __libc_rwlock_init(NAME) \
+ __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0)
+
+/* Same as last but this time we initialize a recursive mutex. */
+#define __libc_lock_init_recursive(NAME) \
+ do { \
+ if (__pthread_mutex_init != NULL) \
+ { \
+ pthread_mutexattr_t __attr; \
+ __pthread_mutexattr_init (&__attr); \
+ __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \
+ __pthread_mutex_init (&(NAME).mutex, &__attr); \
+ __pthread_mutexattr_destroy (&__attr); \
+ } \
+ } while (0)
+
+#define __rtld_lock_init_recursive(NAME) \
+ do { \
+ if (__pthread_mutex_init != NULL) \
+ { \
+ pthread_mutexattr_t __attr; \
+ __pthread_mutexattr_init (&__attr); \
+ __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \
+ __pthread_mutex_init (&(NAME).mutex, &__attr); \
+ __pthread_mutexattr_destroy (&__attr); \
+ } \
+ } while (0)
+
+/* Finalize the named lock variable, which must be locked. It cannot be
+ used again until __libc_lock_init is called again on it. This must be
+ called on a lock variable before the containing storage is reused. */
+#define __libc_lock_fini(NAME) \
+ __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0)
+#define __libc_rwlock_fini(NAME) \
+ __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0)
+
+/* Finalize recursive named lock. */
+#define __libc_lock_fini_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_destroy, (&(NAME).mutex), 0)
+
+/* Lock the named lock variable. */
+#define __libc_lock_lock(NAME) \
+ __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0)
+#define __libc_rwlock_rdlock(NAME) \
+ __libc_ptf_call (__pthread_rwlock_rdlock, (&(NAME)), 0)
+#define __libc_rwlock_wrlock(NAME) \
+ __libc_ptf_call (__pthread_rwlock_wrlock, (&(NAME)), 0)
+
+/* Lock the recursive named lock variable. */
+#define __libc_lock_lock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+
+/* Try to lock the named lock variable. */
+#define __libc_lock_trylock(NAME) \
+ __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0)
+#define __libc_rwlock_tryrdlock(NAME) \
+ __libc_maybe_call (__pthread_rwlock_tryrdlock, (&(NAME)), 0)
+#define __libc_rwlock_trywrlock(NAME) \
+ __libc_maybe_call (__pthread_rwlock_trywrlock, (&(NAME)), 0)
+
+/* Try to lock the recursive named lock variable. */
+#define __libc_lock_trylock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0)
+
+#define __rtld_lock_trylock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0)
+
+/* Unlock the named lock variable. */
+#define __libc_lock_unlock(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
+#define __libc_rwlock_unlock(NAME) \
+ __libc_ptf_call (__pthread_rwlock_unlock, (&(NAME)), 0)
+
+/* Unlock the recursive named lock variable. */
+#define __libc_lock_unlock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
+
+#if defined _LIBC && defined SHARED
+# define __rtld_lock_default_lock_recursive(lock) \
+ ++((pthread_mutex_t *)(lock))->mutex_rcount;
+
+# define __rtld_lock_default_unlock_recursive(lock) \
+ --((pthread_mutex_t *)(lock))->mutex_rcount;
+
+# 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_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+
+# define __rtld_lock_unlock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
+#endif
+
+/* Define once control variable. */
+#if PTHREAD_ONCE_INIT == 0
+/* Special case for static variables where we can avoid the initialization
+ if it is zero. */
+# define __libc_once_define(CLASS, NAME) \
+ CLASS pthread_once_t NAME
+#else
+# define __libc_once_define(CLASS, NAME) \
+ CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT
+#endif
+
+/* Call handler iff the first call. */
+#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
+ do { \
+ if (PTFAVAIL (__pthread_once)) \
+ __libc_ptf_call_always (__pthread_once, (&(ONCE_CONTROL), \
+ INIT_FUNCTION)); \
+ else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \
+ INIT_FUNCTION (); \
+ (ONCE_CONTROL) |= 2; \
+ } \
+ } while (0)
+
+
+/* Note that for I/O cleanup handling we are using the old-style
+ cancel handling. It does not have to be integrated with C++ snce
+ no C++ code is called in the middle. The old-style handling is
+ faster and the support is not going away. */
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+ void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+ int execute);
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
+ void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+ int execute);
+
+/* Start critical region with cleanup. */
+#define __libc_cleanup_region_start(DOIT, FCT, ARG) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ int _avail; \
+ if (DOIT) { \
+ _avail = PTFAVAIL (_pthread_cleanup_push_defer); \
+ if (_avail) { \
+ __libc_ptf_call_always (_pthread_cleanup_push_defer, (&_buffer, FCT, \
+ ARG)); \
+ } else { \
+ _buffer.__routine = (FCT); \
+ _buffer.__arg = (ARG); \
+ } \
+ } else { \
+ _avail = 0; \
+ }
+
+/* End critical region with cleanup. */
+#define __libc_cleanup_region_end(DOIT) \
+ if (_avail) { \
+ __libc_ptf_call_always (_pthread_cleanup_pop_restore, (&_buffer, DOIT));\
+ } else if (DOIT) \
+ _buffer.__routine (_buffer.__arg); \
+ }
+
+/* Sometimes we have to exit the block in the middle. */
+#define __libc_cleanup_end(DOIT) \
+ if (_avail) { \
+ __libc_ptf_call_always (_pthread_cleanup_pop_restore, (&_buffer, DOIT));\
+ } else if (DOIT) \
+ _buffer.__routine (_buffer.__arg)
+
+
+/* Normal cleanup handling, based on C cleanup attribute. */
+__extern_inline void
+__libc_cleanup_routine (struct __pthread_cleanup_frame *f)
+{
+ if (f->__do_it)
+ f->__cancel_routine (f->__cancel_arg);
+}
+
+#define __libc_cleanup_push(fct, arg) \
+ do { \
+ struct __pthread_cleanup_frame __clframe \
+ __attribute__ ((__cleanup__ (__libc_cleanup_routine))) \
+ = { .__cancel_routine = (fct), .__cancel_arg = (arg), \
+ .__do_it = 1 };
+
+#define __libc_cleanup_pop(execute) \
+ __clframe.__do_it = (execute); \
+ } while (0)
+
+
+/* Create thread-specific key. */
+#define __libc_key_create(KEY, DESTRUCTOR) \
+ __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)
+
+/* Get thread-specific data. */
+#define __libc_getspecific(KEY) \
+ __libc_ptf_call (__pthread_getspecific, (KEY), NULL)
+
+/* Set thread-specific data. */
+#define __libc_setspecific(KEY, VALUE) \
+ __libc_ptf_call (__pthread_setspecific, (KEY, VALUE), 0)
+
+
+/* Register handlers to execute before and after `fork'. Note that the
+ last parameter is NULL. The handlers registered by the libc are
+ never removed so this is OK. */
+#define __libc_atfork(PREPARE, PARENT, CHILD) \
+ __register_atfork (PREPARE, PARENT, CHILD, NULL)
+extern int __register_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void),
+ void *__dso_handle);
+
+/* Functions that are used by this file and are internal to the GNU C
+ library. */
+
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+ __const pthread_mutexattr_t *__mutex_attr);
+
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr,
+ int __kind);
+
+#ifdef __USE_UNIX98
+extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock,
+ __const pthread_rwlockattr_t *__attr);
+
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+#endif
+
+extern int __pthread_key_create (pthread_key_t *__key,
+ void (*__destr_function) (void *));
+
+extern int __pthread_setspecific (pthread_key_t __key,
+ __const void *__pointer);
+
+extern void *__pthread_getspecific (pthread_key_t __key);
+
+extern int __pthread_once (pthread_once_t *__once_control,
+ void (*__init_routine) (void));
+
+extern int __pthread_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void));
+
+
+
+/* Make the pthread functions weak so that we can elide them from
+ single-threaded processes. */
+#ifndef __NO_WEAK_PTHREAD_ALIASES
+# ifdef weak_extern
+# if _LIBC
+# include <bp-sym.h>
+# else
+# define BP_SYM (sym) sym
+# endif
+weak_extern (BP_SYM (__pthread_mutex_init))
+weak_extern (BP_SYM (__pthread_mutex_destroy))
+weak_extern (BP_SYM (__pthread_mutex_lock))
+weak_extern (BP_SYM (__pthread_mutex_trylock))
+weak_extern (BP_SYM (__pthread_mutex_unlock))
+weak_extern (BP_SYM (__pthread_mutexattr_init))
+weak_extern (BP_SYM (__pthread_mutexattr_destroy))
+weak_extern (BP_SYM (__pthread_mutexattr_settype))
+weak_extern (BP_SYM (__pthread_rwlock_init))
+weak_extern (BP_SYM (__pthread_rwlock_destroy))
+weak_extern (BP_SYM (__pthread_rwlock_rdlock))
+weak_extern (BP_SYM (__pthread_rwlock_tryrdlock))
+weak_extern (BP_SYM (__pthread_rwlock_wrlock))
+weak_extern (BP_SYM (__pthread_rwlock_trywrlock))
+weak_extern (BP_SYM (__pthread_rwlock_unlock))
+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_defer))
+weak_extern (BP_SYM (_pthread_cleanup_pop_restore))
+weak_extern (BP_SYM (pthread_setcancelstate))
+# else
+# pragma weak __pthread_mutex_init
+# pragma weak __pthread_mutex_destroy
+# pragma weak __pthread_mutex_lock
+# pragma weak __pthread_mutex_trylock
+# pragma weak __pthread_mutex_unlock
+# pragma weak __pthread_mutexattr_init
+# pragma weak __pthread_mutexattr_destroy
+# pragma weak __pthread_mutexattr_settype
+# pragma weak __pthread_rwlock_init
+# pragma weak __pthread_rwlock_destroy
+# pragma weak __pthread_rwlock_rdlock
+# pragma weak __pthread_rwlock_tryrdlock
+# pragma weak __pthread_rwlock_wrlock
+# pragma weak __pthread_rwlock_trywrlock
+# pragma weak __pthread_rwlock_unlock
+# pragma weak __pthread_key_create
+# 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
+# pragma weak pthread_setcancelstate
+# endif
+#endif
+
+#endif /* bits/libc-lock.h */
--- /dev/null
+/* Copyright (C) 2002,2003,2004,2005,2006,2007,2008
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if !defined _BITS_TYPES_H && !defined _PTHREAD_H
+# error "Never include <bits/pthreadtypes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#define __need_schedparam
+#include <bits/sched.h>
+#include <stdint.h>
+#define __need_pthread_bits
+#include <bits/synch.h>
+
+#define __SIZEOF_PTHREAD_ATTR_T 76
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 16
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 80
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 56
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned int pthread_t;
+
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_slist
+{
+ struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is not exposed on purpose. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is not exposed on purpose. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+/* Extra attributes for the cleanup functions. */
+#define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+
+#endif /* bits/pthreadtypes.h */
--- /dev/null
+/* Copyright (C) 2002, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) -1)
+
+#define __need_semaphore_bits
+#include <bits/synch.h>
--- /dev/null
+/* Thread package specific definitions of stream lock type. Generic version.
+ Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_STDIO_LOCK_H
+#define _BITS_STDIO_LOCK_H 1
+
+#include <bits/libc-lock.h>
+
+__libc_lock_define_recursive (typedef, _IO_lock_t)
+
+/* We need recursive (counting) mutexes. */
+#ifdef _LIBC_LOCK_RECURSIVE_INITIALIZER
+# define _IO_lock_initializer _LIBC_LOCK_RECURSIVE_INITIALIZER
+#elif _IO_MTSAFE_IO
+ #error libio needs recursive mutexes for _IO_MTSAFE_IO
+#endif
+
+#define _IO_lock_init(_name) __libc_lock_init_recursive (_name)
+#define _IO_lock_fini(_name) __libc_lock_fini_recursive (_name)
+#define _IO_lock_lock(_name) __libc_lock_lock_recursive (_name)
+#define _IO_lock_trylock(_name) __libc_lock_trylock_recursive (_name)
+#define _IO_lock_unlock(_name) __libc_lock_unlock_recursive (_name)
+
+
+#define _IO_cleanup_region_start(_fct, _fp) \
+ __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp)
+#define _IO_cleanup_region_start_noarg(_fct) \
+ __libc_cleanup_region_start (1, _fct, NULL)
+#define _IO_cleanup_region_end(_doit) \
+ __libc_cleanup_region_end (_doit)
+
+#if defined _LIBC && !defined NOT_IN_libc
+# define _IO_acquire_lock(_fp) \
+ { \
+ _IO_FILE *_IO_acquire_lock_file = _fp; \
+ __libc_cleanup_region_start (1, (void (*) (void *)) _IO_acquire_lock_fct, &_IO_acquire_lock_file); \
+ _IO_flockfile (_IO_acquire_lock_file)
+
+# define _IO_acquire_lock_clear_flags2(_fp) \
+ { \
+ _IO_FILE *_IO_acquire_lock_file = _fp; \
+ __libc_cleanup_region_start (1, (void (*) (void *)) _IO_acquire_lock_clear_flags2_fct, &_IO_acquire_lock_file); \
+ _IO_flockfile (_IO_acquire_lock_file)
+
+# define _IO_release_lock(_fp) \
+ __libc_cleanup_region_end (1); \
+ }
+
+#endif
+
+#endif /* bits/stdio-lock.h */
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <bits/types.h>
+
+#if (defined __need_pthread_bits && !defined __pthread_bits_defined) || \
+ (defined __need_synch_bits && !defined __synch_bits_defined)
+
+# ifdef __need_pthread_bits
+typedef struct
+# else
+typedef struct _lwp_mutex
+# endif
+{
+ struct {
+ uint16_t flag1;
+ uint8_t flag2;
+ uint8_t ceiling;
+ union {
+ uint16_t bcptype;
+ struct {
+ uint8_t count_type1;
+ uint8_t count_type2;
+ } mtype_rcount;
+ } mbcp_type_un;
+ uint16_t magic;
+ } flags;
+ union {
+ struct {
+ uint8_t pad[8];
+ } lock64;
+ struct {
+ uint32_t ownerpid;
+ uint32_t lockword;
+ } lock32;
+ uint64_t owner64;
+ } lock;
+ uint64_t data;
+# ifdef __need_pthread_bits
+} pthread_mutex_t;
+# else
+} lwp_mutex_t;
+# endif
+
+# ifdef __need_pthread_bits
+typedef struct
+# else
+typedef struct _lwp_cond
+# endif
+{
+ struct {
+ uint8_t flag[4];
+ uint16_t type;
+ uint16_t magic;
+ } flags;
+ uint64_t data;
+# ifdef __need_pthread_bits
+} pthread_cond_t;
+# else
+} lwp_cond_t;
+# endif
+
+#endif /* defined __need_pthread_bits && !defined ... */
+
+#if (defined __need_pthread_bits && (defined __USE_UNIX98 || \
+ defined __USE_XOPEN2K) && !defined __pthread_bits_defined) || \
+ (defined __need_synch_bits && !defined __synch_bits_defined)
+
+# ifdef __need_pthread_bits
+typedef struct
+# else
+typedef struct _lwp_rwlock
+# endif
+{
+ int32_t readers;
+ uint16_t type;
+ uint16_t magic;
+# ifdef __need_pthread_bits
+ pthread_mutex_t mutex;
+ pthread_cond_t readercv;
+ pthread_cond_t writercv;
+# else
+ lwp_mutex_t mutex;
+ lwp_cond_t readercv;
+ lwp_cond_t writercv;
+# endif
+/* XXX: These are non-standard additions (see NOTES.opensolaris). */
+ uint64_t owner;
+ uint32_t ownerpid;
+ uint32_t pad;
+# ifdef __need_pthread_bits
+} pthread_rwlock_t;
+# else
+} lwp_rwlock_t;
+# endif
+
+#endif /* defined __need_pthread_bits && !defined ... */
+
+#if (defined __need_semaphore_bits && !defined __semaphore_bits_defined) || \
+ (defined __need_synch_bits && !defined __synch_bits_defined)
+
+#ifdef __need_semaphore_bits
+typedef struct
+#else
+typedef struct _lwp_sema
+#endif
+{
+ uint32_t count;
+ uint16_t type;
+ uint16_t magic;
+ uint8_t flags[8];
+ uint64_t data;
+#ifdef __need_semaphore_bits
+} sem_t;
+#else
+} lwp_sema_t;
+#endif
+
+#endif /* defined __need_semaphore_bits && !defined ... */
+
+#ifdef __need_pthread_bits
+# undef __need_pthread_bits
+# define __pthread_bits_defined
+#endif
+#ifdef __need_semaphore_bits
+# undef __need_semaphore_bits
+# define __semaphore_bits_defined
+#endif
+#ifdef __need_synch_bits
+# undef __need_synch_bits
+# define __synch_bits_defined
+#endif
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_cond_broadcast, cond_t *cv);
+
+
+int cond_broadcast (cond)
+ cond_t *cond;
+{
+ /* Don't bother entering the kernel if there are no waiters. */
+ if (cond->cond_waiters_kernel == 0)
+ return 0;
+
+ return INLINE_SYSCALL (lwp_cond_broadcast, 1, cond);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+
+int cond_destroy (cond)
+ cond_t *cond;
+{
+ memset (cond, 0, sizeof(cond_t));
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+
+int cond_init (cond, type, arg)
+ cond_t *cond;
+ int type;
+ void *arg;
+{
+ // TODO: check type
+
+ memset (cond, 0, sizeof(cond_t));
+ cond->cond_type = type;
+ cond->cond_magic = COND_MAGIC;
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_cond_wait, cond_t *cv, mutex_t *mp,
+ struct timespec *tsp, int check_park);
+
+struct _condvar_cleanup_buffer
+{
+ int oldtype;
+ cond_t *cond;
+ mutex_t *mutex;
+ int old_cond_waiters;
+ int old_mutex_rcount;
+};
+
+void
+__attribute__ ((visibility ("hidden")))
+__condvar_cleanup (void *arg)
+{
+ struct _condvar_cleanup_buffer *cbuffer =
+ (struct _condvar_cleanup_buffer *) arg;
+ mutex_t *mutex = cbuffer->mutex;
+
+ /* Note: we don't whether the mutex was unlocked by the kernel or not. */
+
+ /* The condition variable is no longer using the mutex. */
+ mutex->mutex_cond_waiters = cbuffer->old_cond_waiters;
+
+ int errval = 0;
+ while (1)
+ {
+ if (mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ (mutex->mutex_owner == (uintptr_t)THREAD_SELF))
+ {
+ /* The lock is held by us (we didn't get signaled). */
+ break;
+ }
+ else if (mutex->mutex_lockbyte == 0)
+ {
+ /* The mutex is unlocked. */
+ errval = mutex_lock (mutex);
+ break;
+ }
+ }
+
+ /* Restore the mutex_rcount. */
+ if (errval == 0)
+ mutex->mutex_rcount = cbuffer->old_mutex_rcount;
+}
+
+
+int
+__cond_reltimedwait_internal (cond, mutex, reltime, cancel)
+ cond_t *cond;
+ mutex_t *mutex;
+ struct timespec *reltime;
+ int cancel;
+{
+ struct _pthread_cleanup_buffer buffer;
+ struct _condvar_cleanup_buffer cbuffer;
+
+ /* Reject invalid timeouts. */
+ if (INVALID_TIMESPEC (reltime))
+ return EINVAL;
+
+ if ((mutex->mutex_type & LOCK_ERRORCHECK) &&
+ ((mutex->mutex_lockbyte != LOCKBYTE_SET ||
+ mutex->mutex_owner != (uintptr_t)THREAD_SELF ||
+ ((mutex->mutex_type & LOCK_SHARED) &&
+ mutex->mutex_ownerpid != THREAD_GETMEM (THREAD_SELF, pid)))))
+ {
+ /* Error checking: lock not held by this thread. */
+ return EPERM;
+ }
+ else if ((mutex->mutex_type & LOCK_RECURSIVE) &&
+ mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ mutex->mutex_owner == (uintptr_t)THREAD_SELF &&
+ mutex->mutex_rcount > 0)
+ {
+ /* Recursively held lock. XXX: Using recursive mutexes with condition
+ variables is undefined; we do what sun's libc does, namely fully
+ release the lock. */
+ cbuffer.old_mutex_rcount = mutex->mutex_rcount;
+ mutex->mutex_rcount = 0;
+ }
+
+ /* Mark the mutex as still in use. */
+ cbuffer.old_cond_waiters = mutex->mutex_cond_waiters;
+ if (cbuffer.old_cond_waiters == 0)
+ mutex->mutex_cond_waiters = 1;
+
+ /* Prepare structure passed to cancellation handler. */
+ cbuffer.cond = cond;
+ cbuffer.mutex = mutex;
+
+ if (cancel)
+ {
+ /* Before we block we enable cancellation. Therefore we have to
+ install a cancellation handler. */
+ __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer);
+
+ /* Enable asynchronous cancellation. Required by the standard. */
+ cbuffer.oldtype = __pthread_enable_asynccancel ();
+ }
+
+ int errval = INLINE_SYSCALL (lwp_cond_wait, 4, cond, mutex, reltime, 1);
+
+ /* The docs say to return 0 when interrupted. */
+ if (errval == EINTR)
+ errval = 0;
+
+ if (cancel)
+ {
+ /* Disable asynchronous cancellation. */
+ __pthread_disable_asynccancel (cbuffer.oldtype);
+
+ /* The cancellation handling is back to normal, remove the handler. */
+ __pthread_cleanup_pop (&buffer, 0);
+ }
+
+ /* Re-acquire the lock. The docs say we must always re-acquire so we don't
+ use __mutex_timedlock. Note that even if the above wait fails the kernel
+ always unlocks the mutex. */
+ int errval2 = mutex_lock (mutex);
+ if (errval2 == EINTR)
+ return 0;
+ else if (errval2 != 0 && errval2 != EOWNERDEAD)
+ return errval2;
+ if (errval == 0)
+ errval = errval2;
+
+ /* Restore the mutex_rcount. */
+ if (mutex->mutex_type & LOCK_RECURSIVE)
+ mutex->mutex_rcount = cbuffer.old_mutex_rcount;
+
+ /* The condition variable is no longer using the mutex. */
+ if (cbuffer.old_cond_waiters == 0)
+ mutex->mutex_cond_waiters = 0;
+
+ return errval;
+}
+
+
+int cond_reltimedwait (cond, mutex, reltime)
+ cond_t *cond;
+ mutex_t *mutex;
+ struct timespec *reltime;
+{
+ return __cond_reltimedwait_internal (cond, mutex, reltime, 1);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_cond_signal, cond_t *cv);
+
+
+int cond_signal (cond)
+ cond_t *cond;
+{
+ /* Don't bother entering the kernel if there are no waiters. */
+ if (cond->cond_waiters_kernel == 0)
+ return 0;
+
+ return INLINE_SYSCALL (lwp_cond_signal, 1, cond);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <abstime-to-reltime.h>
+
+
+int cond_timedwait (cond, mutex, abstime)
+ cond_t *cond;
+ mutex_t *mutex;
+ struct timespec *abstime;
+{
+ /* Reject invalid timeouts. */
+ if (INVALID_TIMESPEC (abstime))
+ return EINVAL;
+
+ struct timespec _reltime;
+ struct timespec *reltime = abstime_to_reltime (abstime, &_reltime);
+ return cond_reltimedwait (cond, mutex, reltime);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+
+int cond_wait (cond, mutex)
+ cond_t *cond;
+ mutex_t *mutex;
+{
+ return cond_reltimedwait (cond, mutex, NULL);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <pthreadP.h>
+#include <synch_priv.h>
+#include <sys/synch.h>
+#include <stdbool.h>
+#include <assert.h>
+
+int __mutex_lock_fast (mutex_t *mutex, bool try)
+{
+ if (mutex->mutex_lockword32 == LOCKWORD32_UNSET_NO_WAITERS)
+ {
+ /* The mutex is not held by anyone so try to grab it. */
+ if (mutex->mutex_type & LOCK_SHARED)
+ {
+ uint64_t new_lockword64 = LOCKWORD64_SET_NO_WAITERS |
+ (THREAD_GETMEM (THREAD_SELF, pid) << MUTEX_OWNERPID_SHIFT);
+ uint64_t old_lockword64 = atomic_compare_and_exchange_val_acq (
+ &mutex->mutex_lockword64, new_lockword64,
+ LOCKWORD64_UNSET_NO_WAITERS);
+ if (__builtin_expect (old_lockword64 ==
+ LOCKWORD64_UNSET_NO_WAITERS, 1))
+ {
+ mutex->mutex_owner = (uintptr_t)THREAD_SELF;
+ return 0;
+ }
+ }
+ else
+ {
+ uint32_t old_lockword32 = atomic_compare_and_exchange_val_acq (
+ &mutex->mutex_lockword32, LOCKWORD32_SET_NO_WAITERS,
+ LOCKWORD32_UNSET_NO_WAITERS);
+ if (__builtin_expect (old_lockword32 ==
+ LOCKWORD32_UNSET_NO_WAITERS, 1))
+ {
+ mutex->mutex_owner = (uintptr_t)THREAD_SELF;
+ return 0;
+ }
+ }
+ }
+ else if ((mutex->mutex_type & LOCK_RECURSIVE) &&
+ mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ mutex->mutex_owner == (uintptr_t)THREAD_SELF)
+ {
+ /* Recursively held lock. */
+ if (mutex->mutex_rcount == RECURSION_MAX)
+ return EAGAIN;
+ mutex->mutex_rcount++;
+ return 0;
+ }
+ else if ((mutex->mutex_type & LOCK_ERRORCHECK) &&
+ mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ (mutex->mutex_owner == (uintptr_t)THREAD_SELF))
+ {
+ /* Error checking: lock already held. */
+ return EDEADLK;
+ }
+ else if (try && mutex->mutex_lockbyte == LOCKBYTE_SET)
+ {
+ /* Tried to lock but lock was held. */
+ return EBUSY;
+ }
+
+ /* Need to use the slow code. */
+ return -1;
+}
+
+
+int __mutex_unlock_fast (mutex_t *mutex)
+{
+ if ((mutex->mutex_type & LOCK_RECURSIVE) &&
+ mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ mutex->mutex_owner == (uintptr_t)THREAD_SELF &&
+ mutex->mutex_rcount > 0)
+ {
+ /* Recursively held lock. */
+ --mutex->mutex_rcount;
+ return 0;
+ }
+ else if ((mutex->mutex_type & LOCK_ERRORCHECK) &&
+ ((mutex->mutex_lockbyte != LOCKBYTE_SET ||
+ ((mutex->mutex_type & LOCK_SHARED) &&
+ mutex->mutex_ownerpid != THREAD_GETMEM (THREAD_SELF, pid)) ||
+ mutex->mutex_owner != (uintptr_t)THREAD_SELF)))
+ {
+ /* error checking: lock not held by this thread */
+ return EPERM;
+ }
+ else if (mutex->mutex_lockword32 == LOCKWORD32_SET_NO_WAITERS)
+ {
+ /* We need to clear the owner before we fully unlock. Otherwise
+ we have a race condition where we might clear the owner after
+ another thread sets the lock word. If we fail to unlock here
+ we don't need to reset the owner as we're just going to unlock
+ in the kernel (which doesn't check this field anyhow). */
+ mutex->mutex_owner = (uintptr_t)NULL;
+
+ /* Nobody is waiting on the mutex so we can try to release it. */
+ if (mutex->mutex_type & LOCK_SHARED)
+ {
+ uint64_t test_lockword64 = LOCKWORD64_SET_NO_WAITERS |
+ (mutex->mutex_ownerpid << MUTEX_OWNERPID_SHIFT);
+ (THREAD_GETMEM (THREAD_SELF, pid) << MUTEX_OWNERPID_SHIFT);
+ uint64_t old_lockword64 = atomic_compare_and_exchange_val_acq (
+ &mutex->mutex_lockword64, LOCKWORD64_UNSET_NO_WAITERS,
+ test_lockword64);
+ if (__builtin_expect (old_lockword64 == test_lockword64, 1))
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ uint32_t old_lockword32 = atomic_compare_and_exchange_val_acq (
+ &mutex->mutex_lockword32, LOCKWORD32_UNSET_NO_WAITERS,
+ LOCKWORD32_SET_NO_WAITERS);
+ if (__builtin_expect (old_lockword32 ==
+ LOCKWORD32_SET_NO_WAITERS, 1))
+ {
+ return 0;
+ }
+ }
+ }
+
+ /* Need to use the slow code. */
+ return -1;
+}
--- /dev/null
+/* Copyright (C) 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <libio/libioP.h>
+#include <tls.h>
+#include "fork.h"
+#include <hp-timing.h>
+#include <ldsodefs.h>
+#include <bits/stdio-lock.h>
+#include <atomic.h>
+#include <inline-syscall.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_self, void);
+DECLARE_INLINE_SYSCALL (int64_t, forkx, int flags);
+
+
+unsigned long int *__fork_generation_pointer;
+
+
+
+/* The single linked list of all currently registered for handlers. */
+struct fork_handler *__fork_handlers;
+
+
+static void
+fresetlockfiles (void)
+{
+ _IO_ITER i;
+
+ for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+ _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
+}
+
+
+pid_t
+__libc_fork (void)
+{
+ pid_t pid;
+ struct used_handler
+ {
+ struct fork_handler *handler;
+ struct used_handler *next;
+ } *allp = NULL;
+
+ /* Run all the registered preparation handlers. In reverse order.
+ While doing this we build up a list of all the entries. */
+ struct fork_handler *runp;
+ while ((runp = __fork_handlers) != NULL)
+ {
+ unsigned int oldval = runp->refcntr;
+
+ if (oldval == 0)
+ /* This means some other thread removed the list just after
+ the pointer has been loaded. Try again. Either the list
+ is empty or we can retry it. */
+ continue;
+
+ /* Bump the reference counter. */
+ if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr,
+ oldval + 1, oldval))
+ /* The value changed, try again. */
+ continue;
+
+ /* We bumped the reference counter for the first entry in the
+ list. That means that none of the following entries will
+ just go away. The unloading code works in the order of the
+ list.
+
+ While executing the registered handlers we are building a
+ list of all the entries so that we can go backward later on. */
+ while (1)
+ {
+ /* Execute the handler if there is one. */
+ if (runp->prepare_handler != NULL)
+ runp->prepare_handler ();
+
+ /* Create a new element for the list. */
+ struct used_handler *newp
+ = (struct used_handler *) alloca (sizeof (*newp));
+ newp->handler = runp;
+ newp->next = allp;
+ allp = newp;
+
+ /* Advance to the next handler. */
+ runp = runp->next;
+ if (runp == NULL)
+ break;
+
+ /* Bump the reference counter for the next entry. */
+ atomic_increment (&runp->refcntr);
+ }
+
+ /* We are done. */
+ break;
+ }
+
+ _IO_list_lock ();
+
+ rval_t result;
+ result.rval64 = INLINE_SYSCALL (forkx, 1, 0);
+ if (result.rval64 == -1)
+ pid = (pid_t)-1;
+ else if (result.rval2 != 0)
+ pid = 0;
+ else
+ pid = (pid_t)result.rval1;
+
+ if (pid == 0)
+ {
+ struct pthread *self = THREAD_SELF;
+
+ if (__fork_generation_pointer != NULL)
+ *__fork_generation_pointer += 4;
+
+ /* Adjust the PID field for the new process. */
+ THREAD_SETMEM (self, pid, getpid());
+ int tid = INLINE_SYSCALL (lwp_self, 0);
+ THREAD_SETMEM (self, tid, tid);
+
+#if HP_TIMING_AVAIL
+ /* The CPU clock of the thread and process have to be set to zero. */
+ hp_timing_t now;
+ HP_TIMING_NOW (now);
+ THREAD_SETMEM (self, cpuclock_offset, now);
+ GL(dl_cpuclock_offset) = now;
+#endif
+
+ /* Reset the file list. These are recursive mutexes. */
+ fresetlockfiles ();
+
+ /* Reset locks in the I/O code. */
+ _IO_list_resetlock ();
+
+ /* Reset the lock the dynamic loader uses to protect its data. */
+ __rtld_lock_initialize (GL(dl_load_lock));
+
+ /* Run the handlers registered for the child. */
+ while (allp != NULL)
+ {
+ if (allp->handler->child_handler != NULL)
+ allp->handler->child_handler ();
+
+ /* Note that we do not have to wake any possible waiter.
+ This is the only thread in the new process. The count
+ may have been bumped up by other threads doing a fork.
+ We reset it to 1, to avoid waiting for non-existing
+ thread(s) to release the count. */
+ allp->handler->refcntr = 1;
+
+ /* XXX We could at this point look through the object pool
+ and mark all objects not on the __fork_handlers list as
+ unused. This is necessary in case the fork() happened
+ while another thread called dlclose() and that call had
+ to create a new list. */
+
+ allp = allp->next;
+ }
+
+ /* Initialize the fork lock. */
+ __libc_lock_init(__fork_lock);
+ }
+ else
+ {
+ /* We execute this even if the 'fork' call failed. */
+ _IO_list_unlock ();
+
+ /* Run the handlers registered for the parent. */
+ while (allp != NULL)
+ {
+ if (allp->handler->parent_handler != NULL)
+ allp->handler->parent_handler ();
+
+#if 0 // TODO
+ if (atomic_decrement_and_test (&allp->handler->refcntr)
+ && allp->handler->need_signal)
+ lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE);
+#endif
+
+ allp = allp->next;
+ }
+ }
+
+ return pid;
+}
+weak_alias (__libc_fork, __fork)
+libc_hidden_def (__fork)
+weak_alias (__libc_fork, fork)
--- /dev/null
+/* Copyright (C) 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <bits/libc-lock.h>
+
+/* The fork generation counter, defined in libpthread. */
+extern unsigned long int __fork_generation attribute_hidden;
+
+/* Pointer to the fork generation counter in the thread library. */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+/* Lock to protect allocation and deallocation of fork handlers. */
+__libc_lock_define (extern, __fork_lock attribute_hidden);
+
+/* Elements of the fork handler lists. */
+struct fork_handler
+{
+ struct fork_handler *next;
+ void (*prepare_handler) (void);
+ void (*parent_handler) (void);
+ void (*child_handler) (void);
+ void *dso_handle;
+ unsigned int refcntr;
+ int need_signal;
+};
+
+/* The single linked list of all currently registered for handlers. */
+extern struct fork_handler *__fork_handlers attribute_hidden;
+
+
+/* Function to call to unregister fork handlers. */
+extern void __unregister_atfork (void *dso_handle) attribute_hidden;
+#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
+
+
+/* C library side function to register new fork handlers. */
+extern int __register_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void),
+ void *dso_handle);
+libc_hidden_proto (__register_atfork)
--- /dev/null
+/* Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* We define a special synchronization primitive for AIO. POSIX
+ conditional variables would be ideal but the pthread_cond_*wait
+ operations do not return on EINTR. This is a requirement for
+ correct aio_suspend and lio_listio implementations. */
+
+#include <assert.h>
+#include <signal.h>
+#include <pthreadP.h>
+
+#undef DONT_NEED_GAI_MISC_COND
+
+
+#define gai_start_notify_thread __gai_start_notify_thread
+#define gai_create_helper_thread __gai_create_helper_thread
+
+extern inline void
+__gai_start_notify_thread (void)
+{
+ sigset_t ss;
+ sigemptyset (&ss);
+ sigprocmask (SIG_SETMASK, &ss, NULL);
+}
+
+extern inline int
+__gai_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
+ void *arg)
+{
+ pthread_attr_t attr;
+
+ /* Make sure the thread is created detached. */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+ /* The helper thread needs only very little resources. */
+ (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+
+ /* Block all signals in the helper thread. To do this thoroughly we
+ temporarily have to block all signals here. */
+ sigset_t ss;
+ sigset_t oss;
+ sigfillset (&ss);
+ sigprocmask (SIG_SETMASK, &ss, &oss);
+
+ int ret = pthread_create (threadp, &attr, tf, arg);
+
+ /* Restore the signal mask. */
+ sigprocmask (SIG_SETMASK, &oss, NULL);
+
+ (void) pthread_attr_destroy (&attr);
+ return ret;
+}
+
+#include <resolv/gai_misc.h>
--- /dev/null
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <tls.h>
+#include <ucontext.h>
+#include <sys/segments.h>
+#include <sys/stack.h>
+#include <sys/stack.h>
+#include <sys/regset.h>
+#include <sys/segments.h>
+#include <inline-syscall.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_create, ucontext_t *ucp, int flags,
+ pthread_t *new_lwp);
+DECLARE_INLINE_SYSCALL (int, lwp_continue, pthread_t lwpid);
+DECLARE_INLINE_SYSCALL (int, lwp_kill, pthread_t lwpid, int sig);
+
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+/* Pointer to the corresponding variable in libc. */
+int *__libc_multiple_threads_ptr attribute_hidden;
+#endif
+
+static int
+create_thread (struct pthread *pd, const struct pthread_attr *attr,
+ STACK_VARIABLES_PARMS)
+{
+#ifdef TLS_TCB_AT_TP
+ assert (pd->header.tcb != NULL);
+#endif
+
+ ucontext_t ctx = {0};
+
+ /* Clone the segment registers (except gs - see below). */
+ ucontext_t _ctx;
+ _ctx.uc_flags = UC_CPU;
+ if (getcontext(&_ctx) != 0)
+ return errno;
+ ctx.uc_mcontext.gregs[CS] = _ctx.uc_mcontext.gregs[CS];
+ ctx.uc_mcontext.gregs[DS] = _ctx.uc_mcontext.gregs[DS];
+ ctx.uc_mcontext.gregs[ES] = _ctx.uc_mcontext.gregs[ES];
+ ctx.uc_mcontext.gregs[FS] = _ctx.uc_mcontext.gregs[FS];
+ ctx.uc_mcontext.gregs[SS] = _ctx.uc_mcontext.gregs[SS];
+
+ /* Setup the stack (note that it grows down). */
+ uint32_t *stack_ptr = (uint32_t *)((uintptr_t)((uint32_t *)stackaddr - 1) &
+ ~(STACK_ALIGN - 1)) + 1;
+ *--stack_ptr = (uint32_t)pd; /* arg 1 */
+ *--stack_ptr = 0; /* return addr (thread_start never returns) */
+ ctx.uc_mcontext.gregs[UESP] = (greg_t)stack_ptr;
+ ctx.uc_mcontext.gregs[EBP] = (greg_t)(stack_ptr + 2); // TODO
+ ctx.uc_mcontext.gregs[EIP] = (greg_t)start_thread;
+ ctx.uc_flags |= UC_CPU;
+
+ /* This is a hack to get the kernel to set gs for us */
+ ctx.uc_mcontext.gregs[GS] = (greg_t)LWPGS_SEL;
+ ctx.uc_mcontext.gregs[ESP] = (greg_t)pd;
+
+ /* One more thread. We cannot have the thread do this itself, since it
+ might exist but not have been scheduled yet by the time we've returned
+ and need to check the value to behave correctly. We must do it before
+ creating the thread, in case it does get scheduled first and then
+ might mistakenly think it was the only thread. In the failure case,
+ we momentarily store a false value; this doesn't matter because there
+ is no kosher thing a signal handler interrupting us right here can do
+ that cares whether the thread count is correct. */
+ atomic_increment (&__nptl_nthreads);
+
+ /* We set the thread to be initially suspended so that we can set
+ scheduling magic. */
+ int lwp_flags = THR_SUSPENDED |
+ ((attr->flags & ATTR_FLAG_DAEMON) ? THR_DAEMON : 0) |
+ ((attr->flags & ATTR_FLAG_DETACHSTATE) ? THR_DETACHED : 0);
+ int errval = INLINE_SYSCALL (lwp_create, 3, &ctx, lwp_flags, &pd->tid);
+ if (errval == 0)
+ {
+ // TODO: set scheduling
+
+ if (errval == 0)
+ {
+ /* Resume thread if requested. */
+ if (!(attr->flags & ATTR_FLAG_SUSPENDED))
+ {
+ errval = INLINE_SYSCALL (lwp_continue, 1, pd->tid);
+ }
+ }
+
+ /* Kill the thread if we didn't succeed above. */
+ if (errval != 0)
+ INLINE_SYSCALL (lwp_kill, 2, pd->tid, SIGKILL);
+ }
+
+ if (errval != 0)
+ {
+ atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
+
+ /* Failed. If the thread is detached, remove the TCB here since
+ the caller cannot do this. The caller remembered the thread
+ as detached and cannot reverify that it is not since it must
+ not access the thread descriptor again. */
+ if (IS_DETACHED (pd))
+ __deallocate_stack (pd);
+ }
+
+ return errval;
+}
--- /dev/null
+/* Copyright (C) 2002, 2003, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include_next <pthreaddef.h>
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. SSE requires 16
+ bytes. */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here. */
+
+#include <inline-syscall.h>
+
+DECLARE_INLINE_SYSCALL (void, lwp_exit, void);
+
+/* While there is no such syscall. */
+#define __exit_thread_inline(val) \
+ INLINE_SYSCALL (lwp_exit, 0);
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYNCH_PRIV_H
+#define _SYNCH_PRIV_H
+
+/* mutex helper macros */
+#define mutex_type flags.mbcp_type_un.mtype_rcount.count_type1
+#define mutex_magic flags.magic
+#define mutex_flag flags.flag1
+#define mutex_ceiling flags.ceiling
+#define mutex_rcount flags.mbcp_type_un.mtype_rcount.count_type2
+#define mutex_owner data
+#define mutex_lockword32 lock.lock32.lockword
+#define mutex_lockword64 lock.owner64
+#define mutex_lockbyte lock.lock64.pad[7]
+#define mutex_waiters lock.lock64.pad[6]
+#define mutex_spinners lock.lock64.pad[5]
+#define mutex_cond_waiters mutex_spinners
+#define mutex_ownerpid lock.lock32.ownerpid
+#define RECURSION_MAX 255 /* UCHAR_MAX */
+#define LOCKBYTE_SET 0x01
+#define LOCKBYTE_UNSET 0x00
+#define LOCKWORD32_SET_NO_WAITERS 0x01000000
+#define LOCKWORD32_UNSET_NO_WAITERS 0x00000000
+#define LOCKWORD64_SET_NO_WAITERS 0x0100000000000000
+#define LOCKWORD64_UNSET_NO_WAITERS 0x0000000000000000
+#define MUTEX_OWNERPID_SHIFT 0
+
+/* condition variable helper macros */
+#define cond_type flags.type
+#define cond_magic flags.magic
+#define cond_clockid flags.flag[1]
+#define cond_waiters_user flags.flag[2]
+#define cond_waiters_kernel flags.flag[3]
+
+/* semaphore helper macros */
+#define sema_count count
+#define sema_type type
+#define sema_waiters flags[7]
+
+#endif /* _SYNCH_PRIV_H */
--- /dev/null
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2008
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+/* XXX: We don't support _NOERRNO or _ERRVAL varietites. */
+#undef PSEUDO_ERRNO
+#undef PSEUDO_SUBCALL_NOERRNO
+#undef PSEUDO_ERRVAL
+#undef PSEUDO_SUBCALL_NOERRNO
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \
+ jne L(pseudo_cancel); \
+ .type __##syscall_name##_nocancel,@function; \
+ .globl __##syscall_name##_nocancel; \
+ __##syscall_name##_nocancel: \
+ L(restart): \
+ DO_CALL (syscall_name, args); \
+ jnb 2f; \
+ cmpl $ERESTART, %eax; \
+ je L(restart); \
+ jmp SYSCALL_ERROR_LABEL; \
+2: ret; \
+ .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
+ L(pseudo_cancel): \
+ L(restart_cancel): \
+ CENABLE; \
+ movl %eax, %ecx; \
+ DO_CALL (syscall_name, args); \
+ jnb 3f; \
+ pushl %eax; cfi_adjust_cfa_offset (4); \
+ pushl %ecx; cfi_adjust_cfa_offset (4); \
+ CDISABLE; \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ popl %eax; cfi_adjust_cfa_offset (-4); \
+ cmpl $ERESTART, %eax; \
+ je L(restart_cancel); \
+ jmp SYSCALL_ERROR_LABEL; \
+3: \
+ pushl %eax; cfi_adjust_cfa_offset (4); \
+ pushl %ecx; cfi_adjust_cfa_offset (4); \
+ CDISABLE; \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ popl %eax; cfi_adjust_cfa_offset (-4); \
+ L(pseudo_end):
+
+/* XXX: This uses %edx, so subcalls that return 64-bit ints won't work. */
+# undef PSEUDO_SUBCALL
+# define PSEUDO_SUBCALL(name, syscall_name, subcall_name, args) \
+ .text; \
+ ENTRY (name) \
+ cmpl $0, %gs:MULTIPLE_THREADS_OFFSET; \
+ jne L(pseudo_cancel); \
+ .type __##subcall_name##_nocancel,@function; \
+ .globl __##subcall_name##_nocancel; \
+ __##subcall_name##_nocancel: \
+ movl 0(%esp), %ecx; \
+ movl %ecx, -4(%esp); \
+ movl $SYS_ify (SUB_##subcall_name), 0(%esp); \
+ addl $-4, %esp; cfi_adjust_cfa_offset (4); \
+ L(restart): \
+ DO_CALL (syscall_name, args); \
+ jnb 2f; \
+ cmpl $ERESTART, %eax; \
+ je L(restart); \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ movl %ecx, 0(%esp); \
+ jmp SYSCALL_ERROR_LABEL; \
+2: \
+ addl $4, %esp; \
+ movl %ecx, 0(%esp); \
+ ret; \
+ .size __##subcall_name##_nocancel,.-__##subcall_name##_nocancel; \
+ L(pseudo_cancel): \
+ CENABLE; \
+ movl %eax, %edx; \
+ movl 0(%esp), %ecx; \
+ movl %ecx, -4(%esp); \
+ movl $SYS_ify (SUB_##subcall_name), 0(%esp); \
+ addl $-4, %esp; cfi_adjust_cfa_offset (4); \
+ L(restart_cancel): \
+ DO_CALL (syscall_name, args); \
+ jnb 3f; \
+ pushl %eax; cfi_adjust_cfa_offset (4); \
+ pushl %edx; cfi_adjust_cfa_offset (4); \
+ CDISABLE; \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ popl %eax; cfi_adjust_cfa_offset (-4); \
+ cmpl $ERESTART, %eax; \
+ je L(restart_cancel); \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ movl %edx, 0(%esp); \
+ jmp SYSCALL_ERROR_LABEL; \
+3: \
+ pushl %eax; cfi_adjust_cfa_offset (4); \
+ pushl %edx; cfi_adjust_cfa_offset (4); \
+ CDISABLE; \
+ addl $4, %esp; cfi_adjust_cfa_offset (-4); \
+ popl %eax; cfi_adjust_cfa_offset (-4); \
+ addl $4, %esp; \
+ movl %ecx, 0(%esp); \
+ L(pseudo_end):
+
+
+# define SAVE_OLDTYPE movl %eax, %ecx;
+# ifdef IS_IN_libpthread
+# define CENABLE call __pthread_enable_asynccancel;
+# define CDISABLE call __pthread_disable_asynccancel
+# elif !defined NOT_IN_libc
+# define CENABLE call __libc_enable_asynccancel;
+# define CDISABLE call __libc_disable_asynccancel
+# elif defined IS_IN_librt
+# define CENABLE call __librt_enable_asynccancel;
+# define CDISABLE call __librt_disable_asynccancel
+# else
+# error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+# else
+# define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+#endif
--- /dev/null
+#include <sysdep.h>
+#include <tls.h>
+
+MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
+#ifdef NEED_DL_SYSINFO
+SYSINFO_OFFSET offsetof (tcbhead_t, sysinfo)
+#endif
+POINTER_GUARD offsetof (tcbhead_t, pointer_guard)
--- /dev/null
+/* Definition for thread-local data handling. OpenSolaris/i386 version.
+ Copyright (C) 2002, 2003, 2004, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+# include <dl-sysdep.h>
+
+/* __thread doesn't work for statically-linked executables. */
+#if !defined (SHARED)
+# undef HAVE___THREAD
+#endif
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <atomic.h>
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+
+/* Type of the TCB. */
+typedef struct
+{
+ void *tcb; /* Points to this structure. */
+ dtv_t *dtv; /* Vector of pointers to TLS data. */
+ void *self; /* Pointer to the thread descriptor. */
+ int multiple_threads;
+ uintptr_t sysinfo;
+ uintptr_t stack_guard;
+ uintptr_t pointer_guard;
+ int gscope_flag;
+} tcbhead_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif
+
+/* We require TLS support in the tools. */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available. */
+#define USE_TLS 1
+
+#ifndef __ASSEMBLER__
+/* Get system call information. */
+# include <sysdep.h>
+
+/* Get the thread descriptor definition. */
+# include <descr.h>
+
+/* This is the size of the initial TCB. */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB. */
+# define TLS_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* The TCB can have any size and the memory following the address the
+ thread pointer points to is unspecified. Allocate the TCB there. */
+# define TLS_TCB_AT_TP 1
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(descr, dtvp) \
+ ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ ({ struct pthread *__descr; \
+ THREAD_GETMEM (__descr, header.dtv); })
+
+/* Return the thread descriptor for the current thread.
+
+ The contained asm must *not* be marked volatile since otherwise
+ assignments like
+ pthread_descr self = thread_self();
+ do not get optimized away. */
+# define THREAD_SELF \
+ ({ struct pthread *__self; \
+ asm ("movl %%gs:%c1,%0" : "=r" (__self) \
+ : "i" (offsetof (struct pthread, header.self))); \
+ __self;})
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) \
+ ({ __typeof (descr->member) __value; \
+ if (sizeof (__value) == 1) \
+ asm volatile ("movb %%gs:%P2,%b0" \
+ : "=q" (__value) \
+ : "0" (0), "i" (offsetof (struct pthread, member))); \
+ else if (sizeof (__value) == 4) \
+ asm volatile ("movl %%gs:%P1,%0" \
+ : "=r" (__value) \
+ : "i" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (__value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%gs:%P1,%%eax\n\t" \
+ "movl %%gs:%P2,%%edx" \
+ : "=A" (__value) \
+ : "i" (offsetof (struct pthread, member)), \
+ "i" (offsetof (struct pthread, member) + 4)); \
+ } \
+ __value; })
+
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ ({ __typeof (descr->member[0]) __value; \
+ if (sizeof (__value) == 1) \
+ asm volatile ("movb %%gs:%P2(%3),%b0" \
+ : "=q" (__value) \
+ : "0" (0), "i" (offsetof (struct pthread, member[0])), \
+ "r" (idx)); \
+ else if (sizeof (__value) == 4) \
+ asm volatile ("movl %%gs:%P1(,%2,4),%0" \
+ : "=r" (__value) \
+ : "i" (offsetof (struct pthread, member[0])), \
+ "r" (idx)); \
+ else \
+ { \
+ if (sizeof (__value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \
+ "movl %%gs:4+%P1(,%2,8),%%edx" \
+ : "=&A" (__value) \
+ : "i" (offsetof (struct pthread, member[0])), \
+ "r" (idx)); \
+ } \
+ __value; })
+
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM(descr, member, value) \
+ ({ if (sizeof (descr->member) == 1) \
+ asm volatile ("movb %b0,%%gs:%P1" : \
+ : "iq" (value), \
+ "i" (offsetof (struct pthread, member))); \
+ else if (sizeof (descr->member) == 4) \
+ asm volatile ("movl %0,%%gs:%P1" : \
+ : "ir" (value), \
+ "i" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (descr->member) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%eax,%%gs:%P1\n\t" \
+ "movl %%edx,%%gs:%P2" : \
+ : "A" (value), \
+ "i" (offsetof (struct pthread, member)), \
+ "i" (offsetof (struct pthread, member) + 4)); \
+ }})
+
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ ({ if (sizeof (descr->member[0]) == 1) \
+ asm volatile ("movb %b0,%%gs:%P1(%2)" : \
+ : "iq" (value), \
+ "i" (offsetof (struct pthread, member)), \
+ "r" (idx)); \
+ else if (sizeof (descr->member[0]) == 4) \
+ asm volatile ("movl %0,%%gs:%P1(,%2,4)" : \
+ : "ir" (value), \
+ "i" (offsetof (struct pthread, member)), \
+ "r" (idx)); \
+ else \
+ { \
+ if (sizeof (descr->member[0]) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \
+ "movl %%edx,%%gs:4+%P1(,%2,8)" : \
+ : "A" (value), \
+ "i" (offsetof (struct pthread, member)), \
+ "r" (idx)); \
+ }})
+
+#define LOCK_PREFIX "lock;"
+
+/* Atomic compare and exchange on TLS, returning old value. */
+#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
+ ({ __typeof (descr->member) __ret; \
+ __typeof (oldval) __old = (oldval); \
+ if (sizeof (descr->member) == 4) \
+ asm volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3" \
+ : "=a" (__ret) \
+ : "0" (__old), "r" (newval), \
+ "i" (offsetof (struct pthread, member))); \
+ else \
+ /* Not necessary for other sizes in the moment. */ \
+ abort (); \
+ __ret; })
+
+
+/* Atomic set bit. */
+#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
+ (void) ({ if (sizeof ((descr)->member) == 4) \
+ asm volatile (LOCK_PREFIX "orl %1, %%gs:%P0" \
+ :: "i" (offsetof (struct pthread, member)), \
+ "ir" (1 << (bit))); \
+ else \
+ /* Not necessary for other sizes in the moment. */ \
+ abort (); })
+
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) \
+ ({ struct pthread *__descr; \
+ THREAD_SETMEM (__descr, header.dtv, (dtv)); })
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(descr) \
+ (((tcbhead_t *) (descr))->dtv)
+
+# ifdef __PIC__
+# define TLS_EBX_ARG "r"
+# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+# else
+# define TLS_EBX_ARG "b"
+# define TLS_LOAD_EBX
+# endif
+
+# if defined NEED_DL_SYSINFO
+# define INIT_SYSINFO \
+ head->sysinfo = GLRO(dl_sysinfo)
+# else
+# define INIT_SYSINFO
+# endif
+
+/* Code to initially initialize the thread pointer. This might need
+ special attention since 'errno' is not yet available and if the
+ operation can cause a failure 'errno' must not be touched. */
+
+/* solaris2 has lwp_private in order to set the thread data */
+# include <sys/lwp.h>
+# include <inline-syscall.h>
+
+# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
+ ({ \
+ DECLARE_INLINE_SYSCALL (int, lwp_private, int cmd, int which, \
+ uintptr_t base); \
+ (INLINE_SYSCALL (lwp_private, 3, _LWP_SETPRIVATE, _LWP_GSBASE, \
+ (uintptr_t)descr) == -1) \
+ ? "lwp_private failed when setting up thread-local storage\n" : NULL; \
+ })
+
+/* The value of this macro is null if successful, or an error string. */
+
+# define TLS_INIT_TP(descr, secondcall) \
+ ({ \
+ void *_descr = (descr); \
+ tcbhead_t *head = _descr; \
+ \
+ head->tcb = _descr; \
+ /* For now the thread descriptor is at the same address. */ \
+ head->self = _descr; \
+ \
+ INIT_SYSINFO; \
+ TLS_SETUP_GS_SEGMENT (_descr, secondcall); \
+ })
+
+/* Set the stack guard field in TCB head. */
+# define THREAD_SET_STACK_GUARD(value) \
+ THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
+# define THREAD_COPY_STACK_GUARD(descr) \
+ ((descr)->header.stack_guard \
+ = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
+
+/* Set the pointer guard field in the TCB head. */
+# define THREAD_SET_POINTER_GUARD(value) \
+ THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
+# define THREAD_COPY_POINTER_GUARD(descr) \
+ ((descr)->header.pointer_guard \
+ = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
+
+/* Get and set the global scope generation counter in the TCB head. */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED 1
+#define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res; \
+ asm volatile ("xchgl %0, %%gs:%P1" \
+ : "=r" (__res) \
+ : "i" (offsetof (struct pthread, header.gscope_flag)), \
+ "0" (THREAD_GSCOPE_FLAG_UNUSED)); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+ THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
+#define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+# endif /* __ASSEMBLER__ */
+
+#endif /* _TLS_H */
--- /dev/null
+/* Copyright (C) 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _INTERNALTYPES_H
+#define _INTERNALTYPES_H 1
+
+#include <stdint.h>
+#include <time.h>
+#include <stdbool.h>
+
+
+struct pthread_attr
+{
+ /* Scheduler parameters and priority. */
+ struct sched_param schedparam;
+ int schedpolicy;
+ /* Various flags like detachstate, scope, etc. */
+ int flags;
+ /* Size of guard area. */
+ size_t guardsize;
+ /* Stack handling. */
+ void *stackaddr;
+ size_t stacksize;
+ /* Affinity map. */
+ cpu_set_t *cpuset;
+ size_t cpusetsize;
+};
+
+#define ATTR_FLAG_DETACHSTATE 0x0001
+#define ATTR_FLAG_NOTINHERITSCHED 0x0002
+#define ATTR_FLAG_SCOPEPROCESS 0x0004
+#define ATTR_FLAG_STACKADDR 0x0008
+#define ATTR_FLAG_OLDATTR 0x0010
+#define ATTR_FLAG_SCHED_SET 0x0020
+#define ATTR_FLAG_POLICY_SET 0x0040
+#define ATTR_FLAG_DAEMON 0x0080
+#define ATTR_FLAG_SUSPENDED 0x0100
+
+
+/* Mutex attribute data structure. */
+struct pthread_mutexattr
+{
+ /* Identifier for the kind of mutex.
+
+ Bit 31 is set if the mutex is to be shared between processes.
+
+ Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
+ the type of the mutex. */
+ int mutexkind;
+};
+
+
+/* Conditional variable attribute data structure. */
+struct pthread_condattr
+{
+ /* Combination of values:
+
+ Bit 0 : flag whether coditional variable will be shareable between
+ processes.
+
+ Bit 1-7: clock ID. */
+ int value;
+};
+
+
+/* The __NWAITERS field is used as a counter and to house the number
+ of bits for other purposes. COND_CLOCK_BITS is the number
+ of bits needed to represent the ID of the clock. COND_NWAITERS_SHIFT
+ is the number of bits reserved for other purposes like the clock. */
+#define COND_CLOCK_BITS 1
+#define COND_NWAITERS_SHIFT 1
+
+
+/* Read-write lock variable attribute data structure. */
+struct pthread_rwlockattr
+{
+ int lockkind;
+ int pshared;
+};
+
+#define BARRIER_EXITING 0x01
+
+/* Barrier data structure. */
+struct pthread_barrier
+{
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned int curr_event;
+ unsigned int left;
+ unsigned int init_count;
+ unsigned int flag;
+};
+
+
+/* Barrier variable attribute data structure. */
+struct pthread_barrierattr
+{
+ int pshared;
+};
+
+
+/* Thread-local data handling. */
+struct pthread_key_struct
+{
+ /* Sequence numbers. Even numbers indicated vacant entries. Note
+ that zero is even. We use uintptr_t to not require padding on
+ 32- and 64-bit machines. On 64-bit machines it helps to avoid
+ wrapping, too. */
+ uintptr_t seq;
+
+ /* Destructor for the data. */
+ void (*destr) (void *);
+};
+
+/* Check whether an entry is unused. */
+#define KEY_UNUSED(p) (((p) & 1) == 0)
+/* Check whether a key is usable. We cannot reuse an allocated key if
+ the sequence counter would overflow after the next destroy call.
+ This would mean that we potentially free memory for a key with the
+ same sequence. This is *very* unlikely to happen, A program would
+ have to create and destroy a key 2^31 times (on 32-bit platforms,
+ on 64-bit platforms that would be 2^63). If it should happen we
+ simply don't use this specific key anymore. */
+#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2)))
+
+
+/* Handling of read-write lock data. */
+// XXX For now there is only one flag. Maybe more in future.
+//#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0)
+
+
+/* Compatibility type for old conditional variable interfaces. */
+typedef struct
+{
+ pthread_cond_t *cond;
+} pthread_cond_2_0_t;
+
+#endif /* internaltypes.h */
--- /dev/null
+#include <lowlevellock.c>
--- /dev/null
+#include <nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c>
--- /dev/null
+#include <nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c>
--- /dev/null
+/* See lowlevellock.h */
--- /dev/null
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <stddef.h>
+#include <inline-syscall.h>
+#include <pthread.h>
+
+#define lll_define(class, futex) \
+ class pthread_mutex_t futex
+
+#define LLL_LOCK_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
+#define lll_define_initialized(class, futex) \
+ class pthread_mutex_t futex = PTHREAD_MUTEX_INITIALIZER
+
+#define lll_init(futex) \
+ __pthread_mutex_init (&(futex), NULL)
+
+#define lll_lock(futex, private) \
+ __pthread_mutex_lock (&(futex))
+
+#define lll_trylock(futex) \
+ __pthread_mutex_trylock (&(futex))
+
+#define lll_unlock(futex, private) \
+ __pthread_mutex_unlock (&(futex))
+
+DECLARE_INLINE_SYSCALL (int, lwp_wait, pthread_t tid, pthread_t *departed);
+
+/* XXX: we really shouldn't assume the existence of result */
+#define lll_wait_tid(tid) \
+ do { \
+ result = INLINE_SYSCALL (lwp_wait, 2, (tid), NULL); \
+ } while (result == EINTR);
+
+DECLARE_INLINE_SYSCALL (int, lwp_kill, pthread_t tid, int sig);
+
+#define lll_tryjoin(tid) \
+ (INLINE_SYSCALL (lwp_kill, 2, (tid), 0) != ESRCH)
+
+#endif /* _LOWLEVELLOCK_H */
--- /dev/null
+/* Unimplemented */
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+
+int mutex_consistent (mutex)
+ mutex_t *mutex;
+{
+ if ((mutex->mutex_type & LOCK_ROBUST) == 0 ||
+ (mutex->mutex_flag & LOCK_INITED) == 0 ||
+ (mutex->mutex_flag & (LOCK_OWNERDEAD | LOCK_UNMAPPED)) == 0)
+ return EINVAL;
+
+ mutex->mutex_flag &= ~(LOCK_OWNERDEAD | LOCK_UNMAPPED);
+
+ /* The lock cannot be recursively held since it was just reclaimed. */
+ mutex->mutex_rcount = 0;
+
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+#include <synch_priv.h>
+
+
+int mutex_destroy (mutex)
+ mutex_t *mutex;
+{
+ if (mutex->mutex_type & LOCK_ROBUST)
+ memset (mutex, 0, sizeof(mutex_t));
+ else
+ mutex->mutex_magic = -1;
+
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_mutex_register, mutex_t *lp);
+
+
+int mutex_init (mutex, type, arg)
+ mutex_t *mutex;
+ int type;
+ void * arg;
+{
+ // TODO: check type
+
+ if (type & LOCK_ROBUST)
+ {
+ if ((mutex->mutex_type & LOCK_INITED))
+ return EBUSY;
+ }
+ else
+ {
+ memset (mutex, 0, sizeof(mutex_t));
+ }
+ mutex->mutex_type = type;
+ mutex->mutex_flag = LOCK_INITED;
+ mutex->mutex_magic = MUTEX_MAGIC;
+ mutex->mutex_ceiling = (int)arg;
+ mutex->mutex_cond_waiters = 0;
+
+ /* Register robust shared lock. */
+ if ((type & (LOCK_ROBUST | LOCK_SHARED)) == (LOCK_ROBUST | LOCK_SHARED))
+ {
+ int errval = INLINE_SYSCALL (lwp_mutex_register, 1, mutex);
+ if (errval != 0)
+ return errval;
+ }
+
+ return 0;
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <pthreadP.h>
+#include <synch.h>
+
+int mutex_lock (mutex)
+ mutex_t *mutex;
+{
+ return __mutex_timedlock (mutex, NULL);
+}
--- /dev/null
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <inline-syscall.h>
+#include <pthreadP.h>
+#include <synch.h>
+#include <errno.h>
+#include <time.h>
+#include <synch_priv.h>
+#include <abstime-to-reltime.h>
+
+DECLARE_INLINE_SYSCALL (int, lwp_mutex_timedlock, mutex_t *lp,
+ struct timespec *tsp);
+
+extern int __mutex_lock_fast (mutex_t *mutex, bool try);
+
+
+int __mutex_timedlock (mutex, abstime)
+ mutex_t *mutex;
+ const struct timespec *abstime;
+{
+ /* Handle inconsistent robust mutexes. */
+ if ((mutex->mutex_type & LOCK_ROBUST) &&
+ (mutex->mutex_flag & LOCK_NOTRECOVERABLE))
+ return ENOTRECOVERABLE;
+
+ /* Always hit the kernel for priority inherit locks. */
+ if ((mutex->mutex_type & LOCK_PRIO_INHERIT) == 0)
+ {
+ int res = __mutex_lock_fast (mutex, false);
+ if(res >= 0)
+ return res;
+ }
+ else
+ {
+ /* Except when we already hold a recursive lock. */
+ if ((mutex->mutex_type & LOCK_RECURSIVE) &&
+ mutex->mutex_lockbyte == LOCKBYTE_SET &&
+ ((mutex->mutex_type & LOCK_SHARED) == 0 ||
+ mutex->mutex_ownerpid == THREAD_GETMEM (THREAD_SELF, pid)) &&
+ mutex->mutex_owner == (uintptr_t)THREAD_SELF)
+ {
+ /* XXX: Solaris mutexes have no overflow check and don't know about
+ EAGAIN; in practice overflow will not occur so we don't care. */
+ if (mutex->mutex_rcount == RECURSION_MAX)
+ return EAGAIN;
+ ++mutex->mutex_rcount;
+ return 0;
+ }
+ }
+
+ /* Reject invalid timeouts. */
+ if (INVALID_TIMESPEC (abstime))
+ return EINVAL;
+
+ struct timespec _reltime;
+ struct timespec *reltime = abstime_to_reltime (abstime, &_reltime);
+ if (reltime && reltime->tv_sec < 0)
+ return ETIME;
+
+ int errval;
+ do
+ errval = INLINE_SYSCALL (lwp_mutex_timedlock, 2, mutex, reltime);
+ while (errval == EINTR);
+
+ /* The kernel sets EDEADLK for priority inherit mutexes. */
+ if (errval == EDEADLK && (mutex->mutex_type & LOCK_PRIO_INHERIT) &&
+ (mutex->mutex_type & LOCK_ERRORCHECK) == 0)
+ {
+ /* We aren't an error checking mutex so we need to block. */
+ INTERNAL_SYSCALL_DECL (err);
+ if (abstime)
+ {
+ int result = INTERNAL_SYSCALL (nanosleep, err, 2, reltime, NULL);
+