diff options
| author | Mike Frysinger <vapier@gentoo.org> | 2006-01-31 05:05:15 +0000 | 
|---|---|---|
| committer | Mike Frysinger <vapier@gentoo.org> | 2006-01-31 05:05:15 +0000 | 
| commit | cccc549ced940c85039c8ce263c8bb571f244afd (patch) | |
| tree | ef77a870db7211ad6f511867fc56ee1a1a8b4c18 /libpthread/linuxthreads/sysdeps/pthread | |
| parent | e73b1211737842732951f9b9049294ef732e1ef0 (diff) | |
| download | uClibc-alpine-cccc549ced940c85039c8ce263c8bb571f244afd.tar.bz2 uClibc-alpine-cccc549ced940c85039c8ce263c8bb571f244afd.tar.xz | |
initial import of latest linuxthreads
Diffstat (limited to 'libpthread/linuxthreads/sysdeps/pthread')
41 files changed, 3868 insertions, 0 deletions
| diff --git a/libpthread/linuxthreads/sysdeps/pthread/.cvsignore b/libpthread/linuxthreads/sysdeps/pthread/.cvsignore new file mode 100644 index 000000000..7ee8f5969 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/.cvsignore @@ -0,0 +1,2 @@ +.cvsignore +*.os diff --git a/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries b/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries new file mode 100644 index 000000000..c93808acb --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries @@ -0,0 +1,27 @@ +D/bits//// +/Makefile/1.7/Tue Nov 15 14:20:47 2005// +/Subdirs/1.1/Tue Nov 15 14:20:47 2005// +/errno-loc.c/1.4/Tue Nov 15 14:20:47 2005// +/flockfile.c/1.2/Tue Nov 15 14:20:47 2005// +/ftrylockfile.c/1.1/Tue Nov 15 14:20:47 2005// +/funlockfile.c/1.1/Tue Nov 15 14:20:47 2005// +/getcpuclockid.c/1.6/Tue Nov 15 14:20:47 2005// +/herrno-loc.c/1.3/Tue Nov 15 14:20:47 2005// +/list.h/1.2/Tue Nov 15 14:20:47 2005// +/malloc-machine.h/1.2/Tue Nov 15 14:20:47 2005// +/posix-timer.h/1.10/Tue Nov 15 14:20:47 2005// +/pt-initfini.c/1.4/Tue Nov 15 14:20:47 2005// +/pthread-functions.h/1.4/Tue Nov 15 14:20:47 2005// +/pthread.h/1.42/Tue Nov 15 14:20:47 2005// +/ptlongjmp.c/1.1/Tue Nov 15 14:20:47 2005// +/res-state.c/1.4/Tue Nov 15 14:20:47 2005// +/semaphore.h/1.1/Tue Nov 15 14:20:47 2005// +/tcb-offsets.h/1.1/Tue Nov 15 14:20:47 2005// +/timer_create.c/1.11/Tue Nov 15 14:20:47 2005// +/timer_delete.c/1.5/Tue Nov 15 14:20:47 2005// +/timer_getoverr.c/1.6/Tue Nov 15 14:20:47 2005// +/timer_gettime.c/1.5/Tue Nov 15 14:20:47 2005// +/timer_routines.c/1.24/Tue Nov 15 14:20:47 2005// +/timer_settime.c/1.5/Tue Nov 15 14:20:47 2005// +/tst-timer.c/1.5/Tue Nov 15 14:20:47 2005// +/sigaction.c/1.2/Thu Dec 29 06:43:12 2005// diff --git a/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries.Log b/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries.Log new file mode 100644 index 000000000..6f4aa299a --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/CVS/Entries.Log @@ -0,0 +1,4 @@ +A D/cmpxchg//// +A D/no-cmpxchg//// +R D/no-cmpxchg//// +R D/cmpxchg//// diff --git a/libpthread/linuxthreads/sysdeps/pthread/CVS/Repository b/libpthread/linuxthreads/sysdeps/pthread/CVS/Repository new file mode 100644 index 000000000..1203c7c61 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/CVS/Repository @@ -0,0 +1 @@ +ports/linuxthreads/sysdeps/pthread diff --git a/libpthread/linuxthreads/sysdeps/pthread/CVS/Root b/libpthread/linuxthreads/sysdeps/pthread/CVS/Root new file mode 100644 index 000000000..ca45c5d4d --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/CVS/Root @@ -0,0 +1 @@ +:pserver:anoncvs@sources.redhat.com:/cvs/glibc diff --git a/libpthread/linuxthreads/sysdeps/pthread/Subdirs b/libpthread/linuxthreads/sysdeps/pthread/Subdirs new file mode 100644 index 000000000..2c5649784 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/Subdirs @@ -0,0 +1 @@ +linuxthreads_db diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Entries b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Entries new file mode 100644 index 000000000..a90faa843 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Entries @@ -0,0 +1,6 @@ +/initspin.h/1.3/Tue Nov 15 14:20:47 2005// +/pthreadtypes.h/1.12/Tue Nov 15 15:32:00 2005// +/typesizes.h/1.2/Tue Nov 15 14:20:47 2005// +/libc-tsd.h/1.9/Tue Nov 29 20:26:59 2005// +/libc-lock.h/1.33/Fri Jan 20 14:26:50 2006// +D diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Repository b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Repository new file mode 100644 index 000000000..8eabf3c06 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Repository @@ -0,0 +1 @@ +ports/linuxthreads/sysdeps/pthread/bits diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Root b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Root new file mode 100644 index 000000000..ca45c5d4d --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/CVS/Root @@ -0,0 +1 @@ +:pserver:anoncvs@sources.redhat.com:/cvs/glibc diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h b/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h new file mode 100644 index 000000000..a19ec077e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/initspin.h @@ -0,0 +1,28 @@ +/* Generic definitions for spinlock initializers. +   Copyright (C) 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* Initial value of a spinlock.  Most platforms should use zero, +   unless they only implement a "test and clear" operation instead of +   the usual "test and set". */ +#define __LT_SPINLOCK_INIT 0 + +/* Macros for lock initializers, using the above definition. */ +#define __LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ALT_LOCK_INITIALIZER { 0, __LT_SPINLOCK_INIT } +#define __ATOMIC_INITIALIZER { 0, __LT_SPINLOCK_INIT } diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 000000000..2299b3af5 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,409 @@ +/* libc-internal interface for mutex locks.  LinuxThreads version. +   Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2006 +   	Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   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> + +#if defined _LIBC && !defined NOT_IN_libc +#include <linuxthreads/internals.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; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +typedef __libc_lock_recursive_t __rtld_lock_recursive_t; +#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. + +   For the C library we take a deeper look at the initializer.  For +   this implementation all fields are initialized to zero.  Therefore +   we don't initialize the variable which allows putting it into the +   BSS section.  (Except on PA-RISC and other odd architectures, where +   initialized locks must be set to one due to the lack of normal +   atomic operations.) */ + +#if __LT_SPINLOCK_INIT == 0 +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME; +#else +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; +#endif + +#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} + +#if defined _LIBC && defined IS_IN_libpthread +# define __libc_maybe_call(FUNC, ARGS, ELSE) FUNC ARGS +#else +# if defined __PIC__ || (defined _LIBC && defined SHARED) +#  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 +#endif +#if defined _LIBC && !defined NOT_IN_libc && defined SHARED +# define __libc_maybe_call2(FUNC, ARGS, ELSE) \ +  ({__builtin_expect (__libc_pthread_functions.ptr_##FUNC != NULL, 0) \ +    ? __libc_pthread_functions.ptr_##FUNC ARGS : ELSE; }) +#else +# define __libc_maybe_call2(FUNC, ARGS, ELSE) __libc_maybe_call (__##FUNC, ARGS, ELSE) +#endif + +/* Initialize the named lock variable, leaving it in a consistent, unlocked +   state.  */ +#if defined _LIBC && !defined NOT_IN_libc && defined SHARED +#define __libc_lock_init(NAME) \ +  ({									      \ +    (NAME).__m_count = 0;						      \ +    (NAME).__m_owner = NULL;						      \ +    (NAME).__m_kind = PTHREAD_MUTEX_TIMED_NP;				      \ +    (NAME).__m_lock.__status = 0;					      \ +    (NAME).__m_lock.__spinlock = __LT_SPINLOCK_INIT;			      \ +    0; }) +#else +#define __libc_lock_init(NAME) \ +  (__libc_maybe_call2 (pthread_mutex_init, (&(NAME), NULL), 0)) +#endif +#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.  */ +#if defined _LIBC && !defined NOT_IN_libc && defined SHARED +#define __libc_lock_init_recursive(NAME) \ +  ({									      \ +    (NAME).mutex.__m_count = 0;						      \ +    (NAME).mutex.__m_owner = NULL;					      \ +    (NAME).mutex.__m_kind = PTHREAD_MUTEX_RECURSIVE_NP;			      \ +    (NAME).mutex.__m_lock.__status = 0;					      \ +    (NAME).mutex.__m_lock.__spinlock = __LT_SPINLOCK_INIT;		      \ +    0; }) +#else +#define __libc_lock_init_recursive(NAME) \ +  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); +#endif +#define __rtld_lock_init_recursive(NAME) \ +  __libc_lock_init_recursive (NAME) + +/* 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_call2 (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_lock_fini ((NAME).mutex) +#define __rtld_lock_fini_recursive(NAME) __libc_lock_fini_recursive (NAME) + +/* Lock the named lock variable.  */ +#define __libc_lock_lock(NAME) \ +  (__libc_maybe_call2 (pthread_mutex_lock, (&(NAME)), 0)); +#define __libc_rwlock_rdlock(NAME) \ +  (__libc_maybe_call (__pthread_rwlock_rdlock, (&(NAME)), 0)); +#define __libc_rwlock_wrlock(NAME) \ +  (__libc_maybe_call (__pthread_rwlock_wrlock, (&(NAME)), 0)); + +/* Lock the recursive named lock variable.  */ +#define __libc_lock_lock_recursive(NAME) __libc_lock_lock ((NAME).mutex) + +/* Try to lock the named lock variable.  */ +#define __libc_lock_trylock(NAME) \ +  (__libc_maybe_call2 (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_lock_trylock ((NAME).mutex) +#define __rtld_lock_trylock_recursive(NAME) \ +  __libc_lock_trylock_recursive (NAME) + +/* Unlock the named lock variable.  */ +#define __libc_lock_unlock(NAME) \ +  (__libc_maybe_call2 (pthread_mutex_unlock, (&(NAME)), 0)); +#define __libc_rwlock_unlock(NAME) \ +  (__libc_maybe_call (__pthread_rwlock_unlock, (&(NAME)), 0)); + +/* Unlock the recursive named lock variable.  */ +#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex) + +#if defined _LIBC && defined SHARED +# define __rtld_lock_default_lock_recursive(lock) \ +  ++((pthread_mutex_t *)(lock))->__m_count; + +# define __rtld_lock_default_unlock_recursive(lock) \ +  --((pthread_mutex_t *)(lock))->__m_count; + +# define __rtld_lock_lock_recursive(NAME) \ +  GL(dl_rtld_lock_recursive) (&(NAME).mutex) + +# define __rtld_lock_unlock_recursive(NAME) \ +  GL(dl_rtld_unlock_recursive) (&(NAME).mutex) +#else +#define __rtld_lock_lock_recursive(NAME) __libc_lock_lock_recursive (NAME) +#define __rtld_lock_unlock_recursive(NAME) __libc_lock_unlock_recursive (NAME) +#endif + +/* Define once control variable.  */ +#if PTHREAD_ONCE_INIT == 0 +/* Special case for static variables where we can avoid the initialization +   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 (__pthread_once != NULL)						      \ +      __pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION));		      \ +    else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) {			      \ +      INIT_FUNCTION ();							      \ +      (ONCE_CONTROL) = 2;						      \ +    }									      \ +  } while (0) + + +/* Start critical region with cleanup.  */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ +  { struct _pthread_cleanup_buffer _buffer;				      \ +    int _avail = (DOIT) && _pthread_cleanup_push_defer != NULL;		      \ +    if (_avail) {							      \ +      _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG));		      \ +    } + +/* End critical region with cleanup.  */ +#define __libc_cleanup_region_end(DOIT) \ +    if (_avail) {							      \ +      _pthread_cleanup_pop_restore (&_buffer, (DOIT));			      \ +    }									      \ +  } + +/* Sometimes we have to exit the block in the middle.  */ +#define __libc_cleanup_end(DOIT) \ +    if (_avail) {							      \ +      _pthread_cleanup_pop_restore (&_buffer, (DOIT));			      \ +    } + +#define __libc_cleanup_push(fct, arg) \ +    { struct _pthread_cleanup_buffer _buffer; 				      \ +    __libc_maybe_call (_pthread_cleanup_push, (&_buffer, (fct), (arg)), 0) + +#define __libc_cleanup_pop(execute) \ +    __libc_maybe_call (_pthread_cleanup_pop, (&_buffer, execute), 0);	      \ +    } + +/* Create thread-specific key.  */ +#define __libc_key_create(KEY, DESTRUCTOR) \ +  (__libc_maybe_call (__pthread_key_create, (KEY, DESTRUCTOR), 1)) + +/* Get thread-specific data.  */ +#define __libc_getspecific(KEY) \ +  (__libc_maybe_call (__pthread_getspecific, (KEY), NULL)) + +/* Set thread-specific data.  */ +#define __libc_setspecific(KEY, VALUE) \ +  (__libc_maybe_call (__pthread_setspecific, (KEY, VALUE), 0)) + + +/* Register handlers to execute before and after `fork'.  */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ +  (__libc_maybe_call (__pthread_atfork, (PREPARE, PARENT, CHILD), 0)) + +/* 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 +#   define BP_SYM(sym) sym +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)) +weak_extern (BP_SYM (_pthread_cleanup_pop)) +weak_extern (BP_SYM (_pthread_cleanup_push_defer)) +weak_extern (BP_SYM (_pthread_cleanup_pop_restore)) +# 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_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_cleanup_push +#  pragma weak _pthread_cleanup_pop +# endif +#endif + +/* We need portable names for some functions.  E.g., when they are +   used as argument to __libc_cleanup_region_start.  */ +#define __libc_mutex_unlock __pthread_mutex_unlock + +#endif	/* bits/libc-lock.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 000000000..fa6eb4be2 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,59 @@ +/* libc-internal interface for thread-specific data.  LinuxThreads version. +   Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   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_TSD_H +#define _BITS_LIBC_TSD_H 1 + +#include <linuxthreads/descr.h> +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +/* When __thread works, the generic definition is what we want.  */ +# include <sysdeps/generic/bits/libc-tsd.h> + +#else + +# include <bits/libc-lock.h> + +# ifndef SHARED +extern void ** __pthread_internal_tsd_address (int); +extern void *__pthread_internal_tsd_get (int); +extern int __pthread_internal_tsd_set (int, const void *); + +weak_extern (__pthread_internal_tsd_address) +weak_extern (__pthread_internal_tsd_get) +weak_extern (__pthread_internal_tsd_set) +# endif + +#define __libc_tsd_define(CLASS, KEY)	CLASS void *__libc_tsd_##KEY##_data; +#define __libc_tsd_address(KEY) \ +  __libc_maybe_call2 (pthread_internal_tsd_address,			\ +		      (_LIBC_TSD_KEY_##KEY), &__libc_tsd_##KEY##_data) +#define __libc_tsd_get(KEY) \ +  __libc_maybe_call2 (pthread_internal_tsd_get,				\ +		      (_LIBC_TSD_KEY_##KEY), __libc_tsd_##KEY##_data) +#define __libc_tsd_set(KEY, VALUE) \ +  __libc_maybe_call2 (pthread_internal_tsd_set,				\ +		      (_LIBC_TSD_KEY_##KEY, (VALUE)),			\ +		       (__libc_tsd_##KEY##_data = (VALUE), 0)) + +#endif + +#endif	/* bits/libc-tsd.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h new file mode 100644 index 000000000..d1daef07a --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h @@ -0,0 +1,152 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix        */ +/* threads for Linux.                                                   */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */ +/*                                                                      */ +/* This program is free software; you can redistribute it and/or        */ +/* modify it under the terms of the GNU Library General Public License  */ +/* as published by the Free Software Foundation; either version 2       */ +/* of the License, or (at your option) any later version.               */ +/*                                                                      */ +/* This program is distributed in the hope that it will be useful,      */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */ +/* GNU Library General Public License for more details.                 */ + +#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> + +/* Fast locks (not abstract because mutexes and conditions aren't abstract). */ +struct _pthread_fastlock +{ +  long int __status;   /* "Free" or "taken" or head of waiting list */ +  int __spinlock;      /* Used by compare_and_swap emulation. Also, +			  adaptive SMP lock stores spin count here. */ +}; + +#ifndef _PTHREAD_DESCR_DEFINED +/* Thread descriptors */ +typedef struct _pthread_descr_struct *_pthread_descr; +# define _PTHREAD_DESCR_DEFINED +#endif + + +/* Attributes for threads.  */ +typedef struct __pthread_attr_s +{ +  int __detachstate; +  int __schedpolicy; +  struct __sched_param __schedparam; +  int __inheritsched; +  int __scope; +  size_t __guardsize; +  int __stackaddr_set; +  void *__stackaddr; +  size_t __stacksize; +} pthread_attr_t; + + +/* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */ + +#ifdef __GLIBC_HAVE_LONG_LONG +__extension__ typedef long long __pthread_cond_align_t; +#else +typedef long __pthread_cond_align_t; +#endif + +typedef struct +{ +  struct _pthread_fastlock __c_lock; /* Protect against concurrent access */ +  _pthread_descr __c_waiting;        /* Threads waiting on this condition */ +  char __padding[48 - sizeof (struct _pthread_fastlock) +		 - sizeof (_pthread_descr) - sizeof (__pthread_cond_align_t)]; +  __pthread_cond_align_t __align; +} pthread_cond_t; + + +/* Attribute for conditionally variables.  */ +typedef struct +{ +  int __dummy; +} pthread_condattr_t; + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER).  */ +/* (The layout is unnatural to maintain binary compatibility +    with earlier releases of LinuxThreads.) */ +typedef struct +{ +  int __m_reserved;               /* Reserved for future use */ +  int __m_count;                  /* Depth of recursive locking */ +  _pthread_descr __m_owner;       /* Owner thread (if recursive or errcheck) */ +  int __m_kind;                   /* Mutex kind: fast, recursive or errcheck */ +  struct _pthread_fastlock __m_lock; /* Underlying fast lock */ +} pthread_mutex_t; + + +/* Attribute for mutex.  */ +typedef struct +{ +  int __mutexkind; +} pthread_mutexattr_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Read-write locks.  */ +typedef struct _pthread_rwlock_t +{ +  struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */ +  int __rw_readers;                   /* Number of readers */ +  _pthread_descr __rw_writer;         /* Identity of writer, or NULL if none */ +  _pthread_descr __rw_read_waiting;   /* Threads waiting for reading */ +  _pthread_descr __rw_write_waiting;  /* Threads waiting for writing */ +  int __rw_kind;                      /* Reader/Writer preference selection */ +  int __rw_pshared;                   /* Shared between processes or not */ +} pthread_rwlock_t; + + +/* Attribute for read-write locks.  */ +typedef struct +{ +  int __lockkind; +  int __pshared; +} pthread_rwlockattr_t; +#endif + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barrier. */ +typedef struct { +  struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */ +  int __ba_required;                  /* Threads needed for completion */ +  int __ba_present;                   /* Threads waiting */ +  _pthread_descr __ba_waiting;        /* Queue of waiting threads */ +} pthread_barrier_t; + +/* barrier attribute */ +typedef struct { +  int __pshared; +} pthread_barrierattr_t; + +#endif + + +/* Thread identifiers */ +typedef unsigned long int pthread_t; + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h new file mode 100644 index 000000000..45264ac9c --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/bits/typesizes.h @@ -0,0 +1,66 @@ +/* bits/typesizes.h -- underlying types for *_t.  Generic version. +   Copyright (C) 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_TYPES_H +# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead." +#endif + +#ifndef	_BITS_TYPESIZES_H +#define	_BITS_TYPESIZES_H	1 + +/* See <bits/types.h> for the meaning of these macros.  This file exists so +   that <bits/types.h> need not vary across different GNU platforms.  */ + +#define __DEV_T_TYPE		__UQUAD_TYPE +#define __UID_T_TYPE		__U32_TYPE +#define __GID_T_TYPE		__U32_TYPE +#define __INO_T_TYPE		__ULONGWORD_TYPE +#define __INO64_T_TYPE		__UQUAD_TYPE +#define __MODE_T_TYPE		__U32_TYPE +#define __NLINK_T_TYPE		__UWORD_TYPE +#define __OFF_T_TYPE		__SLONGWORD_TYPE +#define __OFF64_T_TYPE		__SQUAD_TYPE +#define __PID_T_TYPE		__S32_TYPE +#define __RLIM_T_TYPE		__ULONGWORD_TYPE +#define __RLIM64_T_TYPE		__UQUAD_TYPE +#define	__BLKCNT_T_TYPE		__SLONGWORD_TYPE +#define	__BLKCNT64_T_TYPE	__SQUAD_TYPE +#define	__FSBLKCNT_T_TYPE	__ULONGWORD_TYPE +#define	__FSBLKCNT64_T_TYPE	__UQUAD_TYPE +#define	__FSFILCNT_T_TYPE	__ULONGWORD_TYPE +#define	__FSFILCNT64_T_TYPE	__UQUAD_TYPE +#define	__ID_T_TYPE		__U32_TYPE +#define __CLOCK_T_TYPE		__SLONGWORD_TYPE +#define __TIME_T_TYPE		__SLONGWORD_TYPE +#define __USECONDS_T_TYPE	__U32_TYPE +#define __SUSECONDS_T_TYPE	__SLONGWORD_TYPE +#define __DADDR_T_TYPE		__S32_TYPE +#define __SWBLK_T_TYPE		__SLONGWORD_TYPE +#define __KEY_T_TYPE		__S32_TYPE +#define __CLOCKID_T_TYPE	__S32_TYPE +#define __TIMER_T_TYPE		__S32_TYPE +#define __BLKSIZE_T_TYPE	__SLONGWORD_TYPE +#define __FSID_T_TYPE		struct { int __val[2]; } +#define __SSIZE_T_TYPE		__SWORD_TYPE + +/* Number of descriptors that can fit in an `fd_set'.  */ +#define	__FD_SETSIZE		1024 + + +#endif /* bits/typesizes.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c b/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c new file mode 100644 index 000000000..c3b3087e4 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/errno-loc.c @@ -0,0 +1,45 @@ +/* MT support function to get address of `errno' variable, linuxthreads +   version. +   Copyright (C) 1996, 1998, 2002, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD && !RTLD_PRIVATE_ERRNO +#undef errno +extern int errno; +#endif + +int * +#if ! USE___THREAD +weak_const_function +#endif +__errno_location (void) +{ +#if ! USE___THREAD && !defined NOT_IN_libc +  if (! SINGLE_THREAD_P) +    { +      pthread_descr self = thread_self(); +      return LIBC_THREAD_GETMEM (self, p_errnop); +    } +#endif +  return &errno; +} +libc_hidden_def (__errno_location) diff --git a/libpthread/linuxthreads/sysdeps/pthread/flockfile.c b/libpthread/linuxthreads/sysdeps/pthread/flockfile.c new file mode 100644 index 000000000..918cb84f6 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/flockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <bits/stdio-lock.h> + + +void +__flockfile (stream) +     FILE *stream; +{ +  _IO_lock_lock (*stream->_lock); +} +strong_alias (__flockfile, _IO_flockfile) +weak_alias (__flockfile, flockfile) diff --git a/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c b/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c new file mode 100644 index 000000000..21c1ea01e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/ftrylockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <bits/stdio-lock.h> + + +int +__ftrylockfile (stream) +     FILE *stream; +{ +  return _IO_lock_trylock (*stream->_lock); +} +strong_alias (__ftrylockfile, _IO_ftrylockfile) +weak_alias (__ftrylockfile, ftrylockfile) diff --git a/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c b/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c new file mode 100644 index 000000000..f941fc985 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/funlockfile.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthread.h> +#include <stdio.h> +#include <libio.h> +#include <bits/stdio-lock.h> + + +void +__funlockfile (stream) +     FILE *stream; +{ +  _IO_lock_unlock (*stream->_lock); +} +strong_alias (__funlockfile, _IO_funlockfile) +weak_alias (__funlockfile, funlockfile) diff --git a/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c b/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c new file mode 100644 index 000000000..1c64e6c2b --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/getcpuclockid.c @@ -0,0 +1,117 @@ +/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t.  Linux version +   Copyright (C) 2000, 2001, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <sys/time.h> +#include <time.h> +#include <internals.h> +#include <spinlock.h> +#include <kernel-features.h> +#include <kernel-posix-cpu-timers.h> + + +#if !(__ASSUME_POSIX_CPU_TIMERS > 0) +int __libc_missing_posix_cpu_timers attribute_hidden; +#endif +#if !(__ASSUME_POSIX_TIMERS > 0) +int __libc_missing_posix_timers attribute_hidden; +#endif + +int +pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id) +{ +#ifdef __NR_clock_getres +  pthread_handle handle = thread_handle(thread_id); +  int pid; + +  __pthread_lock (&handle->h_lock, NULL); +  if (nonexisting_handle (handle, thread_id)) +    { +      __pthread_unlock (&handle->h_lock); +      return ESRCH; +    } +  pid = handle->h_descr->p_pid; +  __pthread_unlock (&handle->h_lock); + +  /* The clockid_t value is a simple computation from the PID. +     But we do a clock_getres call to validate it if we aren't +     yet sure we have the kernel support.  */ + +  const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, CPUCLOCK_SCHED); + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +#  if !(__ASSUME_POSIX_TIMERS > 0) +  if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) +    __libc_missing_posix_cpu_timers = 1; +#  endif +  if (!__libc_missing_posix_cpu_timers) +    { +      INTERNAL_SYSCALL_DECL (err); +      int r = INTERNAL_SYSCALL (clock_getres, err, 2, pidclock, NULL); +      if (!INTERNAL_SYSCALL_ERROR_P (r, err)) +# endif +	{ +	  *clock_id = pidclock; +	  return 0; +	} + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +#  if !(__ASSUME_POSIX_TIMERS > 0) +      if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) +	{ +	  /* The kernel doesn't support these calls at all.  */ +	  __libc_missing_posix_timers = 1; +	  __libc_missing_posix_cpu_timers = 1; +	} +      else +#  endif +	if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL) +	  { +	    /* The kernel doesn't support these clocks at all.  */ +	    __libc_missing_posix_cpu_timers = 1; +	  } +      else +	return INTERNAL_SYSCALL_ERRNO (r, err); +    } +# endif +#endif + +#ifdef CLOCK_THREAD_CPUTIME_ID +  /* We need to store the thread ID in the CLOCKID variable together +     with a number identifying the clock.  We reserve the low 3 bits +     for the clock ID and the rest for the thread ID.  This is +     problematic if the thread ID is too large.  But 29 bits should be +     fine. + +     If some day more clock IDs are needed the ID part can be +     enlarged.  The IDs are entirely internal.  */ +  if (2 * PTHREAD_THREADS_MAX +      >= 1 << (8 * sizeof (*clock_id) - CLOCK_IDFIELD_SIZE)) +    return ERANGE; + +  /* Store the number.  */ +  *clock_id = CLOCK_THREAD_CPUTIME_ID | (thread_id << CLOCK_IDFIELD_SIZE); + +  return 0; +#else +  /* We don't have a timer for that.  */ +  return ENOENT; +#endif +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c b/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c new file mode 100644 index 000000000..fbc557616 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/herrno-loc.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1996, 97, 98, 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <netdb.h> +#include <tls.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD +# undef h_errno +extern int h_errno; +#endif + +/* When threaded, h_errno may be a per-thread variable.  */ +int * +weak_const_function +__h_errno_location (void) +{ +#if ! USE___THREAD +  if (! SINGLE_THREAD_P) +    { +      pthread_descr self = thread_self(); +      return LIBC_THREAD_GETMEM (self, p_h_errnop); +    } +#endif +  return &h_errno; +} +libc_hidden_def (__h_errno_location) diff --git a/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h b/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h new file mode 100644 index 000000000..424922ec0 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/kernel-features.h @@ -0,0 +1,72 @@ +/* Set flags signalling availability of kernel features based on given +   kernel version number. +   Copyright (C) 1999-2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   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.  */ + +/* This file must not contain any C code.  At least it must be protected +   to allow using the file also in assembler files.  */ + +#if defined __mips__ +# include <sgidefs.h> +#endif + +#include <linux/version.h> +#define __LINUX_KERNEL_VERSION	LINUX_VERSION_CODE + +/* Real-time signal became usable in 2.1.70.  */ +#if __LINUX_KERNEL_VERSION >= 131398 +# define __ASSUME_REALTIME_SIGNALS	1 +#endif + +/* Beginning with 2.5.63 support for realtime and monotonic clocks and +   timers based on them is available.  */ +#if __LINUX_KERNEL_VERSION >= 132415 +# define __ASSUME_POSIX_TIMERS		1 +#endif + +/* On x86, the set_thread_area syscall was introduced in 2.5.29, but its +   semantics was changed in 2.5.30, and again after 2.5.31.  */ +#if __LINUX_KERNEL_VERSION >= 132384 && defined __i386__ +# define __ASSUME_SET_THREAD_AREA_SYSCALL	1 +#endif + +/* We can use the LDTs for threading with Linux 2.3.99 and newer.  */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_LDT_WORKS		1 +#endif + +/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way +   and the vfork syscall made it into the official kernel.  */ +#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ +# define __ASSUME_STD_AUXV		1 +# define __ASSUME_VFORK_SYSCALL		1 +#endif + +/* The vfork syscall on x86 and arm was definitely available in 2.4.  */ +#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __arm__) +# define __ASSUME_VFORK_SYSCALL		1 +#endif + +/* These features were surely available with 2.4.12.  */ +#if __LINUX_KERNEL_VERSION >= 132108 && defined __mc68000__ +# define __ASSUME_MMAP2_SYSCALL		1 +# define __ASSUME_TRUNCATE64_SYSCALL	1 +# define __ASSUME_STAT64_SYSCALL	1 +# define __ASSUME_FCNTL64		1 +# define __ASSUME_VFORK_SYSCALL		1 +#endif diff --git a/libpthread/linuxthreads/sysdeps/pthread/list.h b/libpthread/linuxthreads/sysdeps/pthread/list.h new file mode 100644 index 000000000..43186a2d5 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/list.h @@ -0,0 +1,114 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LIST_H +#define _LIST_H	1 + +/* The definitions of this file are adopted from those which can be +   found in the Linux kernel headers to enable people familiar with +   the latter find their way in these sources as well.  */ + + +/* Basic type for the double-link list.  */ +typedef struct list_head +{ +  struct list_head *next; +  struct list_head *prev; +} list_t; + + +/* Define a variable with the head and tail of the list.  */ +#define LIST_HEAD(name) \ +  list_t name = { &(name), &(name) } + +/* Initialize a new list head.  */ +#define INIT_LIST_HEAD(ptr) \ +  (ptr)->next = (ptr)->prev = (ptr) + + +/* Add new element at the head of the list.  */ +static inline void +list_add (list_t *newp, list_t *head) +{ +  head->next->prev = newp; +  newp->next = head->next; +  newp->prev = head; +  head->next = newp; +} + + +/* Add new element at the tail of the list.  */ +static inline void +list_add_tail (list_t *newp, list_t *head) +{ +  head->prev->next = newp; +  newp->next = head; +  newp->prev = head->prev; +  head->prev = newp; +} + + +/* Remove element from list.  */ +static inline void +list_del (list_t *elem) +{ +  elem->next->prev = elem->prev; +  elem->prev->next = elem->next; +} + + +/* Join two lists.  */ +static inline void +list_splice (list_t *add, list_t *head) +{ +  /* Do nothing if the list which gets added is empty.  */ +  if (add != add->next) +    { +      add->next->prev = head; +      add->prev->next = head->next; +      head->next->prev = add->prev; +      head->next = add->next; +    } +} + + +/* Get typed element from list at a given position.  */ +#define list_entry(ptr, type, member) \ +  ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list.  */ +#define list_for_each(pos, head) \ +  for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list.  */ +#define list_for_each_prev(pos, head) \ +  for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list.  The list elements can be +   removed from the list while doing this.  */ +#define list_for_each_prev_safe(pos, p, head) \ +  for (pos = (head)->prev, p = pos->prev; \ +       pos != (head); \ +       pos = p, p = pos->prev) + +#endif	/* list.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h b/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h new file mode 100644 index 000000000..5191f8c77 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,67 @@ +/* Basic platform-independent macro definitions for mutexes, +   thread-specific data and parameters for malloc. +   Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _MALLOC_MACHINE_H +#define _MALLOC_MACHINE_H + +#undef thread_atfork_static + +#include <atomic.h> +#include <bits/libc-lock.h> + +__libc_lock_define (typedef, mutex_t) + +#define mutex_init(m)		\ +  __libc_maybe_call2 (pthread_mutex_init, (m, NULL), (*(int *)(m) = 0)) +#define mutex_lock(m)		\ +  __libc_maybe_call2 (pthread_mutex_lock, (m), ((*(int *)(m) = 1), 0)) +#define mutex_trylock(m)	\ +  __libc_maybe_call2 (pthread_mutex_trylock, (m), \ +		      (*(int *)(m) ? 1 : ((*(int *)(m) = 1), 0))) +#define mutex_unlock(m)		\ +  __libc_maybe_call2 (pthread_mutex_unlock, (m), (*(int *)(m) = 0)) + +/* This is defined by newer gcc version unique for each module.  */ +extern void *__dso_handle __attribute__ ((__weak__)); + +#include <fork.h> + +#ifdef SHARED +# define thread_atfork(prepare, parent, child) \ +   __register_atfork (prepare, parent, child, __dso_handle) +#else +# define thread_atfork(prepare, parent, child) \ +   __register_atfork (prepare, parent, child,				      \ +		      &__dso_handle == NULL ? NULL : __dso_handle) +#endif + +/* thread specific data for glibc */ + +#include <bits/libc-tsd.h> + +typedef int tsd_key_t[1];	/* no key data structure, libc magic does it */ +__libc_tsd_define (static, MALLOC)	/* declaration/common definition */ +#define tsd_key_create(key, destr)	((void) (key)) +#define tsd_setspecific(key, data)	__libc_tsd_set (MALLOC, (data)) +#define tsd_getspecific(key, vptr)	((vptr) = __libc_tsd_get (MALLOC)) + +#include <sysdeps/generic/malloc-machine.h> + +#endif /* !defined(_MALLOC_MACHINE_H) */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h new file mode 100644 index 000000000..4373917df --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/not-cancel.h @@ -0,0 +1,62 @@ +/* Uncancelable versions of cancelable interfaces.  Linux version. +   Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sys/syscall.h> +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(func, numargs, args...) syscall(__NR_ ## func, args) + +/* Uncancelable open.  */ +#define open_not_cancel(name, flags, mode) \ +   INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode)) +#define open_not_cancel_2(name, flags) \ +   INLINE_SYSCALL (open, 2, (const char *) (name), (flags)) + +/* Uncancelable close.  */ +#define close_not_cancel(fd) \ +  INLINE_SYSCALL (close, 1, fd) +#define close_not_cancel_no_status(fd) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read.  */ +#define read_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (read, 3, (fd), (buf), (n)) + +/* Uncancelable write.  */ +#define write_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (write, 3, (fd), (buf), (n)) + +/* Uncancelable writev.  */ +#define writev_not_cancel_no_status(fd, iov, n) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl.  */ +#define fcntl_not_cancel(fd, cmd, val) \ +  __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid.  */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif diff --git a/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h b/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h new file mode 100644 index 000000000..1b0a2b65e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/posix-timer.h @@ -0,0 +1,204 @@ +/* Definitions for POSIX timer implementation on top of LinuxThreads. +   Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <limits.h> +#include <signal.h> + +/* Double linked list.  */ +struct list_links +{ +  struct list_links *next; +  struct list_links *prev; +}; + + +/* Forward declaration.  */ +struct timer_node; + + +/* Definitions for an internal thread of the POSIX timer implementation.  */ +struct thread_node +{ +  struct list_links links; +  pthread_attr_t attr; +  pthread_t id; +  unsigned int exists; +  struct list_links timer_queue; +  pthread_cond_t cond; +  struct timer_node *current_timer; +  pthread_t captured; +  clockid_t clock_id; +}; + + +/* Internal representation of a timer.  */ +struct timer_node +{ +  struct list_links links; +  struct sigevent event; +  clockid_t clock; +  struct itimerspec value; +  struct timespec expirytime; +  pthread_attr_t attr; +  unsigned int abstime; +  unsigned int armed; +  enum { +    TIMER_FREE, TIMER_INUSE, TIMER_DELETED +  } inuse; +  struct thread_node *thread; +  pid_t creator_pid; +  int refcount; +  int overrun_count; +}; + + +/* Static array with the structures for all the timers.  */ +extern struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists.  */ +extern pthread_mutex_t __timer_mutex; + +/* Variable to protext initialization.  */ +extern pthread_once_t __timer_init_once_control; + +/* Nonzero if initialization of timer implementation failed.  */ +extern int __timer_init_failed; + +/* Nodes for the threads used to deliver signals.  */ +/* A distinct thread is used for each clock type.  */ + +extern struct thread_node __timer_signal_thread_rclk; + + +/* Return pointer to timer structure corresponding to ID.  */ +static inline struct timer_node * +timer_id2ptr (timer_t timerid) +{ +  if (timerid >= 0 && timerid < TIMER_MAX) +    return &__timer_array[timerid]; + +  return NULL; +} + +/* Return ID of TIMER.  */ +static inline int +timer_ptr2id (struct timer_node *timer) +{ +  return timer - __timer_array; +} + +/* Check whether timer is valid; global mutex must be held. */ +static inline int +timer_valid (struct timer_node *timer) +{ +  return timer && timer->inuse == TIMER_INUSE; +} + +/* Timer refcount functions; need global mutex. */ +extern void __timer_dealloc (struct timer_node *timer); + +static inline void +timer_addref (struct timer_node *timer) +{ +  timer->refcount++; +} + +static inline void +timer_delref (struct timer_node *timer) +{ +  if (--timer->refcount == 0) +    __timer_dealloc (timer); +} + +/* Timespec helper routines.  */ +static inline int +timespec_compare (const struct timespec *left, const struct timespec *right) +{ +  if (left->tv_sec < right->tv_sec) +    return -1; +  if (left->tv_sec > right->tv_sec) +    return 1; + +  if (left->tv_nsec < right->tv_nsec) +    return -1; +  if (left->tv_nsec > right->tv_nsec) +    return 1; + +  return 0; +} + +static inline void +timespec_add (struct timespec *sum, const struct timespec *left, +	      const struct timespec *right) +{ +  sum->tv_sec = left->tv_sec + right->tv_sec; +  sum->tv_nsec = left->tv_nsec + right->tv_nsec; + +  if (sum->tv_nsec >= 1000000000) +    { +      ++sum->tv_sec; +      sum->tv_nsec -= 1000000000; +    } +} + +static inline void +timespec_sub (struct timespec *diff, const struct timespec *left, +	      const struct timespec *right) +{ +  diff->tv_sec = left->tv_sec - right->tv_sec; +  diff->tv_nsec = left->tv_nsec - right->tv_nsec; + +  if (diff->tv_nsec < 0) +    { +      --diff->tv_sec; +      diff->tv_nsec += 1000000000; +    } +} + + +/* We need one of the list functions in the other modules.  */ +static inline void +list_unlink_ip (struct list_links *list) +{ +  struct list_links *lnext = list->next, *lprev = list->prev; + +  lnext->prev = lprev; +  lprev->next = lnext; + +  /* The suffix ip means idempotent; list_unlink_ip can be called +   * two or more times on the same node. +   */ + +  list->next = list; +  list->prev = list; +} + + +/* Functions in the helper file.  */ +extern void __timer_mutex_cancel_handler (void *arg); +extern void __timer_init_once (void); +extern struct timer_node *__timer_alloc (void); +extern int __timer_thread_start (struct thread_node *thread); +extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t); +extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t); +extern void __timer_thread_dealloc (struct thread_node *thread); +extern int __timer_thread_queue_timer (struct thread_node *thread, +				       struct timer_node *insert); +extern void __timer_thread_wakeup (struct thread_node *thread); diff --git a/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c b/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c new file mode 100644 index 000000000..1ccac2f6e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,124 @@ +/* Special .init and .fini section support.  Linuxthread version. +   Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it +   and/or modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   In addition to the permissions in the GNU Lesser General Public +   License, the Free Software Foundation gives you unlimited +   permission to link the compiled version of this file with other +   programs, and to distribute those programs without any restriction +   coming from the use of this file.  (The Lesser General Public +   License restrictions do apply in other respects; for example, they +   cover modification of the file, and distribution when not linked +   into another program.) + +   The GNU C Library is distributed in the hope that it will be +   useful, but WITHOUT ANY WARRANTY; without even the implied warranty +   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* This file is compiled into assembly code which is then munged by a sed +   script into two files: crti.s and crtn.s. + +   * crti.s puts a function prologue at the beginning of the +   .init and .fini sections and defines global symbols for +   those addresses, so they can be called as functions. + +   * crtn.s puts the corresponding function epilogues +   in the .init and .fini sections. */ + +#include <stdlib.h> + +/* We use embedded asm for .section unconditionally, as this makes it +   easier to insert the necessary directives into crtn.S. */ +#define SECTION(x) asm (".section " x ) + +/* Embed an #include to pull in the alignment and .end directives. */ +asm ("\n#include \"defs.h\""); + +/* The initial common code ends here. */ +asm ("\n/*@HEADER_ENDS*/"); + +/* To determine whether we need .end and .align: */ +asm ("\n/*@TESTS_BEGIN*/"); +extern void dummy (void (*foo) (void)); +void +dummy (void (*foo) (void)) +{ +  if (foo) +    (*foo) (); +} +asm ("\n/*@TESTS_END*/"); + +/* The beginning of _init:  */ +asm ("\n/*@_init_PROLOG_BEGINS*/"); + +static void +call_initialize_minimal (void) +{ +  extern void __pthread_initialize_minimal (void); + +  __pthread_initialize_minimal (); +} + +SECTION (".init"); +extern void _init (void); +void +_init (void) +{ +  /* The very first thing we must do is to set up the registers.  */ +  call_initialize_minimal (); + +  asm ("ALIGN"); +  asm("END_INIT"); +  /* Now the epilog. */ +  asm ("\n/*@_init_PROLOG_ENDS*/"); +  asm ("\n/*@_init_EPILOG_BEGINS*/"); +  SECTION(".init"); +} +asm ("END_INIT"); + +/* End of the _init epilog, beginning of the _fini prolog. */ +asm ("\n/*@_init_EPILOG_ENDS*/"); +asm ("\n/*@_fini_PROLOG_BEGINS*/"); + +SECTION (".fini"); +extern void _fini (void); +void +_fini (void) +{ + +  /* End of the _fini prolog. */ +  asm ("ALIGN"); +  asm ("END_FINI"); +  asm ("\n/*@_fini_PROLOG_ENDS*/"); + +  { +    /* Let GCC know that _fini is not a leaf function by having a dummy +       function call here.  We arrange for this call to be omitted from +       either crt file.  */ +    extern void i_am_not_a_leaf (void); +    i_am_not_a_leaf (); +  } + +  /* Beginning of the _fini epilog. */ +  asm ("\n/*@_fini_EPILOG_BEGINS*/"); +  SECTION (".fini"); +} +asm ("END_FINI"); + +/* End of the _fini epilog.  Any further generated assembly (e.g. .ident) +   is shared between both crt files. */ +asm ("\n/*@_fini_EPILOG_ENDS*/"); +asm ("\n/*@TRAILER_BEGINS*/"); + +/* End of file. */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h b/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h new file mode 100644 index 000000000..9bc2f88a8 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _PTHREAD_FUNCTIONS_H +#define _PTHREAD_FUNCTIONS_H	1 + +#include <pthread.h> +#include <setjmp.h> +#include <linuxthreads/descr.h> + +struct fork_block; + +/* Data type shared with libc.  The libc uses it to pass on calls to +   the thread functions.  Wine pokes directly into this structure, +   so if possible avoid breaking it and append new hooks to the end.  */ +struct pthread_functions +{ +  pid_t (*ptr_pthread_fork) (struct fork_block *); +  int (*ptr_pthread_attr_destroy) (pthread_attr_t *); +  int (*ptr___pthread_attr_init) (pthread_attr_t *); +  int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, +					 struct sched_param *); +  int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, +					 const struct sched_param *); +  int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); +  int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); +  int (*ptr_pthread_condattr_init) (pthread_condattr_t *); +  int (*ptr_pthread_cond_broadcast) (pthread_cond_t *); +  int (*ptr_pthread_cond_destroy) (pthread_cond_t *); +  int (*ptr_pthread_cond_init) (pthread_cond_t *, +				  const pthread_condattr_t *); +  int (*ptr_pthread_cond_signal) (pthread_cond_t *); +  int (*ptr_pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); +  int (*ptr_pthread_equal) (pthread_t, pthread_t); +  void (*ptr___pthread_exit) (void *); +  int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); +  int (*ptr_pthread_setschedparam) (pthread_t, int, +				    const struct sched_param *); +  int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_init) (pthread_mutex_t *, +				 const pthread_mutexattr_t *); +  int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); +  pthread_t (*ptr_pthread_self) (void); +  int (*ptr_pthread_setcancelstate) (int, int *); +  int (*ptr_pthread_setcanceltype) (int, int *); +  void (*ptr_pthread_do_exit) (void *retval, char *currentframe); +  void (*ptr_pthread_cleanup_upto) (__jmp_buf target, +				    char *targetframe); +  pthread_descr (*ptr_pthread_thread_self) (void); +  int (*ptr_pthread_internal_tsd_set) (int key, const void *pointer); +  void * (*ptr_pthread_internal_tsd_get) (int key); +  void ** __attribute__ ((__const__)) +    (*ptr_pthread_internal_tsd_address) (int key); +  int (*ptr_pthread_sigaction) (int sig, const struct sigaction * act, +				struct sigaction *oact); +  int (*ptr_pthread_sigwait) (const sigset_t *set, int *sig); +  int (*ptr_pthread_raise) (int sig); +  int (*ptr_pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, +				       const struct timespec *); +  void (*ptr__pthread_cleanup_push) (struct _pthread_cleanup_buffer * buffer, +				     void (*routine)(void *), void * arg); + +  void (*ptr__pthread_cleanup_pop) (struct _pthread_cleanup_buffer * buffer, +				    int execute); +}; + +/* Variable in libc.so.  */ +extern struct pthread_functions __libc_pthread_functions attribute_hidden; + +#endif	/* pthread-functions.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread.h b/libpthread/linuxthreads/sysdeps/pthread/pthread.h new file mode 100644 index 000000000..44e0e72a5 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/pthread.h @@ -0,0 +1,689 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix        */ +/* threads for Linux.                                                   */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */ +/*                                                                      */ +/* This program is free software; you can redistribute it and/or        */ +/* modify it under the terms of the GNU Library General Public License  */ +/* as published by the Free Software Foundation; either version 2       */ +/* of the License, or (at your option) any later version.               */ +/*                                                                      */ +/* This program is distributed in the hope that it will be useful,      */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */ +/* GNU Library General Public License for more details.                 */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H	1 + +#include <features.h> + +#include <sched.h> +#include <time.h> + +#define __need_sigset_t +#include <signal.h> +#include <bits/pthreadtypes.h> +#include <bits/initspin.h> +#ifdef _LIBC +#include <bits/uClibc_pthread.h> +#endif + + +__BEGIN_DECLS + +/* Initializers.  */ + +#define PTHREAD_MUTEX_INITIALIZER \ +  {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, __LOCK_INITIALIZER} +#ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +  {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER} +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +  {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER} +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +  {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} +#endif + +#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0, "", 0} + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +# define PTHREAD_RWLOCK_INITIALIZER \ +  { __LOCK_INITIALIZER, 0, NULL, NULL, NULL,				      \ +    PTHREAD_RWLOCK_DEFAULT_NP, PTHREAD_PROCESS_PRIVATE } +#endif +#ifdef __USE_GNU +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +  { __LOCK_INITIALIZER, 0, NULL, NULL, NULL,				      \ +    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, PTHREAD_PROCESS_PRIVATE } +#endif + +/* Values for attributes.  */ + +enum +{ +  PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE	PTHREAD_CREATE_JOINABLE +  PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED	PTHREAD_CREATE_DETACHED +}; + +enum +{ +  PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED	PTHREAD_INHERIT_SCHED +  PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED	PTHREAD_EXPLICIT_SCHED +}; + +enum +{ +  PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM	PTHREAD_SCOPE_SYSTEM +  PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS	PTHREAD_SCOPE_PROCESS +}; + +enum +{ +  PTHREAD_MUTEX_TIMED_NP, +  PTHREAD_MUTEX_RECURSIVE_NP, +  PTHREAD_MUTEX_ERRORCHECK_NP, +  PTHREAD_MUTEX_ADAPTIVE_NP +#ifdef __USE_UNIX98 +  , +  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, +  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, +  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, +  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +#endif +#ifdef __USE_GNU +  /* For compatibility.  */ +  , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_ADAPTIVE_NP +#endif +}; + +enum +{ +  PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE	PTHREAD_PROCESS_PRIVATE +  PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED	PTHREAD_PROCESS_SHARED +}; + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +enum +{ +  PTHREAD_RWLOCK_PREFER_READER_NP, +  PTHREAD_RWLOCK_PREFER_WRITER_NP, +  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, +  PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_WRITER_NP +}; +#endif	/* Unix98 */ + +#define PTHREAD_ONCE_INIT 0 + +/* Special constants */ + +#ifdef __USE_XOPEN2K +/* -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + +/* Cleanup buffers */ + +struct _pthread_cleanup_buffer +{ +  void (*__routine) (void *);		  /* Function to call.  */ +  void *__arg;				  /* Its argument.  */ +  int __canceltype;			  /* Saved cancellation type. */ +  struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions.  */ +}; + +/* Cancellation */ + +enum +{ +  PTHREAD_CANCEL_ENABLE, +#define PTHREAD_CANCEL_ENABLE	PTHREAD_CANCEL_ENABLE +  PTHREAD_CANCEL_DISABLE +#define PTHREAD_CANCEL_DISABLE	PTHREAD_CANCEL_DISABLE +}; +enum +{ +  PTHREAD_CANCEL_DEFERRED, +#define PTHREAD_CANCEL_DEFERRED	PTHREAD_CANCEL_DEFERRED +  PTHREAD_CANCEL_ASYNCHRONOUS +#define PTHREAD_CANCEL_ASYNCHRONOUS	PTHREAD_CANCEL_ASYNCHRONOUS +}; +#define PTHREAD_CANCELED ((void *) -1) + + +/* Function for handling threads.  */ + +/* Create a thread with given attributes ATTR (or default attributes +   if ATTR is NULL), and call function START_ROUTINE with given +   arguments ARG.  */ +extern int pthread_create (pthread_t *__restrict __threadp, +			   __const pthread_attr_t *__restrict __attr, +			   void *(*__start_routine) (void *), +			   void *__restrict __arg) __THROW; + +/* Obtain the identifier of the current thread.  */ +extern pthread_t pthread_self (void) __THROW; + +/* Compare two thread identifiers.  */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + +/* Terminate calling thread.  */ +extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); + +/* Make calling thread wait for termination of the thread TH.  The +   exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN +   is not NULL.  */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. +   The resources of TH will therefore be freed immediately when it +   terminates, instead of waiting for another thread to perform PTHREAD_JOIN +   on it.  */ +extern int pthread_detach (pthread_t __th) __THROW; + + +/* Functions for handling attributes.  */ + +/* Initialize thread attribute *ATTR with default attributes +   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, +    no user-provided stack).  */ +extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; + +/* Destroy thread attribute *ATTR.  */ +extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; + +/* Set the `detachstate' attribute in *ATTR according to DETACHSTATE.  */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, +					int __detachstate) __THROW; + +/* Return in *DETACHSTATE the `detachstate' attribute in *ATTR.  */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, +					int *__detachstate) __THROW; + +/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM.  */ +extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, +				       __const struct sched_param *__restrict +				       __param) __THROW; + +/* Return in *PARAM the scheduling parameters of *ATTR.  */ +extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict +				       __attr, +				       struct sched_param *__restrict __param) +     __THROW; + +/* Set scheduling policy in *ATTR according to POLICY.  */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) +     __THROW; + +/* Return in *POLICY the scheduling policy of *ATTR.  */ +extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict +					__attr, int *__restrict __policy) +     __THROW; + +/* Set scheduling inheritance mode in *ATTR according to INHERIT.  */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, +					 int __inherit) __THROW; + +/* Return in *INHERIT the scheduling inheritance mode of *ATTR.  */ +extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict +					 __attr, int *__restrict __inherit) +     __THROW; + +/* Set scheduling contention scope in *ATTR according to SCOPE.  */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) +     __THROW; + +/* Return in *SCOPE the scheduling contention scope of *ATTR.  */ +extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, +				  int *__restrict __scope) __THROW; + +#ifdef __USE_UNIX98 +/* Set the size of the guard area at the bottom of the thread.  */ +extern int pthread_attr_setguardsize (pthread_attr_t *__attr, +				      size_t __guardsize) __THROW; + +/* Get the size of the guard area at the bottom of the thread.  */ +extern int pthread_attr_getguardsize (__const pthread_attr_t *__restrict +				      __attr, size_t *__restrict __guardsize) +     __THROW; +#endif + +/* Set the starting address of the stack of the thread to be created. +   Depending on whether the stack grows up or down the value must either +   be higher or lower than all the address in the memory block.  The +   minimal size of the block must be PTHREAD_STACK_MIN.  */ +extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, +				      void *__stackaddr) __THROW; + +/* Return the previously set address for the stack.  */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict +				      __attr, void **__restrict __stackaddr) +     __THROW; + +#ifdef __USE_XOPEN2K +/* The following two interfaces are intended to replace the last two.  They +   require setting the address as well as the size since only setting the +   address will make the implementation on some architectures impossible.  */ +extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, +				  size_t __stacksize) __THROW; + +/* Return the previously set address for the stack.  */ +extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, +				  void **__restrict __stackaddr, +				  size_t *__restrict __stacksize) __THROW; +#endif + +/* Add information about the minimum stack size needed for the thread +   to be started.  This size must never be less than PTHREAD_STACK_MIN +   and must also not exceed the system limits.  */ +extern int pthread_attr_setstacksize (pthread_attr_t *__attr, +				      size_t __stacksize) __THROW; + +/* Return the currently used minimal stack size.  */ +extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict +				      __attr, size_t *__restrict __stacksize) +     __THROW; + +#ifdef __USE_GNU +/* Initialize thread attribute *ATTR with attributes corresponding to the +   already running thread TH.  It shall be called on unitialized ATTR +   and destroyed with pthread_attr_destroy when no longer needed.  */ +extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; +#endif + +/* Functions for scheduling control.  */ + +/* Set the scheduling parameters for TARGET_THREAD according to POLICY +   and *PARAM.  */ +extern int pthread_setschedparam (pthread_t __target_thread, int __policy, +				  __const struct sched_param *__param) +     __THROW; + +/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD.  */ +extern int pthread_getschedparam (pthread_t __target_thread, +				  int *__restrict __policy, +				  struct sched_param *__restrict __param) +     __THROW; + +#ifdef __USE_UNIX98 +/* Determine level of concurrency.  */ +extern int pthread_getconcurrency (void) __THROW; + +/* Set new concurrency level to LEVEL.  */ +extern int pthread_setconcurrency (int __level) __THROW; +#endif + +#ifdef __USE_GNU +/* Yield the processor to another thread or process. +   This function is similar to the POSIX `sched_yield' function but +   might be differently implemented in the case of a m-on-n thread +   implementation.  */ +extern int pthread_yield (void) __THROW; +#endif + +/* Functions for mutex handling.  */ + +/* Initialize MUTEX using attributes in *MUTEX_ATTR, or use the +   default values if later is NULL.  */ +extern int pthread_mutex_init (pthread_mutex_t *__restrict __mutex, +			       __const pthread_mutexattr_t *__restrict +			       __mutex_attr) __THROW; + +/* Destroy MUTEX.  */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try to lock MUTEX.  */ +extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROW; + +/* Wait until lock for MUTEX becomes available and lock it.  */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; + +#ifdef __USE_XOPEN2K +/* Wait until lock becomes available, or specified time passes. */ +extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, +				    __const struct timespec *__restrict +				    __abstime) __THROW; +#endif + +/* Unlock MUTEX.  */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; + + +/* Functions for handling mutex attributes.  */ + +/* Initialize mutex attribute object ATTR with default attributes +   (kind is PTHREAD_MUTEX_TIMED_NP).  */ +extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW; + +/* Destroy mutex attribute object ATTR.  */ +extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; + +/* Get the process-shared flag of the mutex attribute ATTR.  */ +extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t * +					 __restrict __attr, +					 int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the mutex attribute ATTR.  */ +extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, +					 int __pshared) __THROW; + +#ifdef __USE_UNIX98 +/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, +   PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or +   PTHREAD_MUTEX_DEFAULT).  */ +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) +     __THROW; + +/* Return in *KIND the mutex kind attribute in *ATTR.  */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict +				      __attr, int *__restrict __kind) __THROW; +#endif + + +/* Functions for handling conditional variables.  */ + +/* Initialize condition variable COND using attributes ATTR, or use +   the default values if later is NULL.  */ +extern int pthread_cond_init (pthread_cond_t *__restrict __cond, +			      __const pthread_condattr_t *__restrict +			      __cond_attr) __THROW; + +/* Destroy condition variable COND.  */ +extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; + +/* Wake up one thread waiting for condition variable COND.  */ +extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; + +/* Wake up all threads waiting for condition variables COND.  */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; + +/* Wait for condition variable COND to be signaled or broadcast. +   MUTEX is assumed to be locked before.  */ +extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, +			      pthread_mutex_t *__restrict __mutex); + +/* Wait for condition variable COND to be signaled or broadcast until +   ABSTIME.  MUTEX is assumed to be locked before.  ABSTIME is an +   absolute time specification; zero is the beginning of the epoch +   (00:00:00 GMT, January 1, 1970).  */ +extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, +				   pthread_mutex_t *__restrict __mutex, +				   __const struct timespec *__restrict +				   __abstime); + +/* Functions for handling condition variable attributes.  */ + +/* Initialize condition variable attribute ATTR.  */ +extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; + +/* Destroy condition variable attribute ATTR.  */ +extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; + +/* Get the process-shared flag of the condition variable attribute ATTR.  */ +extern int pthread_condattr_getpshared (__const pthread_condattr_t * +					__restrict __attr, +					int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the condition variable attribute ATTR.  */ +extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, +					int __pshared) __THROW; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Functions for handling read-write locks.  */ + +/* Initialize read-write lock RWLOCK using attributes ATTR, or use +   the default values if later is NULL.  */ +extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, +				__const pthread_rwlockattr_t *__restrict +				__attr) __THROW; + +/* Destroy read-write lock RWLOCK.  */ +extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; + +/* Acquire read lock for RWLOCK.  */ +extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire read lock for RWLOCK.  */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire read lock for RWLOCK or return after specfied time.  */ +extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, +				       __const struct timespec *__restrict +				       __abstime) __THROW; +# endif + +/* Acquire write lock for RWLOCK.  */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire write lock for RWLOCK.  */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire write lock for RWLOCK or return after specfied time.  */ +extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, +				       __const struct timespec *__restrict +				       __abstime) __THROW; +# endif + +/* Unlock RWLOCK.  */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; + + +/* Functions for handling read-write lock attributes.  */ + +/* Initialize attribute object ATTR with default values.  */ +extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; + +/* Destroy attribute object ATTR.  */ +extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; + +/* Return current setting of process-shared attribute of ATTR in PSHARED.  */ +extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * +					  __restrict __attr, +					  int *__restrict __pshared) __THROW; + +/* Set process-shared attribute of ATTR to PSHARED.  */ +extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, +					  int __pshared) __THROW; + +/* Return current setting of reader/writer preference.  */ +extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *__attr, +					  int *__pref) __THROW; + +/* Set reader/write preference.  */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, +					  int __pref) __THROW; +#endif + +#ifdef __USE_XOPEN2K +/* The IEEE Std. 1003.1j-2000 introduces functions to implement +   spinlocks.  */ + +/* Initialize the spinlock LOCK.  If PSHARED is nonzero the spinlock can +   be shared between different processes.  */ +extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) +     __THROW; + +/* Destroy the spinlock LOCK.  */ +extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; + +/* Wait until spinlock LOCK is retrieved.  */ +extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; + +/* Try to lock spinlock LOCK.  */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; + +/* Release spinlock LOCK.  */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; + + +/* Barriers are a also a new feature in 1003.1j-2000. */ + +extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, +				 __const pthread_barrierattr_t *__restrict +				 __attr, unsigned int __count) __THROW; + +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * +					   __restrict __attr, +					   int *__restrict __pshared) __THROW; + +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, +					   int __pshared) __THROW; + +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; +#endif + + +/* Functions for handling thread-specific data.  */ + +/* Create a key value identifying a location in the thread-specific +   data area.  Each thread maintains a distinct thread-specific data +   area.  DESTR_FUNCTION, if non-NULL, is called with the value +   associated to that key when the key is destroyed. +   DESTR_FUNCTION is not called if the value associated is NULL when +   the key is destroyed.  */ +extern int pthread_key_create (pthread_key_t *__key, +			       void (*__destr_function) (void *)) __THROW; + +/* Destroy KEY.  */ +extern int pthread_key_delete (pthread_key_t __key) __THROW; + +/* Store POINTER in the thread-specific data slot identified by KEY. */ +extern int pthread_setspecific (pthread_key_t __key, +				__const void *__pointer) __THROW; + +/* Return current value of the thread-specific data slot identified by KEY.  */ +extern void *pthread_getspecific (pthread_key_t __key) __THROW; + + +/* Functions for handling initialization.  */ + +/* Guarantee that the initialization function INIT_ROUTINE will be called +   only once, even if pthread_once is executed several times with the +   same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or +   extern variable initialized to PTHREAD_ONCE_INIT. + +   The initialization functions might throw exception which is why +   this function is not marked with __THROW.  */ +extern int pthread_once (pthread_once_t *__once_control, +			 void (*__init_routine) (void)); + + +/* Functions for handling cancellation.  */ + +/* Set cancelability state of current thread to STATE, returning old +   state in *OLDSTATE if OLDSTATE is not NULL.  */ +extern int pthread_setcancelstate (int __state, int *__oldstate); + +/* Set cancellation state of current thread to TYPE, returning the old +   type in *OLDTYPE if OLDTYPE is not NULL.  */ +extern int pthread_setcanceltype (int __type, int *__oldtype); + +/* Cancel THREAD immediately or at the next possibility.  */ +extern int pthread_cancel (pthread_t __cancelthread); + +/* Test for pending cancellation for the current thread and terminate +   the thread as per pthread_exit(PTHREAD_CANCELED) if it has been +   cancelled.  */ +extern void pthread_testcancel (void); + + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG +   when the thread is cancelled or calls pthread_exit.  ROUTINE will also +   be called with arguments ARG when the matching pthread_cleanup_pop +   is executed with non-zero EXECUTE argument. +   pthread_cleanup_push and pthread_cleanup_pop are macros and must always +   be used in matching pairs at the same nesting level of braces. */ + +#define pthread_cleanup_push(routine,arg) \ +  { struct _pthread_cleanup_buffer _buffer;				      \ +    _pthread_cleanup_push (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, +				   void (*__routine) (void *), +				   void *__arg) __THROW; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. +   If EXECUTE is non-zero, the handler function is called. */ + +#define pthread_cleanup_pop(execute) \ +    _pthread_cleanup_pop (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, +				  int __execute) __THROW; + +/* Install a cleanup handler as pthread_cleanup_push does, but also +   saves the current cancellation type and set it to deferred cancellation.  */ + +#ifdef __USE_GNU +# define pthread_cleanup_push_defer_np(routine,arg) \ +  { struct _pthread_cleanup_buffer _buffer;				      \ +    _pthread_cleanup_push_defer (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer, +					 void (*__routine) (void *), +					 void *__arg) __THROW; + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also +   restores the cancellation type that was in effect when the matching +   pthread_cleanup_push_defer was called.  */ + +# define pthread_cleanup_pop_restore_np(execute) \ +  _pthread_cleanup_pop_restore (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer, +					  int __execute) __THROW; +#endif + + +#ifdef __USE_XOPEN2K +/* Get ID of CPU-time clock for thread THREAD_ID.  */ +extern int pthread_getcpuclockid (pthread_t __thread_id, +				  __clockid_t *__clock_id) __THROW; +#endif + + +/* Functions for handling signals.  */ +#include <bits/sigthread.h> + + +/* Functions for handling process creation and process execution.  */ + +/* Install handlers to be called when a new process is created with FORK. +   The PREPARE handler is called in the parent process just before performing +   FORK. The PARENT handler is called in the parent process just after FORK. +   The CHILD handler is called in the child process.  Each of the three +   handlers can be NULL, meaning that no handler needs to be called at that +   point. +   PTHREAD_ATFORK can be called several times, in which case the PREPARE +   handlers are called in LIFO order (last added with PTHREAD_ATFORK, +   first called before FORK), and the PARENT and CHILD handlers are called +   in FIFO (first added, first called).  */ + +extern int pthread_atfork (void (*__prepare) (void), +			   void (*__parent) (void), +			   void (*__child) (void)) __THROW; + +/* Terminate all threads in the program except the calling process. +   Should be called just before invoking one of the exec*() functions.  */ + +extern void pthread_kill_other_threads_np (void) __THROW; + +__END_DECLS + +#endif	/* pthread.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c b/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c new file mode 100644 index 000000000..a2a56b8d9 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/ptlongjmp.c @@ -0,0 +1,39 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix        */ +/* threads for Linux.                                                   */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */ +/*                                                                      */ +/* This program is free software; you can redistribute it and/or        */ +/* modify it under the terms of the GNU Library General Public License  */ +/* as published by the Free Software Foundation; either version 2       */ +/* of the License, or (at your option) any later version.               */ +/*                                                                      */ +/* This program is distributed in the hope that it will be useful,      */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of       */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */ +/* GNU Library General Public License for more details.                 */ + +/* Redefine siglongjmp and longjmp so that they interact correctly +   with cleanup handlers */ + +#include <setjmp.h> +#include "pthread.h" +#include "internals.h" + +/* These functions are not declared anywhere since they shouldn't be +   used at another place but here.  */ +extern void __libc_siglongjmp (sigjmp_buf env, int val) +     __attribute__ ((noreturn)); +extern void __libc_longjmp (sigjmp_buf env, int val) +     __attribute__ ((noreturn)); + +#ifdef SHARED +void siglongjmp (sigjmp_buf env, int val) +{ +  __libc_siglongjmp (env, val); +} + +void longjmp (jmp_buf env, int val) +{ +  __libc_longjmp (env, val); +} +#endif diff --git a/libpthread/linuxthreads/sysdeps/pthread/res-state.c b/libpthread/linuxthreads/sysdeps/pthread/res-state.c new file mode 100644 index 000000000..016e20b4e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/res-state.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1996, 97, 98, 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <resolv.h> +#include <tls.h> +#include <linuxthreads/internals.h> +#include <sysdep-cancel.h> + +#if ! USE___THREAD +# undef _res +extern struct __res_state _res; +#endif + +/* When threaded, _res may be a per-thread variable.  */ +struct __res_state * +#if ! USE___THREAD +weak_const_function +#endif +__res_state (void) +{ +#if ! USE___THREAD +  if (! SINGLE_THREAD_P) +    { +      pthread_descr self = thread_self(); +      return LIBC_THREAD_GETMEM (self, p_resp); +    } +  return &_res; +#else +  return __resp; +#endif +} +libc_hidden_def (__res_state) diff --git a/libpthread/linuxthreads/sysdeps/pthread/semaphore.h b/libpthread/linuxthreads/sysdeps/pthread/semaphore.h new file mode 100644 index 000000000..8793768a8 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/semaphore.h @@ -0,0 +1 @@ +#include <linuxthreads/semaphore.h> diff --git a/libpthread/linuxthreads/sysdeps/pthread/sigaction.c b/libpthread/linuxthreads/sysdeps/pthread/sigaction.c new file mode 100644 index 000000000..0a0a9e29f --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/sigaction.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* This is tricky.  GCC doesn't like #include_next in the primary +   source file and even if it did, the first #include_next is this +   exact file anyway.  */ +#ifndef LIBC_SIGACTION + +# include <bits/libc-lock.h> + +# define LIBC_SIGACTION	1 + +# include "sigaction.c" + +# ifndef NOT_IN_libc +#  ifndef SHARED +weak_extern (__pthread_sigaction) +#  endif + +int +__sigaction (sig, act, oact) +     int sig; +     const struct sigaction *act; +     struct sigaction *oact; +{ +  return __libc_maybe_call2 (pthread_sigaction, (sig, act, oact), +			     __libc_sigaction (sig, act, oact)); +} +# else +weak_alias (__libc_sigaction, __sigaction) +# endif +libc_hidden_weak (__sigaction) +weak_alias (__sigaction, sigaction) + +#else + +# include_next <sigaction.c> + +#endif /* LIBC_SIGACTION */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h b/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h new file mode 100644 index 000000000..3fe13702e --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/tcb-offsets.h @@ -0,0 +1 @@ +/* This is overridden by generated tcb-offsets.h on arches which need it.  */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_create.c b/libpthread/linuxthreads/sysdeps/pthread/timer_create.c new file mode 100644 index 000000000..7f7e886c8 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_create.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include <time.h> +#include <unistd.h> + +#include "posix-timer.h" + + +/* Create new per-process timer using CLOCK.  */ +int +timer_create (clock_id, evp, timerid) +     clockid_t clock_id; +     struct sigevent *evp; +     timer_t *timerid; +{ +  int retval = -1; +  struct timer_node *newtimer = NULL; +  struct thread_node *thread = NULL; + +  if (0 +#ifdef _POSIX_CPUTIME +      || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#ifdef _POSIX_THREAD_CPUTIME +      || clock_id == CLOCK_THREAD_CPUTIME_ID +#endif +      ) +    { +      /* We don't allow timers for CPU clocks.  At least not in the +	 moment.  */ +      __set_errno (ENOTSUP); +      return -1; +    } + +  if (clock_id != CLOCK_REALTIME) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  pthread_once (&__timer_init_once_control, __timer_init_once); + +  if (__timer_init_failed) +    { +      __set_errno (ENOMEM); +      return -1; +    } + +  pthread_mutex_lock (&__timer_mutex); + +  newtimer = __timer_alloc (); +  if (__builtin_expect (newtimer == NULL, 0)) +    { +      __set_errno (EAGAIN); +      goto unlock_bail; +    } + +  if (evp != NULL) +    newtimer->event = *evp; +  else +    { +      newtimer->event.sigev_notify = SIGEV_SIGNAL; +      newtimer->event.sigev_signo = SIGALRM; +      newtimer->event.sigev_value.sival_int = timer_ptr2id (newtimer); +      newtimer->event.sigev_notify_function = 0; +    } + +  newtimer->event.sigev_notify_attributes = &newtimer->attr; +  newtimer->creator_pid = getpid (); + +  switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) +    { +    case SIGEV_NONE: +    case SIGEV_SIGNAL: +      /* We have a global thread for delivering timed signals. +	 If it is not running, try to start it up.  */ +      thread = &__timer_signal_thread_rclk; +      if (! thread->exists) +	{ +	  if (__builtin_expect (__timer_thread_start (thread), +				1) < 0) +	    { +	      __set_errno (EAGAIN); +	      goto unlock_bail; +            } +        } +      break; + +    case SIGEV_THREAD: +      /* Copy over thread attributes or set up default ones.  */ +      if (evp->sigev_notify_attributes) +	newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; +      else +	pthread_attr_init (&newtimer->attr); + +      /* Ensure thread attributes call for deatched thread.  */ +      pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); + +      /* Try to find existing thread having the right attributes.  */ +      thread = __timer_thread_find_matching (&newtimer->attr, clock_id); + +      /* If no existing thread has these attributes, try to allocate one.  */ +      if (thread == NULL) +	thread = __timer_thread_alloc (&newtimer->attr, clock_id); + +      /* Out of luck; no threads are available.  */ +      if (__builtin_expect (thread == NULL, 0)) +	{ +	  __set_errno (EAGAIN); +	  goto unlock_bail; +	} + +      /* If the thread is not running already, try to start it.  */ +      if (! thread->exists +	  && __builtin_expect (! __timer_thread_start (thread), 0)) +	{ +	  __set_errno (EAGAIN); +	  goto unlock_bail; +	} +      break; + +    default: +      __set_errno (EINVAL); +      goto unlock_bail; +    } + +  newtimer->clock = clock_id; +  newtimer->abstime = 0; +  newtimer->armed = 0; +  newtimer->thread = thread; + +  *timerid = timer_ptr2id (newtimer); +  retval = 0; + +  if (__builtin_expect (retval, 0) == -1) +    { +    unlock_bail: +      if (thread != NULL) +	__timer_thread_dealloc (thread); +      if (newtimer != NULL) +	{ +	  timer_delref (newtimer); +	  __timer_dealloc (newtimer); +	} +    } + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c b/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c new file mode 100644 index 000000000..48ba1f272 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_delete.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID.  */ +int +timer_delete (timerid) +     timer_t timerid; +{ +  struct timer_node *timer; +  int retval = -1; + +  pthread_mutex_lock (&__timer_mutex); + +  timer = timer_id2ptr (timerid); +  if (! timer_valid (timer)) +    /* Invalid timer ID or the timer is not in use.  */ +    __set_errno (EINVAL); +  else +    { +      if (timer->armed && timer->thread != NULL) +	{ +	  struct thread_node *thread = timer->thread; +	  assert (thread != NULL); + +	  /* If thread is cancelled while waiting for handler to terminate, +	     the mutex is unlocked and timer_delete is aborted.  */ +	  pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); + +	  /* If timer is currently being serviced, wait for it to finish.  */ +	  while (thread->current_timer == timer) +	    pthread_cond_wait (&thread->cond, &__timer_mutex); + +	  pthread_cleanup_pop (0); +        } + +      /* Remove timer from whatever queue it may be on and deallocate it.  */ +      timer->inuse = TIMER_DELETED; +      list_unlink_ip (&timer->links); +      timer_delref (timer); +      retval = 0; +    } + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c b/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c new file mode 100644 index 000000000..f3e22215b --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get expiration overrun for timer TIMERID.  */ +int +timer_getoverrun (timerid) +     timer_t timerid; +{ +  struct timer_node *timer; +  int retval = -1; + +  pthread_mutex_lock (&__timer_mutex); + +  if (! timer_valid (timer = timer_id2ptr (timerid))) +    __set_errno (EINVAL); +  else +    retval = timer->overrun_count; + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c b/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c new file mode 100644 index 000000000..723a61632 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_gettime.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2000, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Get current value of timer TIMERID and store it in VLAUE.  */ +int +timer_gettime (timerid, value) +     timer_t timerid; +     struct itimerspec *value; +{ +  struct timer_node *timer; +  struct timespec now, expiry; +  int retval = -1, armed = 0, valid; +  clock_t clock = 0; + +  pthread_mutex_lock (&__timer_mutex); + +  timer = timer_id2ptr (timerid); +  valid = timer_valid (timer); + +  if (valid) { +    armed = timer->armed; +    expiry = timer->expirytime; +    clock = timer->clock; +    value->it_interval = timer->value.it_interval; +  } + +  pthread_mutex_unlock (&__timer_mutex); + +  if (valid) +    { +      if (armed) +	{ +	  clock_gettime (clock, &now); +	  if (timespec_compare (&now, &expiry) < 0) +	    timespec_sub (&value->it_value, &expiry, &now); +	  else +	    { +	      value->it_value.tv_sec = 0; +	      value->it_value.tv_nsec = 0; +	    } +	} +      else +	{ +	  value->it_value.tv_sec = 0; +	  value->it_value.tv_nsec = 0; +	} + +      retval = 0; +    } +  else +    __set_errno (EINVAL); + +  return retval; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c b/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c new file mode 100644 index 000000000..3877b86fb --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_routines.c @@ -0,0 +1,573 @@ +/* Helper code for POSIX timer implementation on LinuxThreads. +   Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include "posix-timer.h" + + +/* Number of threads used.  */ +#define THREAD_MAXNODES	16 + +/* Array containing the descriptors for the used threads.  */ +static struct thread_node thread_array[THREAD_MAXNODES]; + +/* Static array with the structures for all the timers.  */ +struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists.  */ +pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Variable to protext initialization.  */ +pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT; + +/* Nonzero if initialization of timer implementation failed.  */ +int __timer_init_failed; + +/* Node for the thread used to deliver signals.  */ +struct thread_node __timer_signal_thread_rclk; + +/* Lists to keep free and used timers and threads.  */ +struct list_links timer_free_list; +struct list_links thread_free_list; +struct list_links thread_active_list; + + +#ifdef __NR_rt_sigqueueinfo +extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *); +#endif + + +/* List handling functions.  */ +static inline void +list_init (struct list_links *list) +{ +  list->next = list->prev = list; +} + +static inline void +list_append (struct list_links *list, struct list_links *newp) +{ +  newp->prev = list->prev; +  newp->next = list; +  list->prev->next = newp; +  list->prev = newp; +} + +static inline void +list_insbefore (struct list_links *list, struct list_links *newp) +{ +  list_append (list, newp); +} + +/* + * Like list_unlink_ip, except that calling it on a node that + * is already unlinked is disastrous rather than a noop. + */ + +static inline void +list_unlink (struct list_links *list) +{ +  struct list_links *lnext = list->next, *lprev = list->prev; + +  lnext->prev = lprev; +  lprev->next = lnext; +} + +static inline struct list_links * +list_first (struct list_links *list) +{ +  return list->next; +} + +static inline struct list_links * +list_null (struct list_links *list) +{ +  return list; +} + +static inline struct list_links * +list_next (struct list_links *list) +{ +  return list->next; +} + +static inline int +list_isempty (struct list_links *list) +{ +  return list->next == list; +} + + +/* Functions build on top of the list functions.  */ +static inline struct thread_node * +thread_links2ptr (struct list_links *list) +{ +  return (struct thread_node *) ((char *) list +				 - offsetof (struct thread_node, links)); +} + +static inline struct timer_node * +timer_links2ptr (struct list_links *list) +{ +  return (struct timer_node *) ((char *) list +				- offsetof (struct timer_node, links)); +} + + +/* Initialize a newly allocated thread structure.  */ +static void +thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id) +{ +  if (attr != NULL) +    thread->attr = *attr; +  else +    { +      pthread_attr_init (&thread->attr); +      pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED); +    } + +  thread->exists = 0; +  list_init (&thread->timer_queue); +  pthread_cond_init (&thread->cond, 0); +  thread->current_timer = 0; +  thread->captured = pthread_self (); +  thread->clock_id = clock_id; +} + + +/* Initialize the global lists, and acquire global resources.  Error +   reporting is done by storing a non-zero value to the global variable +   timer_init_failed.  */ +static void +init_module (void) +{ +  int i; + +  list_init (&timer_free_list); +  list_init (&thread_free_list); +  list_init (&thread_active_list); + +  for (i = 0; i < TIMER_MAX; ++i) +    { +      list_append (&timer_free_list, &__timer_array[i].links); +      __timer_array[i].inuse = TIMER_FREE; +    } + +  for (i = 0; i < THREAD_MAXNODES; ++i) +    list_append (&thread_free_list, &thread_array[i].links); + +  thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME); +} + + +/* This is a handler executed in a child process after a fork() +   occurs.  It reinitializes the module, resetting all of the data +   structures to their initial state.  The mutex is initialized in +   case it was locked in the parent process.  */ +static void +reinit_after_fork (void) +{ +  init_module (); +  pthread_mutex_init (&__timer_mutex, 0); +} + + +/* Called once form pthread_once in timer_init. This initializes the +   module and ensures that reinit_after_fork will be executed in any +   child process.  */ +void +__timer_init_once (void) +{ +  init_module (); +  pthread_atfork (0, 0, reinit_after_fork); +} + + +/* Deinitialize a thread that is about to be deallocated.  */ +static void +thread_deinit (struct thread_node *thread) +{ +  assert (list_isempty (&thread->timer_queue)); +  pthread_cond_destroy (&thread->cond); +} + + +/* Allocate a thread structure from the global free list.  Global +   mutex lock must be held by caller.  The thread is moved to +   the active list. */ +struct thread_node * +__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id) +{ +  struct list_links *node = list_first (&thread_free_list); + +  if (node != list_null (&thread_free_list)) +    { +      struct thread_node *thread = thread_links2ptr (node); +      list_unlink (node); +      thread_init (thread, desired_attr, clock_id); +      list_append (&thread_active_list, node); +      return thread; +    } + +  return 0; +} + + +/* Return a thread structure to the global free list.  Global lock +   must be held by caller.  */ +void +__timer_thread_dealloc (struct thread_node *thread) +{ +  thread_deinit (thread); +  list_unlink (&thread->links); +  list_append (&thread_free_list, &thread->links); +} + + +/* Each of our threads which terminates executes this cleanup +   handler. We never terminate threads ourselves; if a thread gets here +   it means that the evil application has killed it.  If the thread has +   timers, these require servicing and so we must hire a replacement +   thread right away.  We must also unblock another thread that may +   have been waiting for this thread to finish servicing a timer (see +   timer_delete()).  */ + +static void +thread_cleanup (void *val) +{ +  if (val != NULL) +    { +      struct thread_node *thread = val; + +      /* How did the signal thread get killed?  */ +      assert (thread != &__timer_signal_thread_rclk); + +      pthread_mutex_lock (&__timer_mutex); + +      thread->exists = 0; + +      /* We are no longer processing a timer event.  */ +      thread->current_timer = 0; + +      if (list_isempty (&thread->timer_queue)) +	  __timer_thread_dealloc (thread); +      else +	(void) __timer_thread_start (thread); + +      pthread_mutex_unlock (&__timer_mutex); + +      /* Unblock potentially blocked timer_delete().  */ +      pthread_cond_broadcast (&thread->cond); +    } +} + + +/* Handle a timer which is supposed to go off now.  */ +static void +thread_expire_timer (struct thread_node *self, struct timer_node *timer) +{ +  self->current_timer = timer; /* Lets timer_delete know timer is running. */ + +  pthread_mutex_unlock (&__timer_mutex); + +  switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL)) +    { +    case SIGEV_NONE: +      break; + +    case SIGEV_SIGNAL: +#ifdef __NR_rt_sigqueueinfo +      { +	siginfo_t info; + +	/* First, clear the siginfo_t structure, so that we don't pass our +	   stack content to other tasks.  */ +	memset (&info, 0, sizeof (siginfo_t)); +	/* We must pass the information about the data in a siginfo_t +           value.  */ +	info.si_signo = timer->event.sigev_signo; +	info.si_code = SI_TIMER; +	info.si_pid = timer->creator_pid; +	info.si_uid = getuid (); +	info.si_value = timer->event.sigev_value; + +	INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info); +      } +#else +      if (pthread_kill (self->captured, timer->event.sigev_signo) != 0) +	{ +	  if (pthread_kill (self->id, timer->event.sigev_signo) != 0) +	    abort (); +        } +#endif +      break; + +    case SIGEV_THREAD: +      timer->event.sigev_notify_function (timer->event.sigev_value); +      break; + +    default: +      assert (! "unknown event"); +      break; +    } + +  pthread_mutex_lock (&__timer_mutex); + +  self->current_timer = 0; + +  pthread_cond_broadcast (&self->cond); +} + + +/* Thread function; executed by each timer thread. The job of this +   function is to wait on the thread's timer queue and expire the +   timers in chronological order as close to their scheduled time as +   possible.  */ +static void +__attribute__ ((noreturn)) +thread_func (void *arg) +{ +  struct thread_node *self = arg; + +  /* Register cleanup handler, in case rogue application terminates +     this thread.  (This cannot happen to __timer_signal_thread, which +     doesn't invoke application callbacks). */ + +  pthread_cleanup_push (thread_cleanup, self); + +  pthread_mutex_lock (&__timer_mutex); + +  while (1) +    { +      struct list_links *first; +      struct timer_node *timer = NULL; + +      /* While the timer queue is not empty, inspect the first node.  */ +      first = list_first (&self->timer_queue); +      if (first != list_null (&self->timer_queue)) +	{ +	  struct timespec now; + +	  timer = timer_links2ptr (first); + +	  /* This assumes that the elements of the list of one thread +	     are all for the same clock.  */ +	  clock_gettime (timer->clock, &now); + +	  while (1) +	    { +	      /* If the timer is due or overdue, remove it from the queue. +		 If it's a periodic timer, re-compute its new time and +		 requeue it.  Either way, perform the timer expiry. */ +	      if (timespec_compare (&now, &timer->expirytime) < 0) +		break; + +	      list_unlink_ip (first); + +	      if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0 +		  || timer->value.it_interval.tv_nsec != 0) +		{ +		  timer->overrun_count = 0; +		  timespec_add (&timer->expirytime, &timer->expirytime, +				&timer->value.it_interval); +		  while (timespec_compare (&timer->expirytime, &now) < 0) +		    { +		      timespec_add (&timer->expirytime, &timer->expirytime, +				    &timer->value.it_interval); +		      if (timer->overrun_count < DELAYTIMER_MAX) +			++timer->overrun_count; +		    } +		  __timer_thread_queue_timer (self, timer); +		} + +	      thread_expire_timer (self, timer); + +	      first = list_first (&self->timer_queue); +	      if (first == list_null (&self->timer_queue)) +		break; + +	      timer = timer_links2ptr (first); +	    } +	} + +      /* If the queue is not empty, wait until the expiry time of the +	 first node.  Otherwise wait indefinitely.  Insertions at the +	 head of the queue must wake up the thread by broadcasting +	 this condition variable.  */ +      if (timer != NULL) +	pthread_cond_timedwait (&self->cond, &__timer_mutex, +				&timer->expirytime); +      else +	pthread_cond_wait (&self->cond, &__timer_mutex); +    } +  /* This macro will never be executed since the while loop loops +     forever - but we have to add it for proper nesting.  */ +  pthread_cleanup_pop (1); +} + + +/* Enqueue a timer in wakeup order in the thread's timer queue. +   Returns 1 if the timer was inserted at the head of the queue, +   causing the queue's next wakeup time to change. */ + +int +__timer_thread_queue_timer (struct thread_node *thread, +			    struct timer_node *insert) +{ +  struct list_links *iter; +  int athead = 1; + +  for (iter = list_first (&thread->timer_queue); +       iter != list_null (&thread->timer_queue); +        iter = list_next (iter)) +    { +      struct timer_node *timer = timer_links2ptr (iter); + +      if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0) +	  break; +      athead = 0; +    } + +  list_insbefore (iter, &insert->links); +  return athead; +} + + +/* Start a thread and associate it with the given thread node.  Global +   lock must be held by caller.  */ +int +__timer_thread_start (struct thread_node *thread) +{ +  int retval = 1; + +  assert (!thread->exists); +  thread->exists = 1; + +  if (pthread_create (&thread->id, &thread->attr, +		      (void *(*) (void *)) thread_func, thread) != 0) +    { +      thread->exists = 0; +      retval = -1; +    } + +  return retval; +} + + +void +__timer_thread_wakeup (struct thread_node *thread) +{ +  pthread_cond_broadcast (&thread->cond); +} + + +/* Compare two pthread_attr_t thread attributes for exact equality. +   Returns 1 if they are equal, otherwise zero if they are not equal or +   contain illegal values.  This version is LinuxThreads-specific for +   performance reason.  One could use the access functions to get the +   values of all the fields of the attribute structure.  */ +static int +thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right) +{ +  return (left->__detachstate == right->__detachstate +	  && left->__schedpolicy == right->__schedpolicy +	  && left->__guardsize == right->__guardsize +	  && (left->__schedparam.sched_priority +	      == right->__schedparam.sched_priority) +	  && left->__inheritsched == right->__inheritsched +	  && left->__scope == right->__scope +	  && left->__stacksize == right->__stacksize +	  && left->__stackaddr_set == right->__stackaddr_set +	  && (left->__stackaddr_set +	      || left->__stackaddr == right->__stackaddr)); +} + + +/* Search the list of active threads and find one which has matching +   attributes.  Global mutex lock must be held by caller.  */ +struct thread_node * +__timer_thread_find_matching (const pthread_attr_t *desired_attr, +			      clockid_t desired_clock_id) +{ +  struct list_links *iter = list_first (&thread_active_list); + +  while (iter != list_null (&thread_active_list)) +    { +      struct thread_node *candidate = thread_links2ptr (iter); + +      if (thread_attr_compare (desired_attr, &candidate->attr) +	  && desired_clock_id == candidate->clock_id) +	return candidate; + +      iter = list_next (iter); +    } + +  return NULL; +} + + +/* Grab a free timer structure from the global free list.  The global +   lock must be held by the caller.  */ +struct timer_node * +__timer_alloc (void) +{ +  struct list_links *node = list_first (&timer_free_list); + +  if (node != list_null (&timer_free_list)) +    { +      struct timer_node *timer = timer_links2ptr (node); +      list_unlink_ip (node); +      timer->inuse = TIMER_INUSE; +      timer->refcount = 1; +      return timer; +    } + +  return NULL; +} + + +/* Return a timer structure to the global free list.  The global lock +   must be held by the caller.  */ +void +__timer_dealloc (struct timer_node *timer) +{ +  assert (timer->refcount == 0); +  timer->thread = NULL;	/* Break association between timer and thread.  */ +  timer->inuse = TIMER_FREE; +  list_append (&timer_free_list, &timer->links); +} + + +/* Thread cancellation handler which unlocks a mutex.  */ +void +__timer_mutex_cancel_handler (void *arg) +{ +  pthread_mutex_unlock (arg); +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c b/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c new file mode 100644 index 000000000..592b5271b --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/timer_settime.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Set timer TIMERID to VALUE, returning old value in OVLAUE.  */ +int +timer_settime (timerid, flags, value, ovalue) +     timer_t timerid; +     int flags; +     const struct itimerspec *value; +     struct itimerspec *ovalue; +{ +  struct timer_node *timer; +  struct thread_node *thread = NULL; +  struct timespec now; +  int have_now = 0, need_wakeup = 0; +  int retval = -1; + +  timer = timer_id2ptr (timerid); +  if (timer == NULL) +    { +      __set_errno (EINVAL); +      goto bail; +    } + +  if (value->it_interval.tv_nsec < 0 +      || value->it_interval.tv_nsec >= 1000000000 +      || value->it_value.tv_nsec < 0 +      || value->it_value.tv_nsec >= 1000000000) +    { +      __set_errno (EINVAL); +      goto bail; +    } + +  /* Will need to know current time since this is a relative timer; +     might as well make the system call outside of the lock now! */ + +  if ((flags & TIMER_ABSTIME) == 0) +    { +      clock_gettime (timer->clock, &now); +      have_now = 1; +    } + +  pthread_mutex_lock (&__timer_mutex); +  timer_addref (timer); + +  /* One final check of timer validity; this one is possible only +     until we have the mutex, because it accesses the inuse flag. */ + +  if (! timer_valid(timer)) +    { +      __set_errno (EINVAL); +      goto unlock_bail; +    } + +  if (ovalue != NULL) +    { +      ovalue->it_interval = timer->value.it_interval; + +      if (timer->armed) +	{ +	  if (! have_now) +	    { +	      pthread_mutex_unlock (&__timer_mutex); +	      clock_gettime (timer->clock, &now); +	      have_now = 1; +	      pthread_mutex_lock (&__timer_mutex); +	      timer_addref (timer); +	    } + +	  timespec_sub (&ovalue->it_value, &timer->expirytime, &now); +	} +      else +	{ +	  ovalue->it_value.tv_sec = 0; +	  ovalue->it_value.tv_nsec = 0; +	} +    } + +  timer->value = *value; + +  list_unlink_ip (&timer->links); +  timer->armed = 0; + +  thread = timer->thread; + +  /* A value of { 0, 0 } causes the timer to be stopped. */ +  if (value->it_value.tv_sec != 0 +      || __builtin_expect (value->it_value.tv_nsec != 0, 1)) +    { +      if ((flags & TIMER_ABSTIME) != 0) +	/* The user specified the expiration time.  */ +	timer->expirytime = value->it_value; +      else +	timespec_add (&timer->expirytime, &now, &value->it_value); + +      /* Only need to wake up the thread if timer is inserted +	 at the head of the queue. */ +      if (thread != NULL) +	need_wakeup = __timer_thread_queue_timer (thread, timer); +      timer->armed = 1; +    } + +  retval = 0; + +unlock_bail: +  timer_delref (timer); +  pthread_mutex_unlock (&__timer_mutex); + +bail: +  if (thread != NULL && need_wakeup) +    __timer_thread_wakeup (thread); + +  return retval; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c b/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c new file mode 100644 index 000000000..7417bcd5f --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/tst-timer.c @@ -0,0 +1,114 @@ +/* Tests for POSIX timer implementation. +   Copyright (C) 2000, 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +static void +notify_func (union sigval sigval) +{ +  puts ("notify_func"); +} + + +static void +signal_func (int sig) +{ +  static const char text[] = "signal_func\n"; +  signal (sig, signal_func); +  write (STDOUT_FILENO, text, sizeof text - 1); +} + +static void +intr_sleep (int sec) +{ +  struct timespec ts; + +  ts.tv_sec = sec; +  ts.tv_nsec = 0; + +  while (nanosleep (&ts, &ts) == -1 && errno == EINTR) +    ; +} + +#define ZSIGALRM 14 + + +int +main (void) +{ +  struct timespec ts; +  timer_t timer_sig, timer_thr1, timer_thr2; +  int retval; +  struct sigevent sigev1 = +  { +    .sigev_notify = SIGEV_SIGNAL, +    .sigev_signo = ZSIGALRM +  }; +  struct sigevent sigev2; +  struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } }; +  struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } }; +  struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } }; +  struct itimerspec old; + +  retval = clock_gettime (CLOCK_REALTIME, &ts); + +  sigev2.sigev_notify = SIGEV_THREAD; +  sigev2.sigev_notify_function = notify_func; +  sigev2.sigev_notify_attributes = NULL; + +  setvbuf (stdout, 0, _IOLBF, 0); + +  printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n", +	  retval, ts.tv_sec, ts.tv_nsec); + +  retval = clock_getres (CLOCK_REALTIME, &ts); + +  printf ("clock_getres returned %d, timespec = { %ld, %ld }\n", +	  retval, ts.tv_sec, ts.tv_nsec); + +  timer_create (CLOCK_REALTIME, &sigev1, &timer_sig); +  timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1); +  timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2); + +  timer_settime (timer_thr1, 0, &itimer2, &old); +  timer_settime (timer_thr2, 0, &itimer3, &old); + +  signal (ZSIGALRM, signal_func); + +  timer_settime (timer_sig, 0, &itimer1, &old); + +  timer_delete (-1); + +  intr_sleep (3); + +  timer_delete (timer_sig); +  timer_delete (timer_thr1); + +  intr_sleep (3); + +  timer_delete (timer_thr2); + +  return 0; +} diff --git a/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h b/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h new file mode 100644 index 000000000..803466de1 --- /dev/null +++ b/libpthread/linuxthreads/sysdeps/pthread/uClibc-glue.h @@ -0,0 +1,50 @@ +#ifndef _UCLIBC_GLUE_H +#define _UCLIBC_GLUE_H 1 + +#include <features.h> +#include <sys/cdefs.h> +#include <bits/uClibc_page.h> + +#if IS_IN_linuxthreads +#include "kernel-features.h" + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#ifndef __GLIBC_HAVE_LONG_LONG +# define __GLIBC_HAVE_LONG_LONG +#endif + +#ifndef __UCLIBC_HAS_XLOCALE__ +# define __uselocale(x) +#endif + +#define __getpagesize getpagesize +#define __sched_get_priority_max sched_get_priority_max +#define __sched_get_priority_min sched_get_priority_min +#define __sched_getscheduler sched_getscheduler +#define __sched_setscheduler sched_setscheduler +#define __sched_getparam sched_getparam +#define __getpid getpid +#define __gettimeofday gettimeofday +#define __poll poll +#define __sysctl sysctl +#define __open open +#define __read read +#define __close close +#define __on_exit on_exit +#define __libc_current_sigrtmin_private __libc_current_sigrtmin + +extern void *__libc_stack_end; +extern int __cxa_atexit (void (*func) (void *), void *arg, void *d); + +#endif /* IS_IN_linuxthreads */ + +/* Use a funky version in a probably vein attempt at preventing gdb  + * from dlopen()'ing glibc's libthread_db library... */ +#define STRINGIFY(s) STRINGIFY2 (s) +#define STRINGIFY2(s) #s +#define VERSION STRINGIFY(__UCLIBC_MAJOR__) "." STRINGIFY(__UCLIBC_MINOR__) "." STRINGIFY(__UCLIBC_SUBLEVEL__) + +#endif | 
