diff --git a/Makefile b/Makefile index bfdae7b..736be38 100644 --- a/Makefile +++ b/Makefile @@ -132,7 +132,6 @@ libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate \ pt-sysdep \ pt-setup \ pt-machdep \ - pt-spin \ \ pt-sigstate-init \ pt-sigstate-destroy \ @@ -184,7 +183,8 @@ headers := \ bits/mutex-attr.h \ bits/rwlock.h \ bits/rwlock-attr.h \ - bits/semaphore.h + bits/semaphore.h \ + bits/xint.h ifeq ($(IN_GLIBC),yes) distribute := diff --git a/forward.c b/forward.c index 771b3ca..733af27 100644 --- a/forward.c +++ b/forward.c @@ -151,8 +151,7 @@ struct atfork { struct atfork *next; }; -/* TODO: better locking */ -static struct mutex atfork_lock; +static unsigned int atfork_lock = LLL_INITIALIZER; static struct atfork *fork_handlers, *fork_last_handler; static void diff --git a/pthread/cthreads-compat.c b/pthread/cthreads-compat.c index 1a0971b..1e82a8f 100644 --- a/pthread/cthreads-compat.c +++ b/pthread/cthreads-compat.c @@ -85,17 +85,3 @@ cthread_setspecific (cthread_key_t key, void *val) return err; } -void -__mutex_lock_solid (void *lock) -{ - __pthread_mutex_lock (lock); -} - -void -__mutex_unlock_solid (void *lock) -{ - if (__pthread_spin_trylock (lock) != 0) - /* Somebody already got the lock, that one will manage waking up others */ - return; - __pthread_mutex_unlock (lock); -} diff --git a/pthread/pt-create.c b/pthread/pt-create.c index 84044dc..7a27b29 100644 --- a/pthread/pt-create.c +++ b/pthread/pt-create.c @@ -1,5 +1,5 @@ /* Thread creation. - Copyright (C) 2000, 2002, 2005, 2007 Free Software Foundation, Inc. + Copyright (C) 2000-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -38,7 +38,7 @@ /* The total number of pthreads currently active. This is defined here since it would be really stupid to have a threads-using program that doesn't call `pthread_create'. */ -__atomic_t __pthread_total; +int __pthread_total; /* The entry-point for new threads. */ @@ -196,7 +196,7 @@ __pthread_create_internal (struct __pthread **thread, the number of threads from within the new thread isn't an option since this thread might return and call `pthread_exit' before the new thread runs. */ - __atomic_inc (&__pthread_total); + atomic_increment (&__pthread_total); /* Store a pointer to this thread in the thread ID lookup table. We could use __thread_setid, however, we only lock for reading as no @@ -227,7 +227,7 @@ __pthread_create_internal (struct __pthread **thread, __pthread_dealloc (pthread); __pthread_setid (pthread->thread, NULL); - __atomic_dec (&__pthread_total); + atomic_decrement (&__pthread_total); failed_sigstate: __pthread_sigstate_destroy (pthread); failed_setup: diff --git a/pthread/pt-dealloc.c b/pthread/pt-dealloc.c index e324800..327d0dc 100644 --- a/pthread/pt-dealloc.c +++ b/pthread/pt-dealloc.c @@ -1,5 +1,5 @@ /* Deallocate a thread structure. - Copyright (C) 2000, 2008 Free Software Foundation, Inc. + Copyright (C) 2000-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -20,10 +20,8 @@ #include #include #include - #include - -#include +#include /* List of thread structures corresponding to free thread IDs. */ extern struct __pthread *__pthread_free_threads; @@ -36,7 +34,7 @@ __pthread_dealloc (struct __pthread *pthread) { assert (pthread->state != PTHREAD_TERMINATED); - if (! __atomic_dec_and_test (&pthread->nr_refs)) + if (!atomic_decrement_and_test (&pthread->nr_refs)) return; /* Withdraw this thread from the thread ID lookup table. */ diff --git a/pthread/pt-exit.c b/pthread/pt-exit.c index 3427de5..e7f89f2 100644 --- a/pthread/pt-exit.c +++ b/pthread/pt-exit.c @@ -21,11 +21,8 @@ #include #include #include - #include - -#include - +#include /* Terminate the current thread and make STATUS available to any thread that might join it. */ @@ -50,7 +47,7 @@ __pthread_exit (void *status) /* Decrease the number of threads. We use an atomic operation to make sure that only the last thread calls `exit'. */ - if (__atomic_dec_and_test (&__pthread_total)) + if (atomic_decrement_and_test (&__pthread_total)) /* We are the last thread. */ exit (0); diff --git a/pthread/pt-internal.h b/pthread/pt-internal.h index ec8daed..3028775 100644 --- a/pthread/pt-internal.h +++ b/pthread/pt-internal.h @@ -1,5 +1,5 @@ /* Internal defenitions for pthreads library. - Copyright (C) 2000, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2000-2016 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 @@ -28,8 +28,6 @@ #define __need_res_state #include -#include - #include #include @@ -39,6 +37,8 @@ # include #endif +#include + /* Thread state. */ enum pthread_state { @@ -60,25 +60,13 @@ enum pthread_state # define PTHREAD_SYSDEP_MEMBERS #endif -#ifndef IS_IN_libpthread -#ifdef ENABLE_TLS -/* Type of the TCB. */ -typedef struct -{ - void *tcb; /* Points to this structure. */ - void *dtv; /* Vector of pointers to TLS data. */ - thread_t self; /* This thread's control port. */ -} tcbhead_t; -#endif /* ENABLE_TLS */ -#endif /* IS_IN_libpthread */ - /* This structure describes a POSIX thread. */ struct __pthread { /* Thread ID. */ pthread_t thread; - __atomic_t nr_refs; /* Detached threads have a self reference only, + unsigned int nr_refs; /* Detached threads have a self reference only, while joinable threads have two references. These are used to keep the structure valid at thread destruction. Detaching/joining a thread @@ -173,7 +161,7 @@ __pthread_dequeue (struct __pthread *thread) ) /* The total number of threads currently active. */ -extern __atomic_t __pthread_total; +extern int __pthread_total; /* The total number of thread IDs currently in use, or on the list of available thread IDs. */ @@ -208,6 +196,17 @@ extern struct __pthread *_pthread_self (void); #endif +/* Start and end cancellation points. */ +#define __pthread_cancelpoint_begin() \ + ({ \ + int __prev; \ + __pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &__prev); \ + __prev; \ + }) + +#define __pthread_cancelpoint_end(prev) \ + __pthread_setcanceltype ((prev), 0) + /* Initialize the pthreads library. */ extern void ___pthread_init (void); diff --git a/sysdeps/i386/bits/pt-atomic.h b/sysdeps/i386/bits/pt-atomic.h index 0dfc1f6..6acd513 100644 --- a/sysdeps/i386/bits/pt-atomic.h +++ b/sysdeps/i386/bits/pt-atomic.h @@ -1,10 +1,10 @@ -/* Atomic operations. i386 version. - Copyright (C) 2000 Free Software Foundation, Inc. +/* Additional atomic operations. i386 version. + Copyright (C) 2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the + published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, @@ -20,47 +20,145 @@ #ifndef _BITS_ATOMIC_H #define _BITS_ATOMIC_H 1 -typedef __volatile int __atomic_t; - -static inline void -__atomic_inc (__atomic_t *__var) -{ - __asm__ __volatile ("lock; incl %0" : "=m" (*__var) : "m" (*__var)); -} - -static inline void -__atomic_dec (__atomic_t *__var) -{ - __asm__ __volatile ("lock; decl %0" : "=m" (*__var) : "m" (*__var)); -} - -static inline int -__atomic_dec_and_test (__atomic_t *__var) -{ - unsigned char __ret; - - __asm__ __volatile ("lock; decl %0; sete %1" - : "=m" (*__var), "=qm" (__ret) : "m" (*__var)); - return __ret != 0; -} - -/* We assume that an __atomicptr_t is only used for pointers to - word-aligned objects, and use the lowest bit for a simple lock. */ -typedef __volatile int * __atomicptr_t; - -/* Actually we don't implement that yet, and assume that we run on - something that has the i486 instruction set. */ -static inline int -__atomicptr_compare_and_swap (__atomicptr_t *__ptr, void *__oldval, - void * __newval) -{ - char __ret; - int __dummy; - - __asm__ __volatile ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (__ret), "=m" (*__ptr), "=a" (__dummy) - : "r" (__newval), "m" (*__ptr), "a" (__oldval)); - return __ret; -} +#include + +#ifndef LOCK_PREFIX +# define LOCK_PREFIX "lock;" +#endif + +#if defined (__PIC__) && __GNUC__ < 5 + + /* When PIC is turned on, the %ebx register is used to save + * the value of the GOT pointer. As such, we must preserve + * %ebx across calls. */ + + /* The above doesn't apply anymore for GCC 5+. */ + +# ifdef __OPTIMIZE__ + +# define atomic_casx_bool(ptr, elo, ehi, nlo, nhi) \ + ({ \ + long __s, __v = (nlo); \ + char __r; \ + __asm__ __volatile__ \ + ( \ + "movl %%ebx, %2\n\t" \ + "leal %0, %%edi\n\t" \ + "movl %7, %%ebx\n\t" \ + LOCK_PREFIX "cmpxchg8b (%%edi)\n\t" \ + "movl %2, %%ebx\n\t" \ + "setz %1" \ + : "=m" (*ptr), "=a" (__r), "=m" (__s) \ + : "m" (*ptr), "d" (ehi), "a" (elo), \ + "c" (nhi), "m" (__v) \ + : "%edi", "memory" \ + ); \ + (int)__r; \ + }) + +# else + + /* When using -O0, we have to preserve %edi, otherwise gcc + * fails while looking for a register in class 'GENERAL_REGS'. */ + +# define atomic_casx_bool(ptr, elo, ehi, nlo, nhi) \ + ({ \ + long __d, __s, __v = (nlo); \ + char __r; \ + __asm__ __volatile__ \ + ( \ + "movl %%edi, %3\n\t" \ + "movl %%ebx, %2\n\t" \ + "leal %0, %%edi\n\t" \ + "movl %8, %%ebx\n\t" \ + LOCK_PREFIX "cmpxchg8b (%%edi)\n\t" \ + "movl %2, %%ebx\n\t" \ + "movl %3, %%edi\n\t" \ + "setz %1" \ + : "=m" (*ptr), "=a" (__r), "=m" (__s), "=m" (__d) \ + : "m" (*ptr), "d" (ehi), "a" (elo), \ + "c" (nhi), "m" (__v) \ + : "memory" \ + ); \ + (int)__r; \ + }) + +# endif + +#else + + /* In non-PIC mode, or with a recent-enough gcc, we + * can use %ebx to load the lower word in NLO. */ + +# define atomic_casx_bool(ptr, elo, ehi, nlo, nhi) \ + ({ \ + char __r; \ + __asm__ __volatile__ \ + ( \ + LOCK_PREFIX "cmpxchg8b %0\n\t" \ + "setz %1" \ + : "+m" (*ptr), "=a" (__r) \ + : "a" (elo), "d" (ehi), \ + "b" (nlo), "c" (nhi) \ + : "memory" \ + ); \ + (int)__r; \ + }) + +#endif /* defined (__PIC__) && __GNUC__ < 5 */ + +/* Loads and stores for 64-bit values. */ + +/* Note that loading a 64-bit integer may be implemented in + * a non-atomic way. That's fine since in the vast mayority + * of cases, we'll do a CAS right away. */ + +#if __SSE2__ + + /* When SSE is enabled, we can use one of its registers + * to move around unaligned 64-bit values. */ + +# define atomic_loadx(ptr) \ + ({ \ + typeof (*ptr) __r; \ + __asm__ __volatile__ \ + ( \ + "movq %1, %0" \ + : "=x" (__r) : "m" (*ptr) : "memory" \ + ); \ + __r; \ + }) + +# define atomic_storex(dst, src) \ + ({ \ + __asm__ __volatile__ \ + ( \ + "movq %1, %0" \ + : "=m" (*dst) : "x" (src) : "memory" \ + ); \ + (void)0; \ + }) + +#else + +# define atomic_loadx(ptr) ((typeof (*ptr)) *(ptr)) + + /* For stores, we do want atomicity. */ + +# define atomic_storex(dst, src) \ + ({ \ + union hurd_xint __tmp = { (src) }; \ + typeof (dst) __p = (dst); \ + while (1) \ + { \ + union hurd_xint __val = { *__p }; \ + if (atomic_casx_bool (__p, __val.lo, \ + __val.hi, __tmp.lo, __tmp.hi)) \ + break; \ + } \ + (void)0; \ + }) + +#endif /* __SSE2__ */ #endif diff --git a/sysdeps/mach/bits/spin-lock-inline.h b/sysdeps/mach/bits/spin-lock-inline.h index f9f7c29..b9646e9 100644 --- a/sysdeps/mach/bits/spin-lock-inline.h +++ b/sysdeps/mach/bits/spin-lock-inline.h @@ -1,5 +1,5 @@ /* Definitions of user-visible names for spin locks. - Copyright (C) 1994, 1997, 2002, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 1994-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -22,7 +22,7 @@ #include #include -#include /* This does all the work. */ +#include /* This does all the work. */ __BEGIN_DECLS @@ -63,14 +63,12 @@ __pthread_spin_trylock (__pthread_spinlock_t *__lock) return __spin_try_lock (__lock) ? 0 : __EBUSY; } -__extern_inline int __pthread_spin_lock (__pthread_spinlock_t *__lock); -extern int _pthread_spin_lock (__pthread_spinlock_t *__lock); +__PT_SPIN_INLINE int __pthread_spin_lock (__pthread_spinlock_t *__lock); __extern_inline int __pthread_spin_lock (__pthread_spinlock_t *__lock) { - if (__pthread_spin_trylock (__lock)) - return _pthread_spin_lock (__lock); + __spin_lock (__lock); return 0; } diff --git a/sysdeps/mach/i386/bits/spin-lock-inline.h b/sysdeps/mach/i386/bits/spin-lock-inline.h index e5ed3de..b9a18e4 100644 --- a/sysdeps/mach/i386/bits/spin-lock-inline.h +++ b/sysdeps/mach/i386/bits/spin-lock-inline.h @@ -1,5 +1,5 @@ /* Machine-specific definitions for spin locks. i386 version. - Copyright (C) 2000, 2005, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2000-2016 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 @@ -26,6 +26,7 @@ #include #include +#include __BEGIN_DECLS @@ -45,7 +46,7 @@ __PT_SPIN_INLINE int __pthread_spin_destroy (__pthread_spinlock_t *__lock); __PT_SPIN_INLINE int __pthread_spin_destroy (__pthread_spinlock_t *__lock) { - return 0; + return (0); } __PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock, @@ -54,8 +55,8 @@ __PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock, __PT_SPIN_INLINE int __pthread_spin_init (__pthread_spinlock_t *__lock, int __pshared) { - *__lock = __PTHREAD_SPIN_LOCK_INITIALIZER; - return 0; + *__lock = LLL_INITIALIZER; + return (0); } __PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock); @@ -63,21 +64,16 @@ __PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock); __PT_SPIN_INLINE int __pthread_spin_trylock (__pthread_spinlock_t *__lock) { - int __locked; - __asm__ __volatile ("xchgl %0, %1" - : "=&r" (__locked), "=m" (*__lock) : "0" (1) : "memory"); - return __locked ? __EBUSY : 0; + return (lll_trylock (__lock)); } -__extern_inline int __pthread_spin_lock (__pthread_spinlock_t *__lock); -extern int _pthread_spin_lock (__pthread_spinlock_t *__lock); +__PT_SPIN_INLINE int __pthread_spin_lock (__pthread_spinlock_t *__lock); -__extern_inline int +__PT_SPIN_INLINE int __pthread_spin_lock (__pthread_spinlock_t *__lock) { - if (__pthread_spin_trylock (__lock)) - return _pthread_spin_lock (__lock); - return 0; + lll_lock (__lock, 0); + return (0); } __PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock); @@ -85,10 +81,8 @@ __PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock); __PT_SPIN_INLINE int __pthread_spin_unlock (__pthread_spinlock_t *__lock) { - int __unlocked; - __asm__ __volatile ("xchgl %0, %1" - : "=&r" (__unlocked), "=m" (*__lock) : "0" (0) : "memory"); - return 0; + lll_unlock (__lock, 0); + return (0); } #endif /* Use extern inlines or force inlines. */ diff --git a/sysdeps/pthread/bits/libc-lockP.h b/sysdeps/pthread/bits/libc-lockP.h index 65878f2..4d2e2b2 100644 --- a/sysdeps/pthread/bits/libc-lockP.h +++ b/sysdeps/pthread/bits/libc-lockP.h @@ -51,6 +51,18 @@ FUNC ARGS #endif +/* Type for key to thread-specific data. */ +typedef pthread_key_t __libc_key_t; + +#define __libc_key_create(KEY, DESTR) \ + __libc_maybe_call (__pthread_key_create, (KEY, DESTR), 1) + +#define __libc_getspecific(KEY) \ + __libc_maybe_call (__pthread_getspecific, (KEY), 0) + +#define __libc_setspecific(KEY, VAL) \ + __libc_maybe_call (__pthread_setspecific, (KEY, VAL), 0) + /* Functions that are used by this file and are internal to the GNU C library. */ diff --git a/sysdeps/pthread/bits/xint.h b/sysdeps/pthread/bits/xint.h new file mode 100644 index 0000000..4731548 --- /dev/null +++ b/sysdeps/pthread/bits/xint.h @@ -0,0 +1,41 @@ +/* Extended integer type. Generic version. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_XINT_H +#define _BITS_XINT_H 1 + +union hurd_xint +{ + unsigned long long qv; + struct + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + unsigned int hi; + unsigned int lo; +# define hurd_xint_pair(lo, hi) hi, lo +#else +# define hurd_xint_pair(lo, hi) lo, hi + unsigned int lo; + unsigned int hi; +#endif + }; +} __attribute__ ((aligned (8))); + +#endif +