summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAgustina Arzille <avarzille@riseup.net>2016-10-17 01:00:36 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2017-09-25 21:32:15 +0200
commite325908339b901451a34d78e0689367acd338bec (patch)
treeed9cead28450bc4a7a0c8509936300e6efa5a429
parentf881f17267506f3ced17259a066a4d95bffb57f0 (diff)
Make pthread_rwlock use gsyncgsync-rwlock
-rw-r--r--Makefile3
-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.h37
-rw-r--r--sysdeps/mach/hurd/bits/xint.h49
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-attr.c1
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-destroy.c32
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-init.c44
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-rdlock.c61
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-timedrdlock.c67
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-timedwrlock.c76
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-tryrdlock.c44
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-trywrlock.c42
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-unlock.c74
-rw-r--r--sysdeps/mach/hurd/pt-rwlock-wrlock.c60
-rw-r--r--sysdeps/mach/hurd/pt-rwlock.h94
-rw-r--r--sysdeps/mach/hurd/pt-rwlockattr-destroy.c29
-rw-r--r--sysdeps/mach/hurd/pt-rwlockattr-getpshared.c29
-rw-r--r--sysdeps/mach/hurd/pt-rwlockattr-init.c34
-rw-r--r--sysdeps/mach/hurd/pt-rwlockattr-setpshared.c33
19 files changed, 822 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index 9707f57..29843fc 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
+}