diff options
author | Agustina Arzille <avarzille@riseup.net> | 2016-10-17 01:00:36 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2017-09-25 21:32:15 +0200 |
commit | e325908339b901451a34d78e0689367acd338bec (patch) | |
tree | ed9cead28450bc4a7a0c8509936300e6efa5a429 | |
parent | f881f17267506f3ced17259a066a4d95bffb57f0 (diff) |
Make pthread_rwlock use gsyncgsync-rwlock
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | sysdeps/generic/bits/pt-atomic.h (renamed from sysdeps/i386/bits/pt-atomic.h) | 38 | ||||
-rw-r--r-- | sysdeps/mach/hurd/bits/rwlock.h | 37 | ||||
-rw-r--r-- | sysdeps/mach/hurd/bits/xint.h | 49 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-attr.c | 1 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-destroy.c | 32 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-init.c | 44 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-rdlock.c | 61 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-timedrdlock.c | 67 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-timedwrlock.c | 76 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-tryrdlock.c | 44 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-trywrlock.c | 42 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-unlock.c | 74 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock-wrlock.c | 60 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlock.h | 94 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlockattr-destroy.c | 29 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlockattr-getpshared.c | 29 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlockattr-init.c | 34 | ||||
-rw-r--r-- | sysdeps/mach/hurd/pt-rwlockattr-setpshared.c | 33 |
19 files changed, 822 insertions, 25 deletions
@@ -189,7 +189,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/sysdeps/i386/bits/pt-atomic.h b/sysdeps/generic/bits/pt-atomic.h index 0dfc1f6..7ef0484 100644 --- a/sysdeps/i386/bits/pt-atomic.h +++ b/sysdeps/generic/bits/pt-atomic.h @@ -1,5 +1,5 @@ -/* Atomic operations. i386 version. - Copyright (C) 2000 Free Software Foundation, Inc. +/* Atomic operations. gcc intrinsics 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 @@ -25,42 +25,32 @@ typedef __volatile int __atomic_t; static inline void __atomic_inc (__atomic_t *__var) { - __asm__ __volatile ("lock; incl %0" : "=m" (*__var) : "m" (*__var)); + __atomic_add_fetch (__var, 1, __ATOMIC_SEQ_CST); } static inline void __atomic_dec (__atomic_t *__var) { - __asm__ __volatile ("lock; decl %0" : "=m" (*__var) : "m" (*__var)); + __atomic_add_fetch (__var, -1, __ATOMIC_SEQ_CST); } 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; + __atomic_t res = __atomic_add_fetch (__var, -1, __ATOMIC_SEQ_CST); + return res == 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; +#define atomic_loadx(p) __atomic_load_8(p, __ATOMIC_SEQ_CST) +#define atomic_storex(p, v) __atomic_store_8(p, v, __ATOMIC_SEQ_CST) -/* 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) +static inline char atomic_casx_bool(uint64_t *p, + uint32_t elo, uint32_t ehi, uint32_t nlo, uint32_t nhi) { - 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; + uint64_t n = nlo | (((uint64_t) nhi) << 32); + uint64_t e = elo | (((uint64_t) ehi) << 32); + return __atomic_compare_exchange(p, + &e, &n, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } #endif diff --git a/sysdeps/mach/hurd/bits/rwlock.h b/sysdeps/mach/hurd/bits/rwlock.h new file mode 100644 index 0000000..89927ce --- /dev/null +++ b/sysdeps/mach/hurd/bits/rwlock.h @@ -0,0 +1,37 @@ +/* rwlock type. Generic version. + Copyright (C) 2002-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 + 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_RWLOCK_H +#define _BITS_RWLOCK_H + +#include <bits/xint.h> + +struct __pthread_rwlock +{ + union __hurd_xint __shpid_qwr; + union __hurd_xint __oid_nrd; + int __flags; + unsigned int __reserved1; + unsigned int __reserved2; +}; + +/* Static initializer for read-write locks. */ +#define __PTHREAD_RWLOCK_INITIALIZER { { 0 }, { 0 }, 0 } + +#endif /* bits/rwlock.h */ diff --git a/sysdeps/mach/hurd/bits/xint.h b/sysdeps/mach/hurd/bits/xint.h new file mode 100644 index 0000000..e25fab9 --- /dev/null +++ b/sysdeps/mach/hurd/bits/xint.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __HURD_XINT_H__ +#define __HURD_XINT_H__ 1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +typedef unsigned long int __hurd_xint64; +#else +typedef unsigned long long int __hurd_xint64; +#endif + +/* 64-bit integer that allows direct access to its low + * and high limbs. */ +union __hurd_xint +{ + __hurd_xint64 __qv; + struct + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + unsigned long __hi; + unsigned long __lo; +# define __hurd_xint_pair(lo, hi) hi, lo +#else +# define __hurd_xint_pair(lo, hi) lo, hi + unsigned long __lo; + unsigned long __hi; +#endif + }; +}; + +#endif diff --git a/sysdeps/mach/hurd/pt-rwlock-attr.c b/sysdeps/mach/hurd/pt-rwlock-attr.c new file mode 100644 index 0000000..40a8c17 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-attr.c @@ -0,0 +1 @@ +/* empty */ diff --git a/sysdeps/mach/hurd/pt-rwlock-destroy.c b/sysdeps/mach/hurd/pt-rwlock-destroy.c new file mode 100644 index 0000000..f2eaa41 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-destroy.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int _pthread_rwlock_destroy (pthread_rwlock_t *rwp) +{ + /* XXX: Maybe we could do some sanity checks. */ + (void)rwp; + return (0); +} + +strong_alias (_pthread_rwlock_destroy, pthread_rwlock_destroy) diff --git a/sysdeps/mach/hurd/pt-rwlock-init.c b/sysdeps/mach/hurd/pt-rwlock-init.c new file mode 100644 index 0000000..f4e672e --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-init.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +static const pthread_rwlockattr_t dfl_attr = +{ + .__pshared = PTHREAD_PROCESS_PRIVATE +}; + +int _pthread_rwlock_init (pthread_rwlock_t *rwp, + const pthread_rwlockattr_t *attrp) +{ + if (!attrp) + attrp = &dfl_attr; + + rwp->__shpid_qwr.__qv = rwp->__oid_nrd.__qv = 0; + rwp->__flags = attrp->__pshared == PTHREAD_PROCESS_SHARED ? + GSYNC_SHARED : 0; + + return (0); +} + +strong_alias (_pthread_rwlock_init, pthread_rwlock_init) + diff --git a/sysdeps/mach/hurd/pt-rwlock-rdlock.c b/sysdeps/mach/hurd/pt-rwlock-rdlock.c new file mode 100644 index 0000000..0708bca --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-rdlock.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int __pthread_rwlock_rdlock (pthread_rwlock_t *rwp) +{ + int flags = rwp->__flags & GSYNC_SHARED; + + /* Test that we don't own the write-lock already. */ + if (rwl_owned_p (rwp, early_pthread_self(), flags)) + return (EDEADLK); + + while (1) + { + union __hurd_xint tmp = { atomic_loadx (&rwp->__oid_nrd.__qv) }; + if ((rwl_oid (tmp) & ID_MASK) == 0) + { + /* The lock is either unowned, or the readers hold it. */ + if (catomic_casx_bool (&rwp->__oid_nrd.__qv, + hurd_xint_pair (tmp.__lo, tmp.__hi), + hurd_xint_pair (RWLOCK_RO, rwl_nrd (tmp) + 1))) + { + /* If we grabbed an unowned lock and there were readers + * queued, notify our fellows so they stop blocking. */ + if (rwl_oid (tmp) != RWLOCK_RO && rwl_nrd (tmp) > 0) + lll_wake (&rwl_oid(rwp->__oid_nrd), flags | GSYNC_BROADCAST); + + return (0); + } + } + else + { + /* A writer holds the lock. Sleep. */ + atomic_increment (&rwl_nrd(rwp->__oid_nrd)); + lll_wait (&rwl_oid(rwp->__oid_nrd), rwl_oid (tmp), flags); + atomic_decrement (&rwl_nrd(rwp->__oid_nrd)); + } + } +} + +strong_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock) diff --git a/sysdeps/mach/hurd/pt-rwlock-timedrdlock.c b/sysdeps/mach/hurd/pt-rwlock-timedrdlock.c new file mode 100644 index 0000000..0f77623 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-timedrdlock.c @@ -0,0 +1,67 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwp, + const struct timespec *abstime) +{ + int flags = rwp->__flags & GSYNC_SHARED; + + if (rwl_owned_p (rwp, early_pthread_self(), flags)) + return (EDEADLK); + + while (1) + { + union __hurd_xint tmp = { atomic_loadx (&rwp->__oid_nrd.__qv) }; + if ((rwl_oid (tmp) & ID_MASK) == 0) + { + if (catomic_casx_bool (&rwp->__oid_nrd.__qv, + hurd_xint_pair (tmp.__lo, tmp.__hi), + hurd_xint_pair (RWLOCK_RO, rwl_nrd (tmp) + 1))) + { + if (rwl_oid (tmp) != RWLOCK_RO && rwl_nrd (tmp) > 0) + lll_wake (&rwl_oid(rwp->__oid_nrd), flags | GSYNC_BROADCAST); + + return (0); + } + } + else + { + /* The timeout parameter has to be checked on every iteration, + * because its value may not be examined if the lock can be + * taken without blocking. */ + + if (__glibc_unlikely (abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000)) + return (EINVAL); + + atomic_increment (&rwl_nrd(rwp->__oid_nrd)); + int ret = lll_abstimed_wait (&rwl_oid(rwp->__oid_nrd), + rwl_oid (tmp), abstime, flags); + atomic_decrement (&rwl_nrd(rwp->__oid_nrd)); + + if (ret == KERN_TIMEDOUT) + return (ETIMEDOUT); + } + } +} diff --git a/sysdeps/mach/hurd/pt-rwlock-timedwrlock.c b/sysdeps/mach/hurd/pt-rwlock-timedwrlock.c new file mode 100644 index 0000000..89672cc --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-timedwrlock.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwp, + const struct timespec *abstime) +{ + unsigned int self_id = early_pthread_self(); + int flags = rwp->__flags & GSYNC_SHARED; + + if (rwl_owned_p (rwp, self_id, flags)) + return (EDEADLK); + + while (1) + { + unsigned int *ptr = &rwl_oid (rwp->__oid_nrd); + atomic_read_barrier (); + unsigned int owner = *ptr; + + if (owner == RWLOCK_UNOWNED) + { + if (atomic_compare_and_exchange_bool_acq (ptr, self_id, owner) == 0) + { + rwl_setown (rwp, flags); + return (0); + } + } + else + { + if (__glibc_unlikely (abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000)) + return (EINVAL); + + unsigned int nw = atomic_exchange_and_add (--ptr, 1); + int ret = lll_abstimed_xwait (ptr, nw + 1, owner, abstime, flags); + nw = atomic_exchange_and_add (ptr, -1); + + if (ret == KERN_TIMEDOUT) + { + /* If we timed out, there are no writers pending, the + * lock is unowned *and* there are readers blocked, it's + * possible that a wakeup was meant for us, but we timed + * out first. In such unlikely case, we wake every reader + * in order to avoid a potential deadlock. */ + + union __hurd_xint tmp = { atomic_loadx (&rwp->__oid_nrd.__qv) }; + if (__glibc_unlikely (nw == 1 && rwl_nrd (tmp) > 0 && + rwl_oid (tmp) == RWLOCK_UNOWNED)) + lll_wake (&rwl_oid(rwp->__oid_nrd), flags | GSYNC_BROADCAST); + + /* We still return with an error. */ + return (ETIMEDOUT); + } + } + } +} diff --git a/sysdeps/mach/hurd/pt-rwlock-tryrdlock.c b/sysdeps/mach/hurd/pt-rwlock-tryrdlock.c new file mode 100644 index 0000000..4ce60e4 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-tryrdlock.c @@ -0,0 +1,44 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwp) +{ + if (rwl_owned_p (rwp, early_pthread_self(), rwp->__flags)) + return (EDEADLK); + + union __hurd_xint tmp = { atomic_loadx (&rwp->__oid_nrd.__qv) }; + if ((rwl_oid (tmp) & ID_MASK) == 0 && + catomic_casx_bool (&rwp->__oid_nrd.__qv, + hurd_xint_pair (tmp.__lo, tmp.__hi), + hurd_xint_pair (RWLOCK_RO, rwl_nrd (tmp) + 1))) + { + if (rwl_oid (tmp) != RWLOCK_RO && rwl_nrd (tmp) > 0) + lll_wake (&rwl_oid(rwp->__oid_nrd), GSYNC_BROADCAST | + (rwp->__flags & GSYNC_SHARED)); + + return (0); + } + + return (EBUSY); +} diff --git a/sysdeps/mach/hurd/pt-rwlock-trywrlock.c b/sysdeps/mach/hurd/pt-rwlock-trywrlock.c new file mode 100644 index 0000000..910b3ab --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-trywrlock.c @@ -0,0 +1,42 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwp) +{ + unsigned int self_id = early_pthread_self(); + unsigned int *ptr = &rwl_oid (rwp->__oid_nrd); + atomic_read_barrier (); + unsigned int owner = *ptr; + + if (rwl_owned_p (rwp, self_id, rwp->__flags)) + return (EDEADLK); + else if (owner == RWLOCK_UNOWNED && + atomic_compare_and_exchange_bool_acq (ptr, self_id, owner) == 0) + { + rwl_setown (rwp, rwp->__flags); + return (0); + } + + return (EBUSY); +} diff --git a/sysdeps/mach/hurd/pt-rwlock-unlock.c b/sysdeps/mach/hurd/pt-rwlock-unlock.c new file mode 100644 index 0000000..3162279 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-unlock.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int __pthread_rwlock_unlock (pthread_rwlock_t *rwp) +{ + int flags = rwp->__flags & GSYNC_SHARED; + atomic_read_barrier (); + unsigned int owner = rwl_oid (rwp->__oid_nrd); + + if ((owner & ID_MASK) != 0) + { + /* A writer holds the lock. */ + if (!rwl_owned_p (rwp, early_pthread_self(), flags)) + /* ... But it isn't us. */ + return (EPERM); + + rwl_spid(rwp) = 0; + rwl_oid(rwp->__oid_nrd) = RWLOCK_UNOWNED; + atomic_write_barrier (); + + /* The exclusive lock has been released. Now decide whether + * to wake a queued writer (preferred), or all the queued readers. */ + if (rwl_qwr (rwp->__oid_nrd) > 0) + lll_wake (&rwl_qwr(rwp->__oid_nrd), flags); + else if (rwl_nrd (rwp->__oid_nrd) > 0) + lll_wake (&rwl_oid(rwp->__oid_nrd), flags | GSYNC_BROADCAST); + } + else if (rwl_nrd (rwp->__oid_nrd) == 0) + return (EPERM); + else + { + union __hurd_xint tmp; + while (1) + { + tmp.__qv = atomic_loadx (&rwp->__oid_nrd.__qv); + if (catomic_casx_bool (&rwp->__oid_nrd.__qv, + hurd_xint_pair (tmp.__lo, tmp.__hi), + hurd_xint_pair (rwl_nrd (tmp) == 1 ? + RWLOCK_UNOWNED : RWLOCK_RO, rwl_nrd (tmp) - 1))) + break; + } + + /* As a reader, we only need to do a wakeup iff: + * - We were the last one. + * - There's at least a writer queued. */ + if (rwl_nrd (tmp) == 1 && rwl_qwr (rwp->__oid_nrd) > 0) + lll_wake (&rwl_qwr(rwp->__oid_nrd), flags); + } + + return (0); +} + +strong_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock) diff --git a/sysdeps/mach/hurd/pt-rwlock-wrlock.c b/sysdeps/mach/hurd/pt-rwlock-wrlock.c new file mode 100644 index 0000000..31928b7 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock-wrlock.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int __pthread_rwlock_wrlock (pthread_rwlock_t *rwp) +{ + int flags = rwp->__flags & GSYNC_SHARED; + unsigned int self_id = early_pthread_self(); + + if (rwl_owned_p (rwp, self_id, flags)) + return (EDEADLK); + + while (1) + { + unsigned int *ptr = &rwl_oid (rwp->__oid_nrd); + atomic_read_barrier (); + unsigned int owner = *ptr; + + if (owner == RWLOCK_UNOWNED) + { + if (atomic_compare_and_exchange_bool_acq (ptr, self_id, owner) == 0) + { + rwl_setown (rwp, flags); + return (0); + } + } + else + { + /* Wait on the address. We are only interested in the value of + * the OID field, but we need a different queue for writers. + * As such, we use 64-bit values, with the high word being + * the owner id. */ + unsigned int nw = atomic_exchange_and_add (--ptr, 1); + lll_xwait (ptr, nw + 1, owner, flags); + atomic_decrement (ptr); + } + } +} + +strong_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock) diff --git a/sysdeps/mach/hurd/pt-rwlock.h b/sysdeps/mach/hurd/pt-rwlock.h new file mode 100644 index 0000000..21e321a --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlock.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _PT_RWLOCK_H +#define _PT_RWLOCK_H + +/* Read-write locks have the following memory layout: + * 0 4 8 12 16 + * |__shpid__|__qwriters__|__owner_id__|__nreaders__| + * + * Whenever a thread wants to acquire either lock, it first has to check + * the OID field. It may be unowned, owned by readers, or owner by a + * particular writer. For reader ownership, we use a special OID that no + * thread can ever have. + * + * When it comes to waiting for the lock to change ownership, we need + * different wait queues for readers and writers. However, both of them + * have to monitor the OID field for changes. This is where 64-bit gsync + * comes into play: Readers will wait on the address of the OID, while + * writers will wait on the 64-bit address that starts at NWRITERS and + * extends to OID as well. + * + * This approach can cause some extra work on the writer side, but it's + * more efficient by virtue of being lockless. As long as we have 64-bit + * atomics, we can safely implement the POSIX read-write lock interface + * without using any internal locks. */ + +#define __rwl_atp(ptr, idx) (((unsigned int *)(ptr))[idx]) + +/* Access the fields described above. */ +#define rwl_qwr(val) __rwl_atp (&(val), -1) +#define rwl_oid(val) __rwl_atp (&(val), +0) +#define rwl_nrd(val) __rwl_atp (&(val), +1) + +/* Special ID's to represent unowned and readers-owned locks. */ +#define RWLOCK_UNOWNED (0) +#define RWLOCK_RO (1U << 31) + +#define ID_MASK ~RWLOCK_RO + +/* Access the owner's PID for task-shared rwlocks. */ +#define rwl_spid(rwl) *(unsigned int *)&(rwl)->__shpid_qwr + +/* Test that a read-write lock is owned by a particular thread. */ +#define rwl_owned_p(rwp, tid, flags) \ + (rwl_oid ((rwp)->__oid_nrd) == (tid) && \ + (((flags) & GSYNC_SHARED) == 0 || \ + rwl_spid (rwp) == (unsigned int)__getpid ())) + +#define rwl_setown(rwp, flags) \ + do \ + { \ + if ((flags) & GSYNC_SHARED) \ + rwl_spid(rwp) = __getpid (); \ + } \ + while (0) + +extern int __getpid (void) __attribute__ ((const)); + +/* We need a function, because we're using a macro that + * expands into a list of arguments. */ +static inline int +catomic_casx_bool (unsigned long long *ptr, unsigned int elo, + unsigned int ehi, unsigned int nlo, unsigned int nhi) +{ + return (atomic_casx_bool (ptr, elo, ehi, nlo, nhi)); +} + +static inline pthread_t early_pthread_self(void) +{ + struct __pthread *thread = ___pthread_self; + if (thread) + return thread->thread; + else + /* Initialization time, no need to care. */ + return 0; +} + +#endif /* pt-rwlock.h */ diff --git a/sysdeps/mach/hurd/pt-rwlockattr-destroy.c b/sysdeps/mach/hurd/pt-rwlockattr-destroy.c new file mode 100644 index 0000000..fd6bd5c --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlockattr-destroy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attrp) +{ + (void)attrp; + return (0); +} diff --git a/sysdeps/mach/hurd/pt-rwlockattr-getpshared.c b/sysdeps/mach/hurd/pt-rwlockattr-getpshared.c new file mode 100644 index 0000000..907943d --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlockattr-getpshared.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *ap, int *outp) +{ + *outp = ap->__pshared; + return (0); +} diff --git a/sysdeps/mach/hurd/pt-rwlockattr-init.c b/sysdeps/mach/hurd/pt-rwlockattr-init.c new file mode 100644 index 0000000..4930786 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlockattr-init.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +static const pthread_rwlockattr_t dfl_attr = +{ + .__pshared = PTHREAD_PROCESS_PRIVATE +}; + +int pthread_rwlockattr_init (pthread_rwlockattr_t *attrp) +{ + *attrp = dfl_attr; + return (0); +} diff --git a/sysdeps/mach/hurd/pt-rwlockattr-setpshared.c b/sysdeps/mach/hurd/pt-rwlockattr-setpshared.c new file mode 100644 index 0000000..9fdc1c8 --- /dev/null +++ b/sysdeps/mach/hurd/pt-rwlockattr-setpshared.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + Contributed by Agustina Arzille <avarzille@riseup.net>, 2016. + + 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. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> +#include <pt-internal.h> +#include <bits/pt-atomic.h> +#include <hurdlock.h> +#include "pt-rwlock.h" + +int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attrp, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && + pshared != PTHREAD_PROCESS_SHARED) + return (EINVAL); + + attrp->__pshared = pshared; + return (0); +} |