This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch sthibaul/hurd-builds updated. glibc-2.26.9000-1157-gef70d12


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, sthibaul/hurd-builds has been updated
       via  ef70d12af7133d6b285ba6031c1ad3756e0eef14 (commit)
       via  e4a5aad430c83a229df5d32fd06d48775f39720d (commit)
      from  6953a64474de078688b47565056a21a1cf11748b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ef70d12af7133d6b285ba6031c1ad3756e0eef14

commit ef70d12af7133d6b285ba6031c1ad3756e0eef14
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Fri Jan 19 02:26:28 2018 +0100

    t/gsync-libc
    From: Agustina Arzille <avarzille@riseup.net>
    Subject: [PATCH] Introduce gsync-based locks to glibc.
    
    * hurd/Makefile: Add hurdlock.
    * hurd/Versions: Added new entry to export the above interface.
    * hurd/hurdlock.c: New file.
    * hurd/hurdlock.h: New file.
    * hurd/hurdpid.c: Include <lowlevellock.h>
      (_S_msg_proc_newids): Use lll_wait to synchronize.
    * hurd/hurdsig.c: (reauth_proc): Use __mutex_lock and __mutex_unlock.
    * hurd/setauth.c: Include <hurdlock.h>, use integer for synchronization.
    * hurd/sysvshm.c: Include <hurdlock.h>, use integer for synchronization.
    * mach/Makefile: Remove unneeded file
    * mach/lock-intern.h: Use lll to implement spinlocks.
    * mach/lowlevellock.h: New file
    * mach/mutex-init.c: Rewrite mutex initialization.
    * sysdeps/mach/Makefile: Add libmachuser as dependencies for some libs.
    * sysdeps/mach/libc-lock.h: Reimplemented libc internal locks
      with lll, cleanup routines now use gcc's cleanup attribute
    * sysdeps/mach/hurd/bits/errno.h: New errno values.
    * sysdeps/mach/hurd/libc-lock.h: Removed file.
    * sysdeps/mach/hurd/malloc-machine.h: Reimplemented malloc locks.
    * sysdeps/mach/hurd/setpgid.c: (setpgid): Use gsync for synchronization.
    * sysdeps/mach/hurd/setsid.c: (setsid): Likewise.
    
    t/libc_cleanup
    From: Agustina Arzille <avarzille@riseup.net>
    Subject: [PATCH] Use gcc's cleanup attributes
    
    cleanup routines now use gcc's cleanup attribute

diff --git a/hurd/Makefile b/hurd/Makefile
index f71dc36..fbb2f5c 100644
--- a/hurd/Makefile
+++ b/hurd/Makefile
@@ -54,6 +54,7 @@ routines = hurdstartup hurdinit \
 	   vpprintf \
 	   ports-get ports-set hurdports hurdmsg \
 	   errno-loc \
+	   hurdlock \
 	   $(sig) $(dtable) $(inlines) port-cleanup report-wait xattr
 sig	= hurdsig hurdfault siginfo hurd-raise preempt-sig \
 	  trampoline longjmp-ts catch-exc exc2signal hurdkill sigunwind \
diff --git a/hurd/Versions b/hurd/Versions
index 6db2a9c..fe20020 100644
--- a/hurd/Versions
+++ b/hurd/Versions
@@ -147,4 +147,12 @@ libc {
     cthread_keycreate; cthread_getspecific; cthread_setspecific;
     __libc_getspecific;
   }
+
+  GLIBC_PRIVATE {
+    # Used by other libs.
+    __lll_abstimed_wait; __lll_abstimed_xwait;
+    __lll_abstimed_lock; __lll_robust_lock;
+    __lll_robust_abstimed_lock; __lll_robust_trylock;
+    __lll_robust_unlock;
+  }
 }
diff --git a/hurd/hurdlock.c b/hurd/hurdlock.c
new file mode 100644
index 0000000..6ab180e
--- /dev/null
+++ b/hurd/hurdlock.c
@@ -0,0 +1,215 @@
+/* Copyright (C) 1999-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "hurdlock.h"
+#include <hurd.h>
+#include <time.h>
+#include <errno.h>
+
+/* Convert an absolute timeout in nanoseconds to a relative
+ * timeout in milliseconds. */
+static inline int __attribute__ ((gnu_inline))
+compute_reltime (const struct timespec *abstime, clockid_t clk)
+{
+  struct timespec ts;
+  __clock_gettime (clk, &ts);
+
+  ts.tv_sec = abstime->tv_sec - ts.tv_sec;
+  ts.tv_nsec = abstime->tv_nsec - ts.tv_nsec;
+
+  if (ts.tv_nsec < 0)
+    {
+      --ts.tv_sec;
+      ts.tv_nsec += 1000000000;
+    }
+
+  return (ts.tv_sec < 0 ? -1 :
+    (int)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000));
+}
+
+int __lll_abstimed_wait (void *ptr, int val,
+  const struct timespec *tsp, int flags, int clk)
+{
+  int mlsec = compute_reltime (tsp, clk);
+  return (mlsec < 0 ? KERN_TIMEDOUT :
+    lll_timed_wait (ptr, val, mlsec, flags));
+}
+
+int __lll_abstimed_xwait (void *ptr, int lo, int hi,
+  const struct timespec *tsp, int flags, int clk)
+{
+  int mlsec = compute_reltime (tsp, clk);
+  return (mlsec < 0 ? KERN_TIMEDOUT :
+    lll_timed_xwait (ptr, lo, hi, mlsec, flags));
+}
+
+int __lll_abstimed_lock (void *ptr,
+  const struct timespec *tsp, int flags, int clk)
+{
+  if (lll_trylock (ptr) == 0)
+    return (0);
+
+  while (1)
+    {
+      if (atomic_exchange_acq ((int *)ptr, 2) == 0)
+        return (0);
+      else if (tsp->tv_nsec < 0 || tsp->tv_nsec >= 1000000000)
+        return (EINVAL);
+
+      int mlsec = compute_reltime (tsp, clk);
+      if (mlsec < 0 || lll_timed_wait (ptr,
+          2, mlsec, flags) == KERN_TIMEDOUT)
+        return (ETIMEDOUT);
+    }
+}
+
+/* Robust locks. */
+
+extern int __getpid (void) __attribute__ ((const));
+extern task_t __pid2task (int);
+
+/* Test if a given process id is still valid. */
+static inline int valid_pid (int pid)
+{
+  task_t task = __pid2task (pid);
+  if (task == MACH_PORT_NULL)
+    return (0);
+
+  __mach_port_deallocate (__mach_task_self (), task);
+  return (1);
+}
+
+/* Robust locks have currently no support from the kernel; they
+ * are simply implemented with periodic polling. When sleeping, the
+ * maximum blocking time is determined by this constant. */
+#define MAX_WAIT_TIME   1500
+
+int __lll_robust_lock (void *ptr, int flags)
+{
+  int *iptr = (int *)ptr;
+  int id = __getpid ();
+  int wait_time = 25;
+  unsigned int val;
+
+  /* Try to set the lock word to our PID if it's clear. Otherwise,
+   * mark it as having waiters. */
+  while (1)
+    {
+      val = *iptr;
+      if (!val && atomic_compare_and_exchange_bool_acq (iptr, id, 0) == 0)
+        return (0);
+      else if (atomic_compare_and_exchange_bool_acq (iptr,
+          val | LLL_WAITERS, val) == 0)
+        break;
+    }
+
+  for (id |= LLL_WAITERS ; ; )
+    {
+      val = *iptr;
+      if (!val && atomic_compare_and_exchange_bool_acq (iptr, id, 0) == 0)
+        return (0);
+      else if (val && !valid_pid (val & LLL_OWNER_MASK))
+        {
+          if (atomic_compare_and_exchange_bool_acq (iptr, id, val) == 0)
+            return (EOWNERDEAD);
+        }
+      else
+        {
+          lll_timed_wait (iptr, val, wait_time, flags);
+          if (wait_time < MAX_WAIT_TIME)
+            wait_time <<= 1;
+        }
+    }
+}
+
+int __lll_robust_abstimed_lock (void *ptr,
+  const struct timespec *tsp, int flags, int clk)
+{
+  int *iptr = (int *)ptr;
+  int id = __getpid ();
+  int wait_time = 25;
+  unsigned int val;
+
+  while (1)
+    {
+      val = *iptr;
+      if (!val && atomic_compare_and_exchange_bool_acq (iptr, id, 0) == 0)
+        return (0);
+      else if (atomic_compare_and_exchange_bool_acq (iptr,
+          val | LLL_WAITERS, val) == 0)
+        break;
+    }
+
+  for (id |= LLL_WAITERS ; ; )
+    {
+      val = *iptr;
+      if (!val && atomic_compare_and_exchange_bool_acq (iptr, id, 0) == 0)
+        return (0);
+      else if (val && !valid_pid (val & LLL_OWNER_MASK))
+        {
+          if (atomic_compare_and_exchange_bool_acq (iptr, id, val) == 0)
+            return (EOWNERDEAD);
+        }
+      else
+        {
+          int mlsec = compute_reltime (tsp, clk);
+          if (mlsec < 0)
+            return (ETIMEDOUT);
+          else if (mlsec > wait_time)
+            mlsec = wait_time;
+
+          int res = lll_timed_wait (iptr, val, mlsec, flags);
+          if (res == KERN_TIMEDOUT)
+            return (ETIMEDOUT);
+          else if (wait_time < MAX_WAIT_TIME)
+            wait_time <<= 1;
+        }
+    }
+}
+
+int __lll_robust_trylock (void *ptr)
+{
+  int *iptr = (int *)ptr;
+  int id = __getpid ();
+  unsigned int val = *iptr;
+
+  if (!val)
+    {
+      if (atomic_compare_and_exchange_bool_acq (iptr, id, 0) == 0)
+        return (0);
+    }
+  else if (!valid_pid (val & LLL_OWNER_MASK) &&
+      atomic_compare_and_exchange_bool_acq (iptr, id, val) == 0)
+    return (EOWNERDEAD);
+
+  return (EBUSY);
+}
+
+void __lll_robust_unlock (void *ptr, int flags)
+{
+  unsigned int val = atomic_load_relaxed((unsigned int *)ptr);
+  while (1)
+    {
+      if (val & LLL_WAITERS)
+        {
+          lll_set_wake (ptr, 0, flags);
+          break;
+        }
+      else if (atomic_compare_exchange_weak_release ((unsigned int *)ptr, &val, 0))
+        break;
+    }
+}
diff --git a/hurd/hurdlock.h b/hurd/hurdlock.h
new file mode 100644
index 0000000..e3e7369
--- /dev/null
+++ b/hurd/hurdlock.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 1999-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _HURD_LOCK_H
+#define _HURD_LOCK_H   1
+
+#include <mach/lowlevellock.h>
+
+struct timespec;
+
+/* Flags for robust locks. */
+#define LLL_WAITERS      (1U << 31)
+#define LLL_DEAD_OWNER   (1U << 30)
+
+#define LLL_OWNER_MASK   ~(LLL_WAITERS | LLL_DEAD_OWNER)
+
+/* Wait on 64-bit address PTR, without blocking if its contents
+ * are different from the pair <LO, HI>. */
+#define lll_xwait(ptr, lo, hi, flags) \
+  __gsync_wait (__mach_task_self (), \
+    (vm_offset_t)ptr, lo, hi, 0, flags | GSYNC_QUAD)
+
+/* Same as 'lll_wait', but only block for MLSEC milliseconds. */
+#define lll_timed_wait(ptr, val, mlsec, flags) \
+  __gsync_wait (__mach_task_self (), \
+    (vm_offset_t)ptr, val, 0, mlsec, flags | GSYNC_TIMED)
+
+/* Same as 'lll_xwait', but only block for MLSEC milliseconds. */
+#define lll_timed_xwait(ptr, lo, hi, mlsec, flags) \
+  __gsync_wait (__mach_task_self (), (vm_offset_t)ptr, \
+    lo, hi, mlsec, flags | GSYNC_TIMED | GSYNC_QUAD)
+
+/* Same as 'lll_wait', but only block until TSP elapses,
+ * using clock CLK. */
+extern int __lll_abstimed_wait (void *__ptr, int __val,
+  const struct timespec *__tsp, int __flags, int __clk);
+
+/* Same as 'lll_xwait', but only block until TSP elapses,
+ * using clock CLK. */
+extern int __lll_abstimed_xwait (void *__ptr, int __lo, int __hi,
+  const struct timespec *__tsp, int __flags, int __clk);
+
+/* Same as 'lll_lock', but return with an error if TSP elapses,
+ * using clock CLK. */
+extern int __lll_abstimed_lock (void *__ptr,
+  const struct timespec *__tsp, int __flags, int __clk);
+
+/* Acquire the lock at PTR, but return with an error if
+ * the process containing the owner thread dies. */
+extern int __lll_robust_lock (void *__ptr, int __flags);
+
+/* Same as '__lll_robust_lock', but only block until TSP
+ * elapses, using clock CLK. */
+extern int __lll_robust_abstimed_lock (void *__ptr,
+  const struct timespec *__tsp, int __flags, int __clk);
+
+/* Same as '__lll_robust_lock', but return with an error
+ * if the lock cannot be acquired without blocking. */
+extern int __lll_robust_trylock (void *__ptr);
+
+/* Wake one or more threads waiting on address PTR,
+ * setting its value to VAL before doing so. */
+#define lll_set_wake(ptr, val, flags) \
+  __gsync_wake (__mach_task_self (), \
+    (vm_offset_t)ptr, val, flags | GSYNC_MUTATE)
+
+/* Release the robust lock at PTR. */
+extern void __lll_robust_unlock (void *__ptr, int __flags);
+
+/* Rearrange threads waiting on address SRC to instead wait on
+ * DST, waking one of them if WAIT_ONE is non-zero. */
+#define lll_requeue(src, dst, wake_one, flags) \
+  __gsync_requeue (__mach_task_self (), (vm_offset_t)src, \
+    (vm_offset_t)dst, (boolean_t)wake_one, flags)
+
+/* The following are hacks that allow us to simulate optional
+ * parameters in C, to avoid having to pass the clock id for
+ * every one of these calls, defaulting to CLOCK_REALTIME if
+ * no argument is passed. */
+
+#define lll_abstimed_wait(ptr, val, tsp, flags, ...)   \
+  ({   \
+     const clockid_t __clk[] = { CLOCK_REALTIME, ##__VA_ARGS__ };   \
+     __lll_abstimed_wait ((ptr), (val), (tsp), (flags),   \
+       __clk[sizeof (__clk) / sizeof (__clk[0]) - 1]);   \
+   })
+
+#define lll_abstimed_xwait(ptr, lo, hi, tsp, flags, ...)   \
+  ({   \
+     const clockid_t __clk[] = { CLOCK_REALTIME, ##__VA_ARGS__ };   \
+     __lll_abstimed_xwait ((ptr), (lo), (hi), (tsp), (flags),   \
+       __clk[sizeof (__clk) / sizeof (__clk[0]) - 1]);   \
+   })
+
+#define lll_abstimed_lock(ptr, tsp, flags, ...)   \
+  ({   \
+     const clockid_t __clk[] = { CLOCK_REALTIME, ##__VA_ARGS__ };   \
+     __lll_abstimed_lock ((ptr), (tsp), (flags),   \
+       __clk[sizeof (__clk) / sizeof (__clk[0]) - 1]);   \
+   })
+
+#define lll_robust_abstimed_lock(ptr, tsp, flags, ...)   \
+  ({   \
+     const clockid_t __clk[] = { CLOCK_REALTIME, ##__VA_ARGS__ };   \
+     __lll_robust_abstimed_lock ((ptr), (tsp), (flags),   \
+       __clk[sizeof (__clk) / sizeof (__clk[0]) - 1]);   \
+   })
+
+
+#endif
diff --git a/hurd/hurdpid.c b/hurd/hurdpid.c
index e1dd093..33659cc 100644
--- a/hurd/hurdpid.c
+++ b/hurd/hurdpid.c
@@ -16,6 +16,8 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <hurd.h>
+#include <lowlevellock.h>
+
 pid_t _hurd_pid, _hurd_ppid, _hurd_pgrp;
 int _hurd_orphaned;
 
@@ -66,6 +68,7 @@ _S_msg_proc_newids (mach_port_t me,
 
   /* Notify any waiting user threads that the id change as been completed.  */
   ++_hurd_pids_changed_stamp;
+  lll_wake (&_hurd_pids_changed_stamp, GSYNC_BROADCAST);
 
   return 0;
 }
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index e215cf1..c6b8c63 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -1363,14 +1363,14 @@ reauth_proc (mach_port_t new)
   __mach_port_destroy (__mach_task_self (), ref);
 
   /* Set the owner of the process here too. */
-  mutex_lock (&_hurd_id.lock);
+  __mutex_lock (&_hurd_id.lock);
   if (!_hurd_check_ids ())
     HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
 		   __proc_setowner (port,
 				    (_hurd_id.gen.nuids
 				     ? _hurd_id.gen.uids[0] : 0),
 				    !_hurd_id.gen.nuids));
-  mutex_unlock (&_hurd_id.lock);
+  __mutex_unlock (&_hurd_id.lock);
 
   (void) &reauth_proc;		/* Silence compiler warning.  */
 }
diff --git a/hurd/setauth.c b/hurd/setauth.c
index deece20..025be58 100644
--- a/hurd/setauth.c
+++ b/hurd/setauth.c
@@ -18,14 +18,13 @@
 #include <hurd.h>
 #include <hurd/port.h>
 #include <hurd/id.h>
+#include <hurdlock.h>
 #include "set-hooks.h"
 
 /* Things in the library which want to be run when the auth port changes.  */
 DEFINE_HOOK (_hurd_reauth_hook, (auth_t new_auth));
 
-#include <cthreads.h>
-static struct mutex reauth_lock = MUTEX_INITIALIZER;
-
+static unsigned int reauth_lock = LLL_INITIALIZER;
 
 /* Set the auth port to NEW, and reauthenticate
    everything used by the library.  */
diff --git a/mach/Makefile b/mach/Makefile
index 50047c2..6d068b3 100644
--- a/mach/Makefile
+++ b/mach/Makefile
@@ -23,7 +23,7 @@ headers = mach_init.h mach.h mach_error.h mach-shortcuts.h mach/mach_traps.h \
 	  $(interface-headers) mach/mach.h mach/mig_support.h mach/error.h \
 	  $(lock-headers) machine-sp.h
 lock = spin-solid spin-lock mutex-init mutex-solid
-lock-headers = lock-intern.h machine-lock.h spin-lock.h
+lock-headers = lock-intern.h spin-lock.h
 routines = $(mach-syscalls) $(mach-shortcuts) \
 	   mach_init mig_strncpy msg \
 	   mig-alloc mig-dealloc mig-reply \
diff --git a/mach/lock-intern.h b/mach/lock-intern.h
index af28c3f..34175f5 100644
--- a/mach/lock-intern.h
+++ b/mach/lock-intern.h
@@ -19,62 +19,81 @@
 #define	_LOCK_INTERN_H
 
 #include <sys/cdefs.h>
-#include <machine-lock.h>
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+#include <lowlevellock.h>
+#endif
 
 #ifndef _EXTERN_INLINE
 #define _EXTERN_INLINE __extern_inline
 #endif
 
+/* The type of a spin lock variable. */
+typedef unsigned int __spin_lock_t;
+
+/* Static initializer for spinlocks. */
+#define __SPIN_LOCK_INITIALIZER   0
 
 /* Initialize LOCK.  */
 
 _EXTERN_INLINE void
 __spin_lock_init (__spin_lock_t *__lock)
 {
-  *__lock = __SPIN_LOCK_INITIALIZER;
+  *__lock = LLL_INITIALIZER;
 }
 
 
-/* Lock LOCK, blocking if we can't get it.  */
-extern void __spin_lock_solid (__spin_lock_t *__lock);
-
 /* Lock the spin lock LOCK.  */
 
 _EXTERN_INLINE void
 __spin_lock (__spin_lock_t *__lock)
 {
-  if (! __spin_try_lock (__lock))
-    __spin_lock_solid (__lock);
+  lll_lock (__lock, 0);
 }
-
-/* Name space-clean internal interface to mutex locks.
 
-   Code internal to the C library uses these functions to lock and unlock
-   mutex locks.  These locks are of type `struct mutex', defined in
-   <cthreads.h>.  The functions here are name space-clean.  If the program
-   is linked with the cthreads library, `__mutex_lock_solid' and
-   `__mutex_unlock_solid' will invoke the corresponding cthreads functions
-   to implement real mutex locks.  If not, simple stub versions just use
-   spin locks.  */
+/* Unlock LOCK. */
+void __spin_unlock (__spin_lock_t *__lock);
 
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+_EXTERN_INLINE void
+__spin_unlock (__spin_lock_t *__lock)
+{
+  lll_unlock (__lock, 0);
+}
+#endif
 
-/* Initialize the newly allocated mutex lock LOCK for further use.  */
-extern void __mutex_init (void *__lock);
+/* Try to lock LOCK; return nonzero if we locked it, zero if another has. */
+int __spin_try_lock (__spin_lock_t *__lock);
 
-/* Lock LOCK, blocking if we can't get it.  */
-extern void __mutex_lock_solid (void *__lock);
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+_EXTERN_INLINE int
+__spin_try_lock (__spin_lock_t *__lock)
+{
+  return (lll_trylock (__lock) == 0);
+}
+#endif
+
+/* Return nonzero if LOCK is locked. */
+int __spin_lock_locked (__spin_lock_t *__lock);
 
-/* Finish unlocking LOCK, after the spin lock LOCK->held has already been
-   unlocked.  This function will wake up any thread waiting on LOCK.  */
-extern void __mutex_unlock_solid (void *__lock);
+#if defined __USE_EXTERN_INLINES && defined _LIBC
+_EXTERN_INLINE int
+__spin_lock_locked (__spin_lock_t *__lock)
+{
+  return (*(volatile __spin_lock_t *)__lock != 0);
+}
+#endif
+
+/* Name space-clean internal interface to mutex locks. */
+
+/* Initialize the newly allocated mutex lock LOCK for further use.  */
+extern void __mutex_init (void *__lock);
 
 /* Lock the mutex lock LOCK.  */
 
 _EXTERN_INLINE void
 __mutex_lock (void *__lock)
 {
-  if (! __spin_try_lock ((__spin_lock_t *) __lock))
-    __mutex_lock_solid (__lock);
+  __spin_lock ((__spin_lock_t *)__lock);
 }
 
 /* Unlock the mutex lock LOCK.  */
@@ -82,15 +101,14 @@ __mutex_lock (void *__lock)
 _EXTERN_INLINE void
 __mutex_unlock (void *__lock)
 {
-  __spin_unlock ((__spin_lock_t *) __lock);
-  __mutex_unlock_solid (__lock);
+  __spin_unlock ((__spin_lock_t *)__lock);
 }
 
 
 _EXTERN_INLINE int
 __mutex_trylock (void *__lock)
 {
-  return __spin_try_lock ((__spin_lock_t *) __lock);
+  return (__spin_try_lock ((__spin_lock_t *)__lock));
 }
 
 #endif /* lock-intern.h */
diff --git a/mach/lowlevellock.h b/mach/lowlevellock.h
new file mode 100644
index 0000000..f22910f
--- /dev/null
+++ b/mach/lowlevellock.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 1994-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef __MACH_LOWLEVELLOCK_H__
+#define __MACH_LOWLEVELLOCK_H__   1
+
+#include <mach/gnumach.h>
+#include <atomic.h>
+
+/* Gsync flags. */
+#ifndef GSYNC_SHARED
+  #define GSYNC_SHARED      0x01
+  #define GSYNC_QUAD        0x02
+  #define GSYNC_TIMED       0x04
+  #define GSYNC_BROADCAST   0x08
+  #define GSYNC_MUTATE      0x10
+#endif
+
+/* Static initializer for low-level locks. */
+#define LLL_INITIALIZER   0
+
+/* Wait on address PTR, without blocking if its contents
+ * are different from VAL. */
+#define lll_wait(ptr, val, flags)   \
+  __gsync_wait (__mach_task_self (),   \
+    (vm_offset_t)(ptr), (val), 0, 0, (flags))
+
+/* Wake one or more threads waiting on address PTR. */
+#define lll_wake(ptr, flags)   \
+  __gsync_wake (__mach_task_self (), (vm_offset_t)(ptr), 0, (flags))
+
+/* Acquire the lock at PTR. */
+#define lll_lock(ptr, flags)   \
+  ({   \
+     int *__iptr = (int *)(ptr);   \
+     int __flags = (flags);   \
+     if (*__iptr != 0 ||   \
+         atomic_compare_and_exchange_bool_acq (__iptr, 1, 0) != 0)   \
+       while (1)   \
+         {   \
+           if (atomic_exchange_acq (__iptr, 2) == 0)   \
+             break;   \
+           lll_wait (__iptr, 2, __flags);   \
+         }   \
+     (void)0;   \
+   })
+
+/* Try to acquire the lock at PTR, without blocking.
+ * Evaluates to zero on success. */
+#define lll_trylock(ptr)   \
+  ({   \
+     int *__iptr = (int *)(ptr);   \
+     *__iptr == 0 &&   \
+       atomic_compare_and_exchange_bool_acq (__iptr, 1, 0) == 0 ? 0 : -1;   \
+   })
+
+/* Release the lock at PTR. */
+#define lll_unlock(ptr, flags)   \
+  ({   \
+     int *__iptr = (int *)(ptr);   \
+     if (atomic_exchange_rel (__iptr, 0) == 2)   \
+       lll_wake (__iptr, (flags));   \
+     (void)0;   \
+   })
+
+#endif
diff --git a/mach/mutex-init.c b/mach/mutex-init.c
index cab0a86..776fec5 100644
--- a/mach/mutex-init.c
+++ b/mach/mutex-init.c
@@ -17,13 +17,10 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <lock-intern.h>
-#include <cthreads.h>
+#include <lowlevellock.h>
 
 void
 __mutex_init (void *lock)
 {
-  /* This happens to be name space-safe because it is a macro.
-     It invokes only spin_lock_init, which is a macro for __spin_lock_init;
-     and cthread_queue_init, which is a macro for some simple code.  */
-  mutex_init ((struct mutex *) lock);
+  *(int *)lock = LLL_INITIALIZER;
 }
diff --git a/sysdeps/mach/Makefile b/sysdeps/mach/Makefile
index 2b48b13..95b83d8 100644
--- a/sysdeps/mach/Makefile
+++ b/sysdeps/mach/Makefile
@@ -50,4 +50,25 @@ mach-before-compile:
 before-compile += $(mach-before-compile)
 endif
 
+ifeq (crypt,$(subdir))
+  LDLIBS-crypt.so += $(objdir)/mach/libmachuser.so
+else ifeq (dlfcn,$(subdir))
+  LDLIBS-dl.so += $(objdir)/mach/libmachuser.so
+else ifeq (nis,$(subdir))
+  LDLIBS-nsl.so += $(objdir)/mach/libmachuser.so
+  LDLIBS-nss_nis.so += $(objdir)/mach/libmachuser.so
+  LDLIBS-nss_nisplus.so += $(objdir)/mach/libmachuser.so
+  LDLIBS-nss_compat.so += $(objdir)/mach/libmachuser.so
+else ifeq (nss,$(subdir))
+  LDLIBS-nss.so += $(objdir)/mach/libmachuser.so
+  LDLIBS-nss_files.so += $(objdir)/mach/libmachuser.so
+  LDLIBS-nss_compat.so += $(objdir)/mach/libmachuser.so
+else ifeq (hesiod,$(subdir))
+  LDLIBS-nss_hesiod.so += $(objdir)/mach/libmachuser.so
+else ifeq (posix,$(subdir))
+  LDLIBS-tst-rfc3484 += $(objdir)/mach/libmachuser.so
+  LDLIBS-tst-rfc3484-2 += $(objdir)/mach/libmachuser.so
+  LDLIBS-tst-rfc3484-3 += $(objdir)/mach/libmachuser.so
+endif
+
 endif	# in-Makerules
diff --git a/sysdeps/mach/hurd/bits/errno.h b/sysdeps/mach/hurd/bits/errno.h
index f0a11af..1a9feda 100644
--- a/sysdeps/mach/hurd/bits/errno.h
+++ b/sysdeps/mach/hurd/bits/errno.h
@@ -127,6 +127,8 @@ enum __error_t_codes
   EPROTO                         = 0x40000074,	/* Protocol error */
   ETIME                          = 0x40000075,	/* Timer expired */
   ECANCELED                      = 0x40000077,	/* Operation canceled */
+  EOWNERDEAD                     = 0x40000078,	/* Robust mutex owner died */
+  ENOTRECOVERABLE                = 0x40000079,	/* Robust mutex irrecoverable */
 
 /* Errors from <mach/message.h>.  */
   EMACH_SEND_IN_PROGRESS         = 0x10000001,
@@ -330,6 +332,8 @@ typedef enum __error_t_codes error_t;
 #define EPROTO                         0x40000074
 #define ETIME                          0x40000075
 #define ECANCELED                      0x40000077
+#define EOWNERDEAD                     0x40000078
+#define ENOTRECOVERABLE                0x40000079
 
 /* Errors from <mach/message.h>.  */
 #define EMACH_SEND_IN_PROGRESS         0x10000001
@@ -413,6 +417,6 @@ typedef enum __error_t_codes error_t;
 #define ED_NO_MEMORY                   2508
 #define ED_READ_ONLY                   2509
 
-#define _HURD_ERRNOS 120
+#define _HURD_ERRNOS 122
 
 #endif /* bits/errno.h.  */
diff --git a/sysdeps/mach/hurd/libc-lock.h b/sysdeps/mach/hurd/libc-lock.h
deleted file mode 100644
index b7fffd0..0000000
--- a/sysdeps/mach/hurd/libc-lock.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/* libc-internal interface for mutex locks.  Hurd version using Mach cthreads.
-   Copyright (C) 1996-2018 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, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _LIBC_LOCK_H
-#define _LIBC_LOCK_H 1
-
-#if (_LIBC - 0) || (_CTHREADS_ - 0)
-# if (_LIBC - 0)
-#  include <tls.h>
-# endif
-#include <cthreads.h>
-
-/* The locking here is very inexpensive, even for inlining.  */
-#define _IO_lock_inexpensive  1
-
-typedef struct mutex __libc_lock_t;
-typedef struct
-{
-  struct mutex mutex;
-  void *owner;
-  int count;
-} __libc_lock_recursive_t;
-typedef __libc_lock_recursive_t __rtld_lock_recursive_t;
-
-extern char __libc_lock_self0[0];
-#define __libc_lock_owner_self() (__LIBC_NO_TLS() ? &__libc_lock_self0 : THREAD_SELF)
-
-#else
-typedef struct __libc_lock_opaque__ __libc_lock_t;
-typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
-#endif
-
-/* 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 an initialized lock variable NAME with storage class CLASS.  */
-#define _LIBC_LOCK_INITIALIZER MUTEX_INITIALIZER
-#define __libc_lock_define_initialized(CLASS,NAME) \
-  CLASS __libc_lock_t NAME = _LIBC_LOCK_INITIALIZER;
-
-/* Initialize the named lock variable, leaving it in a consistent, unlocked
-   state.  */
-#define __libc_lock_init(NAME) __mutex_init (&(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) __mutex_unlock (&(NAME))
-#define __libc_lock_fini_recursive(NAME) __mutex_unlock (&(NAME).mutex)
-#define __rtld_lock_fini_recursive(NAME) __mutex_unlock (&(NAME).mutex)
-
-
-/* Lock the named lock variable.  */
-#define __libc_lock_lock(NAME) __mutex_lock (&(NAME))
-
-/* Lock the named lock variable.  */
-#define __libc_lock_trylock(NAME) (!__mutex_trylock (&(NAME)))
-
-/* Unlock the named lock variable.  */
-#define __libc_lock_unlock(NAME) __mutex_unlock (&(NAME))
-
-
-#define __libc_lock_define_recursive(CLASS,NAME) \
-  CLASS __libc_lock_recursive_t NAME;
-#define _LIBC_LOCK_RECURSIVE_INITIALIZER { MUTEX_INITIALIZER, 0, 0 }
-#define __libc_lock_define_initialized_recursive(CLASS,NAME) \
-  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
-
-#define __rtld_lock_define_recursive(CLASS,NAME) \
-  __libc_lock_define_recursive (CLASS, NAME)
-#define _RTLD_LOCK_RECURSIVE_INITIALIZER \
-  _LIBC_LOCK_RECURSIVE_INITIALIZER
-#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
-  __libc_lock_define_initialized_recursive (CLASS, NAME)
-
-#define __libc_lock_init_recursive(NAME) \
-  ({ __libc_lock_recursive_t *const __lock = &(NAME); \
-     __lock->owner = 0; mutex_init (&__lock->mutex); })
-
-#define __libc_lock_trylock_recursive(NAME)				      \
-  ({ __libc_lock_recursive_t *const __lock = &(NAME);			      \
-     void *__self = __libc_lock_owner_self ();				      \
-     __mutex_trylock (&__lock->mutex)					      \
-     ? (__lock->owner = __self, __lock->count = 1, 0)			      \
-     : __lock->owner == __self ? (++__lock->count, 0) : 1; })
-
-#define __libc_lock_lock_recursive(NAME)				      \
-  ({ __libc_lock_recursive_t *const __lock = &(NAME);			      \
-     void *__self = __libc_lock_owner_self ();				      \
-     if (__mutex_trylock (&__lock->mutex)				      \
-	 || (__lock->owner != __self					      \
-	     && (__mutex_lock (&__lock->mutex), 1)))			      \
-       __lock->owner = __self, __lock->count = 1;			      \
-     else								      \
-       ++__lock->count;							      \
-  })
-#define __libc_lock_unlock_recursive(NAME)				      \
-  ({ __libc_lock_recursive_t *const __lock = &(NAME);			      \
-     if (--__lock->count == 0)						      \
-       {								      \
-	 __lock->owner = 0;						      \
-	 __mutex_unlock (&__lock->mutex);				      \
-       }								      \
-  })
-
-
-#define __rtld_lock_initialize(NAME) \
-  (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
-#define __rtld_lock_trylock_recursive(NAME) \
-  __libc_lock_trylock_recursive (NAME)
-#define __rtld_lock_lock_recursive(NAME) \
-  __libc_lock_lock_recursive(NAME)
-#define __rtld_lock_unlock_recursive(NAME) \
-  __libc_lock_unlock_recursive (NAME)
-
-
-/* XXX for now */
-#define __libc_rwlock_define		__libc_lock_define
-#define __libc_rwlock_define_initialized __libc_lock_define_initialized
-#define __libc_rwlock_init		__libc_lock_init
-#define __libc_rwlock_fini		__libc_lock_fini
-#define __libc_rwlock_rdlock		__libc_lock_lock
-#define __libc_rwlock_wrlock		__libc_lock_lock
-#define __libc_rwlock_tryrdlock		__libc_lock_trylock
-#define __libc_rwlock_trywrlock		__libc_lock_trylock
-#define __libc_rwlock_unlock		__libc_lock_unlock
-
-
-/* Start a critical region with a cleanup function */
-#define __libc_cleanup_region_start(DOIT, FCT, ARG)			    \
-{									    \
-  typeof (***(FCT)) *__save_FCT = (DOIT) ? (FCT) : 0;			    \
-  typeof (ARG) __save_ARG = ARG;					    \
-  /* close brace is in __libc_cleanup_region_end below. */
-
-/* End a critical region started with __libc_cleanup_region_start. */
-#define __libc_cleanup_region_end(DOIT)					    \
-  if ((DOIT) && __save_FCT != 0)					    \
-    (*__save_FCT)(__save_ARG);						    \
-}
-
-/* Sometimes we have to exit the block in the middle.  */
-#define __libc_cleanup_end(DOIT)					    \
-  if ((DOIT) && __save_FCT != 0)					    \
-    (*__save_FCT)(__save_ARG);						    \
-
-#define __libc_cleanup_push(fct, arg) __libc_cleanup_region_start (1, fct, arg)
-#define __libc_cleanup_pop(execute) __libc_cleanup_region_end (execute)
-
-#if (_CTHREADS_ - 0)
-
-/* Use mutexes as once control variables. */
-
-struct __libc_once
-  {
-    __libc_lock_t lock;
-    int done;
-  };
-
-#define __libc_once_define(CLASS,NAME) \
-  CLASS struct __libc_once NAME = { MUTEX_INITIALIZER, 0 }
-
-/* Call handler iff the first call.  */
-#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
-  do {									      \
-    __libc_lock_lock (ONCE_CONTROL.lock);				      \
-    if (!ONCE_CONTROL.done)						      \
-      (INIT_FUNCTION) ();						      \
-    ONCE_CONTROL.done = 1;						      \
-    __libc_lock_unlock (ONCE_CONTROL.lock);				      \
-  } while (0)
-
-/* Get once control variable.  */
-#define __libc_once_get(ONCE_CONTROL)	((ONCE_CONTROL).done != 0)
-
-#ifdef _LIBC
-/* We need portable names for some functions.  E.g., when they are
-   used as argument to __libc_cleanup_region_start.  */
-#define __libc_mutex_unlock __mutex_unlock
-#endif
-
-/* Type for key of thread specific data.  */
-typedef cthread_key_t __libc_key_t;
-
-#define __libc_key_create(KEY,DEST) cthread_keycreate (KEY)
-#define __libc_setspecific(KEY,VAL) cthread_setspecific (KEY, VAL)
-void *__libc_getspecific (__libc_key_t key);
-
-#endif /* _CTHREADS_ */
-
-/* Hide the definitions which are only supposed to be used inside libc in
-   a separate file.  This file is not present in the installation!  */
-#ifdef _LIBC
-# include <libc-lockP.h>
-#endif
-
-#endif	/* libc-lock.h */
diff --git a/sysdeps/mach/hurd/setpgid.c b/sysdeps/mach/hurd/setpgid.c
index 32186a2..98b1341 100644
--- a/sysdeps/mach/hurd/setpgid.c
+++ b/sysdeps/mach/hurd/setpgid.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <hurd.h>
 #include <hurd/port.h>
+#include <lowlevellock.h>
 
 /* Set the process group ID of the process matching PID to PGID.
    If PID is zero, the current process's process group ID is set.
@@ -38,14 +39,7 @@ __setpgid (pid_t pid, pid_t pgid)
     /* Synchronize with the signal thread to make sure we have
        received and processed proc_newids before returning to the user.  */
     while (_hurd_pids_changed_stamp == stamp)
-      {
-#ifdef noteven
-	/* XXX we have no need for a mutex, but cthreads demands one.  */
-	__condition_wait (&_hurd_pids_changed_sync, NULL);
-#else
-	__swtch_pri(0);
-#endif
-      }
+      lll_wait (&_hurd_pids_changed_stamp, stamp, 0);
 
   return 0;
 
diff --git a/sysdeps/mach/hurd/setsid.c b/sysdeps/mach/hurd/setsid.c
index 0f6b24b..7b98936 100644
--- a/sysdeps/mach/hurd/setsid.c
+++ b/sysdeps/mach/hurd/setsid.c
@@ -21,6 +21,7 @@
 #include <hurd/port.h>
 #include <hurd/fd.h>
 #include <hurd/ioctl.h>
+#include <lowlevellock.h>
 
 /* Create a new session with the calling process as its leader.
    The process group IDs of the session and the calling process
@@ -55,14 +56,7 @@ __setsid (void)
 	 returned by `getpgrp ()' in other threads) has been updated before
 	 we return.  */
       while (_hurd_pids_changed_stamp == stamp)
-	{
-#ifdef noteven
-	  /* XXX we have no need for a mutex, but cthreads demands one.  */
-	  __condition_wait (&_hurd_pids_changed_sync, NULL);
-#else
-	  __swtch_pri (0);
-#endif
-	}
+        lll_wait (&_hurd_pids_changed_stamp, stamp, 0);
     }
 
   HURD_CRITICAL_END;
diff --git a/sysdeps/mach/libc-lock.h b/sysdeps/mach/libc-lock.h
index caeba47..767f45e 100644
--- a/sysdeps/mach/libc-lock.h
+++ b/sysdeps/mach/libc-lock.h
@@ -20,10 +20,31 @@
 #define _LIBC_LOCK_H 1
 
 #ifdef _LIBC
+
+#include <tls.h>
 #include <cthreads.h>
-#define __libc_lock_t struct mutex
+#include <lowlevellock.h>
+
+/* The locking here is very inexpensive, even for inlining. */
+#define _IO_lock_inexpensive   1
+
+typedef unsigned int __libc_lock_t;
+typedef struct
+{
+  __libc_lock_t lock;
+  int cnt;
+  void *owner;
+} __libc_lock_recursive_t;
+
+typedef __libc_lock_recursive_t __rtld_lock_recursive_t;
+
+extern char __libc_lock_self0[0];
+#define __libc_lock_owner_self()   \
+  (__LIBC_NO_TLS() ? (void *)&__libc_lock_self0 : THREAD_SELF)
+
 #else
 typedef struct __libc_lock_opaque__ __libc_lock_t;
+typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
 #endif
 
 /* Type for key of thread specific data.  */
@@ -40,27 +61,94 @@ typedef cthread_key_t __libc_key_t;
   CLASS __libc_lock_t NAME;
 
 /* Define an initialized lock variable NAME with storage class CLASS.  */
+#define _LIBC_LOCK_INITIALIZER LLL_INITIALIZER
 #define __libc_lock_define_initialized(CLASS,NAME) \
-  CLASS __libc_lock_t NAME = MUTEX_INITIALIZER;
+  CLASS __libc_lock_t NAME = LLL_INITIALIZER;
 
 /* Initialize the named lock variable, leaving it in a consistent, unlocked
    state.  */
-#define __libc_lock_init(NAME) __mutex_init (&(NAME))
+#define __libc_lock_init(NAME) (NAME) = LLL_INITIALIZER
 
 /* 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) __mutex_unlock (&(NAME))
+#define __libc_lock_fini             __libc_lock_unlock
+#define __libc_lock_fini_recursive   __libc_lock_unlock_recursive
+#define __rtld_lock_fini_recursive   __rtld_lock_unlock_recursive
 
 /* Lock the named lock variable.  */
-#define __libc_lock_lock(NAME) __mutex_lock (&(NAME))
+#define __libc_lock_lock(NAME)   \
+  ({ lll_lock (&(NAME), 0); 0; })
 
 /* Lock the named lock variable.  */
-#define __libc_lock_trylock(NAME) (!__mutex_trylock (&(NAME)))
+#define __libc_lock_trylock(NAME) lll_trylock (&(NAME))
 
 /* Unlock the named lock variable.  */
-#define __libc_lock_unlock(NAME) __mutex_unlock (&(NAME))
-
+#define __libc_lock_unlock(NAME)   \
+  ({ lll_unlock (&(NAME), 0); 0; })
+
+#define __libc_lock_define_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME;
+
+#define _LIBC_LOCK_RECURSIVE_INITIALIZER { LLL_INITIALIZER, 0, 0 }
+
+#define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
+
+#define __rtld_lock_define_recursive(CLASS,NAME) \
+  __libc_lock_define_recursive (CLASS, NAME)
+#define _RTLD_LOCK_RECURSIVE_INITIALIZER \
+  _LIBC_LOCK_RECURSIVE_INITIALIZER
+#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
+  __libc_lock_define_initialized_recursive (CLASS, NAME)
+
+#define __libc_lock_init_recursive(NAME)   \
+  ((NAME) = (__libc_lock_recursive_t)_LIBC_LOCK_RECURSIVE_INITIALIZER, 0)
+
+#define __libc_lock_trylock_recursive(NAME)   \
+  ({   \
+     __libc_lock_recursive_t *const __lock = &(NAME);   \
+     void *__self = __libc_lock_owner_self ();   \
+     int __r = 0;   \
+     if (__self == __lock->owner)   \
+       ++__lock->cnt;   \
+     else if ((__r = lll_trylock (&__lock->lock)) == 0)   \
+       __lock->owner = __self, __lock->cnt = 1;   \
+     __r;   \
+   })
+
+#define __libc_lock_lock_recursive(NAME)   \
+  ({   \
+     __libc_lock_recursive_t *const __lock = &(NAME);   \
+     void *__self = __libc_lock_owner_self ();   \
+     if (__self != __lock->owner)   \
+       {   \
+         lll_lock (&__lock->lock, 0);   \
+         __lock->owner = __self;   \
+       }   \
+     ++__lock->cnt;   \
+     (void)0;   \
+   })
+
+#define __libc_lock_unlock_recursive(NAME)   \
+  ({   \
+     __libc_lock_recursive_t *const __lock = &(NAME);   \
+     if (--__lock->cnt == 0)   \
+       {   \
+         __lock->owner = 0;   \
+         lll_unlock (&__lock->lock, 0);   \
+       }   \
+   })
+
+
+#define __rtld_lock_initialize(NAME) \
+  (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
+#define __rtld_lock_trylock_recursive(NAME) \
+  __libc_lock_trylock_recursive (NAME)
+#define __rtld_lock_lock_recursive(NAME) \
+  __libc_lock_lock_recursive(NAME)
+#define __rtld_lock_unlock_recursive(NAME) \
+  __libc_lock_unlock_recursive (NAME)
 
 /* XXX for now */
 #define __libc_rwlock_define		__libc_lock_define
@@ -73,25 +161,38 @@ typedef cthread_key_t __libc_key_t;
 #define __libc_rwlock_trywrlock		__libc_lock_trylock
 #define __libc_rwlock_unlock		__libc_lock_unlock
 
+struct __libc_cleanup_frame
+{
+  void (*__fct) (void *);
+  void *__argp;
+  int __doit;
+};
+
+__extern_inline void
+__libc_cleanup_fct (struct __libc_cleanup_frame *framep)
+{
+  if (framep->__doit)
+    framep->__fct (framep->__argp);
+}
 
 /* Start a critical region with a cleanup function */
-#define __libc_cleanup_region_start(DOIT, FCT, ARG)			    \
-{									    \
-  typeof (***(FCT)) *__save_FCT = (DOIT) ? (FCT) : 0;			    \
-  typeof (ARG) __save_ARG = ARG;					    \
-  /* close brace is in __libc_cleanup_region_end below. */
-
-/* End a critical region started with __libc_cleanup_region_start. */
-#define __libc_cleanup_region_end(DOIT)					    \
-  if ((DOIT) && __save_FCT != 0)					    \
-    (*__save_FCT)(__save_ARG);						    \
-}
+#define __libc_cleanup_region_start(DOIT, FCT, ARG)   \
+  do   \
+    {   \
+      struct __libc_cleanup_frame __cleanup   \
+        __attribute__ ((__cleanup__ (__libc_cleanup_fct))) =   \
+        { .__fct = (FCT), .__argp = (ARG), .__doit = (DOIT) };
+
+/* This one closes the brace above. */
+#define __libc_cleanup_region_end(DOIT)   \
+      __cleanup.__doit = (DOIT);   \
+    }   \
+  while (0)
 
-/* Sometimes we have to exit the block in the middle.  */
-#define __libc_cleanup_end(DOIT)					    \
-  if ((DOIT) && __save_FCT != 0)					    \
-    (*__save_FCT)(__save_ARG);						    \
+#define __libc_cleanup_end(DOIT)   __cleanup.__doit = (DOIT);
 
+#define __libc_cleanup_push(fct, arg) __libc_cleanup_region_start (1, fct, arg)
+#define __libc_cleanup_pop(execute) __libc_cleanup_region_end (execute)
 
 /* Use mutexes as once control variables. */
 
@@ -102,8 +203,7 @@ struct __libc_once
   };
 
 #define __libc_once_define(CLASS,NAME) \
-  CLASS struct __libc_once NAME = { MUTEX_INITIALIZER, 0 }
-
+  CLASS struct __libc_once NAME = { _LIBC_LOCK_INITIALIZER, 0 }
 
 /* Call handler iff the first call.  */
 #define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
@@ -121,25 +221,15 @@ struct __libc_once
 #ifdef _LIBC
 /* We need portable names for some functions.  E.g., when they are
    used as argument to __libc_cleanup_region_start.  */
-#define __libc_mutex_unlock __mutex_unlock
-#endif
+#define __libc_mutex_unlock __libc_lock_unlock
 
 #define __libc_key_create(KEY,DEST) cthread_keycreate (KEY)
 #define __libc_setspecific(KEY,VAL) cthread_setspecific (KEY, VAL)
 void *__libc_getspecific (__libc_key_t key);
 
-/* XXX until cthreads supports recursive locks */
-#define __libc_lock_define_initialized_recursive __libc_lock_define_initialized
-#define __libc_lock_init_recursive __libc_lock_init
-#define __libc_lock_fini_recursive __libc_lock_fini
-#define __libc_lock_trylock_recursive __libc_lock_trylock
-#define __libc_lock_unlock_recursive __libc_lock_unlock
-#define __libc_lock_lock_recursive __libc_lock_lock
-
-#define __rtld_lock_define_initialized_recursive __libc_lock_define_initialized
-#define __rtld_lock_fini_recursive __libc_lock_fini
-#define __rtld_lock_trylock_recursive __libc_lock_trylock
-#define __rtld_lock_unlock_recursive __libc_lock_unlock
-#define __rtld_lock_lock_recursive __libc_lock_lock
+/* Hide the definitions which are only supposed to be used inside libc in
+   a separate file.  This file is not present in the installation!  */
+# include <libc-lockP.h>
+#endif
 
 #endif	/* libc-lock.h */

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e4a5aad430c83a229df5d32fd06d48775f39720d

commit e4a5aad430c83a229df5d32fd06d48775f39720d
Author: Thomas Schwinge <thomas@schwinge.name>
Date:   Fri Jan 19 02:18:09 2018 +0100

    t/tls-threadvar
    
    replace the custom threadvar mechanism with generic TLS.
    That will fix sigaltstack.
    
    Note: the added reply_port and _hurd_sigstate fields should be kept last.

diff --git a/hurd/Versions b/hurd/Versions
index 8b84f73..6db2a9c 100644
--- a/hurd/Versions
+++ b/hurd/Versions
@@ -4,14 +4,9 @@ libc {
     _end;
 
     # variables used in macros & inline functions
-    __hurd_sigthread_stack_base; __hurd_sigthread_stack_end;
-    __hurd_sigthread_variables;
     __hurd_threadvar_max;
     __hurd_threadvar_stack_mask; __hurd_threadvar_stack_offset;
 
-    # functions used in macros & inline functions
-    __hurd_errno_location;
-
     # functions used in libmachuser and libhurduser
     _S_catch_exception_raise;
     _S_catch_exception_raise_state;
@@ -143,6 +138,7 @@ libc {
   HURD_CTHREADS_0.3 {
     # weak refs to libthreads functions that libc calls iff libthreads in use
     cthread_fork; cthread_detach;
+    pthread_getattr_np; pthread_attr_getstack;
 
     # variables used for detecting cthreads
     _cthread_exit_routine; _cthread_init_routine;
diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
index 233d10f..0e6a969 100644
--- a/hurd/hurd/signal.h
+++ b/hurd/hurd/signal.h
@@ -40,7 +40,6 @@
 #include <cthreads.h>		/* For `struct mutex'.  */
 #include <setjmp.h>		/* For `jmp_buf'.  */
 #include <spin-lock.h>
-#include <hurd/threadvar.h>	/* We cache sigstate in a threadvar.  */
 struct hurd_signal_preemptor;	/* <hurd/sigpreempt.h> */
 #if defined __USE_EXTERN_INLINES && defined _LIBC
 #  if IS_IN (libc)
@@ -137,11 +136,9 @@ extern struct hurd_sigstate *_hurd_self_sigstate (void)
 _HURD_SIGNAL_H_EXTERN_INLINE struct hurd_sigstate *
 _hurd_self_sigstate (void)
 {
-  struct hurd_sigstate **location = (struct hurd_sigstate **)
-    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
-  if (*location == NULL)
-    *location = _hurd_thread_sigstate (__mach_thread_self ());
-  return *location;
+  if (THREAD_SELF->_hurd_sigstate == NULL)
+    THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (__mach_thread_self ());
+  return THREAD_SELF->_hurd_sigstate;
 }
 
 /* Thread listening on our message port; also called the "signal thread".  */
@@ -172,16 +169,22 @@ extern int _hurd_core_limit;
 _HURD_SIGNAL_H_EXTERN_INLINE void *
 _hurd_critical_section_lock (void)
 {
-  struct hurd_sigstate **location = (struct hurd_sigstate **)
-    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
-  struct hurd_sigstate *ss = *location;
+  struct hurd_sigstate *ss;
+
+#ifdef __LIBC_NO_TLS
+  if (__LIBC_NO_TLS())
+    /* TLS is currently initializing, no need to enter critical section.  */
+    return NULL;
+#endif
+
+  ss = THREAD_SELF->_hurd_sigstate;
   if (ss == NULL)
     {
       /* The thread variable is unset; this must be the first time we've
 	 asked for it.  In this case, the critical section flag cannot
 	 possible already be set.  Look up our sigstate structure the slow
 	 way.  */
-      ss = *location = _hurd_thread_sigstate (__mach_thread_self ());
+      ss = THREAD_SELF->_hurd_sigstate = _hurd_thread_sigstate (__mach_thread_self ());
     }
 
   if (! __spin_try_lock (&ss->critical_section_lock))
diff --git a/hurd/hurd/threadvar.h b/hurd/hurd/threadvar.h
index 1727dac..0887a17 100644
--- a/hurd/hurd/threadvar.h
+++ b/hurd/hurd/threadvar.h
@@ -20,6 +20,7 @@
 #define	_HURD_THREADVAR_H
 
 #include <features.h>
+#include <tls.h>
 
 /* The per-thread variables are found by ANDing this mask
    with the value of the stack pointer and then adding this offset.
@@ -30,87 +31,24 @@
    __hurd_threadvar_stack_offset to a small offset that skips the data
    cthreads itself maintains at the base of each thread's stack.
 
-   In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the
-   stack pointer is ignored; and __hurd_threadvar_stack_offset gives the
-   address of a small allocated region which contains the variables for the
-   single thread.  */
+   In the single-threaded or libpthread case, __hurd_threadvar_stack_mask is
+   zero, so the stack pointer is ignored. */
 
 extern unsigned long int __hurd_threadvar_stack_mask;
 extern unsigned long int __hurd_threadvar_stack_offset;
 
-/* A special case must always be made for the signal thread.  Even when there
-   is only one user thread and an allocated region can be used for the user
-   thread's variables, the signal thread needs to have its own location for
-   per-thread variables.  The variables __hurd_sigthread_stack_base and
+/* The variables __hurd_sigthread_stack_base and
    __hurd_sigthread_stack_end define the bounds of the stack used by the
    signal thread, so that thread can always be specifically identified.  */
 
 extern unsigned long int __hurd_sigthread_stack_base;
 extern unsigned long int __hurd_sigthread_stack_end;
-extern unsigned long int *__hurd_sigthread_variables;
 
 
-/* At the location described by the two variables above,
-   there are __hurd_threadvar_max `unsigned long int's of per-thread data.  */
+/* We do not use threadvars any more, this is kept as zero for compatibility with cthreads */
 extern unsigned int __hurd_threadvar_max;
 
-/* These values are the indices for the standard per-thread variables.  */
-enum __hurd_threadvar_index
-  {
-    _HURD_THREADVAR_MIG_REPLY,	/* Reply port for MiG user stub functions.  */
-    _HURD_THREADVAR_ERRNO,	/* `errno' value for this thread.  */
-    _HURD_THREADVAR_SIGSTATE,	/* This thread's `struct hurd_sigstate'.  */
-    _HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables.  */
-    _HURD_THREADVAR_MALLOC,	/* For use of malloc.  */
-    _HURD_THREADVAR_DL_ERROR,	/* For use of -ldl and dynamic linker.  */
-    _HURD_THREADVAR_RPC_VARS,	/* For state of RPC functions.  */
-    _HURD_THREADVAR_LOCALE,	/* For thread-local locale setting.  */
-    _HURD_THREADVAR_CTYPE_B,	/* Cache of thread-local locale data.  */
-    _HURD_THREADVAR_CTYPE_TOLOWER, /* Cache of thread-local locale data.  */
-    _HURD_THREADVAR_CTYPE_TOUPPER, /* Cache of thread-local locale data.  */
-    _HURD_THREADVAR_MAX		/* Default value for __hurd_threadvar_max.  */
-  };
-
-
-#ifndef _HURD_THREADVAR_H_EXTERN_INLINE
-#define _HURD_THREADVAR_H_EXTERN_INLINE __extern_inline
-#endif
-
-/* Return the location of the value for the per-thread variable with index
-   INDEX used by the thread whose stack pointer is SP.  */
-
-extern unsigned long int *__hurd_threadvar_location_from_sp
-  (enum __hurd_threadvar_index __index, void *__sp);
-_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
-__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index,
-				   void *__sp)
-{
-  unsigned long int __stack = (unsigned long int) __sp;
-  return &((__stack >= __hurd_sigthread_stack_base &&
-	    __stack < __hurd_sigthread_stack_end)
-	   ? __hurd_sigthread_variables
-	   : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) +
-				    __hurd_threadvar_stack_offset))[__index];
-}
-
-#include <machine-sp.h>		/* Define __thread_stack_pointer.  */
-
-/* Return the location of the current thread's value for the
-   per-thread variable with index INDEX.  */
-
-extern unsigned long int *
-__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW
-     /* This declaration tells the compiler that the value is constant
-	given the same argument.  We assume this won't be called twice from
-	the same stack frame by different threads.  */
-     __attribute__ ((__const__));
-
-_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
-__hurd_threadvar_location (enum __hurd_threadvar_index __index)
-{
-  return __hurd_threadvar_location_from_sp (__index,
-					    __thread_stack_pointer ());
-}
-
+extern mach_port_t __hurd_reply_port0;
+#define __hurd_local_reply_port (*(__LIBC_NO_TLS() ? &__hurd_reply_port0 : &THREAD_SELF->reply_port))
 
 #endif	/* hurd/threadvar.h */
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 3e587a4..e215cf1 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -20,6 +20,7 @@
 #include <string.h>
 
 #include <cthreads.h>		/* For `struct mutex'.  */
+#include <pthread.h>
 #include <mach.h>
 #include <mach/thread_switch.h>
 
@@ -48,7 +49,6 @@ thread_t _hurd_sigthread;
 /* These are set up by _hurdsig_init.  */
 unsigned long int __hurd_sigthread_stack_base;
 unsigned long int __hurd_sigthread_stack_end;
-unsigned long int *__hurd_sigthread_variables;
 
 /* Linked-list of per-thread signal state.  */
 struct hurd_sigstate *_hurd_sigstates;
@@ -234,14 +234,14 @@ abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
    that this location can be set without faulting, or else return NULL.  */
 
 static mach_port_t *
-interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
+interrupted_reply_port_location (thread_t thread,
+				 struct machine_thread_all_state *thread_state,
 				 int sigthread)
 {
-  mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
-    (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
+  mach_port_t *portloc = &THREAD_TCB(thread, thread_state)->reply_port;
 
   if (sigthread && _hurdsig_catch_memory_fault (portloc))
-    /* Faulted trying to read the stack.  */
+    /* Faulted trying to read the TCB.  */
     return NULL;
 
   /* Fault now if this pointer is bogus.  */
@@ -323,7 +323,8 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
 	   our nonzero return tells the trampoline code to finish the message
 	   receive operation before running the handler.  */
 
-	mach_port_t *reply = interrupted_reply_port_location (state,
+	mach_port_t *reply = interrupted_reply_port_location (ss->thread,
+							      state,
 							      sigthread);
 	error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);
 
@@ -835,7 +836,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 
 	    if (! machine_get_basic_state (ss->thread, &thread_state))
 	      goto sigbomb;
-	    loc = interrupted_reply_port_location (&thread_state, 1);
+	    loc = interrupted_reply_port_location (ss->thread,
+						   &thread_state, 1);
 	    if (loc && *loc != MACH_PORT_NULL)
 	      /* This is the reply port for the context which called
 		 sigreturn.  Since we are abandoning that context entirely
@@ -901,7 +903,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	{
 	  /* Fetch the thread variable for the MiG reply port,
 	     and set it to MACH_PORT_NULL.  */
-	  mach_port_t *loc = interrupted_reply_port_location (&thread_state,
+	  mach_port_t *loc = interrupted_reply_port_location (ss->thread,
+							      &thread_state,
 							      1);
 	  if (loc)
 	    {
@@ -1255,7 +1258,11 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
 
   /* Start the signal thread listening on the message port.  */
 
-  if (__hurd_threadvar_stack_mask == 0)
+#pragma weak cthread_fork
+#pragma weak cthread_detach
+#pragma weak pthread_getattr_np
+#pragma weak pthread_attr_getstack
+  if (!cthread_fork)
     {
       err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
       assert_perror (err);
@@ -1270,14 +1277,6 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
       assert_perror (err);
 
       __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
-      __hurd_sigthread_variables =
-	malloc (__hurd_threadvar_max * sizeof (unsigned long int));
-      if (__hurd_sigthread_variables == NULL)
-	__libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
-      memset (__hurd_sigthread_variables, 0,
-	      __hurd_threadvar_max * sizeof (unsigned long int));
-      __hurd_sigthread_variables[_HURD_THREADVAR_LOCALE]
-	= (unsigned long int) &_nl_global_locale;
 
       /* Reinitialize the MiG support routines so they will use a per-thread
 	 variable for the cached reply port.  */
@@ -1288,6 +1287,7 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
     }
   else
     {
+      cthread_t thread;
       /* When cthreads is being used, we need to make the signal thread a
          proper cthread.  Otherwise it cannot use mutex_lock et al, which
          will be the cthreads versions.  Various of the message port RPC
@@ -1297,9 +1297,20 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
          we'll let the signal thread's per-thread variables be found as for
          any normal cthread, and just leave the magic __hurd_sigthread_*
          values all zero so they'll be ignored.  */
-#pragma weak cthread_fork
-#pragma weak cthread_detach
-      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+      cthread_detach (thread = cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+
+      if (pthread_getattr_np)
+	{
+	  /* Record stack layout for fork() */
+	  pthread_attr_t attr;
+	  void *addr;
+	  size_t size;
+
+	  pthread_getattr_np ((pthread_t) thread, &attr);
+	  pthread_attr_getstack (&attr, &addr, &size);
+	  __hurd_sigthread_stack_base = (uintptr_t) addr;
+	  __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + size;
+	}
 
       /* XXX We need the thread port for the signal thread further on
          in this thread (see hurdfault.c:_hurdsigfault_init).
diff --git a/hurd/hurdstartup.c b/hurd/hurdstartup.c
index bd9eca2..b148125 100644
--- a/hurd/hurdstartup.c
+++ b/hurd/hurdstartup.c
@@ -23,7 +23,6 @@
 #include <hurd.h>
 #include <hurd/exec_startup.h>
 #include <sysdep.h>
-#include <hurd/threadvar.h>
 #include <unistd.h>
 #include <elf.h>
 #include <set-hooks.h>
diff --git a/hurd/sigunwind.c b/hurd/sigunwind.c
index 4db9827..40e0f67 100644
--- a/hurd/sigunwind.c
+++ b/hurd/sigunwind.c
@@ -18,6 +18,7 @@
 
 #include <hurd.h>
 #include <thread_state.h>
+#include <hurd/threadvar.h>
 #include <jmpbuf-unwind.h>
 #include <assert.h>
 #include <stdint.h>
@@ -38,8 +39,7 @@ _hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val)
     {
       /* Destroy the MiG reply port used by the signal handler, and restore
 	 the reply port in use by the thread when interrupted.  */
-      mach_port_t *reply_port =
-	(mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+      mach_port_t *reply_port = &__hurd_local_reply_port;
       if (*reply_port)
 	{
 	  mach_port_t port = *reply_port;
diff --git a/include/errno.h b/include/errno.h
index 89353aa..32c2f49 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -24,7 +24,7 @@ extern int rtld_errno attribute_hidden;
 
 #  include <tls.h>
 
-#  if !defined __GNU__
+#  if !(defined(__GNU__) && IS_IN (rtld))
 #   undef  errno
 #   if IS_IN (libc)
 #    define errno __libc_errno
diff --git a/sysdeps/mach/hurd/Versions b/sysdeps/mach/hurd/Versions
index 89e1906..7cab8e8 100644
--- a/sysdeps/mach/hurd/Versions
+++ b/sysdeps/mach/hurd/Versions
@@ -6,6 +6,7 @@ libc {
   GLIBC_PRIVATE {
     # Functions shared with the dynamic linker
     __libc_read; __libc_write; __libc_lseek64;
+    __libc_lock_self0;
 
     _dl_init_first;
   }
@@ -14,8 +15,6 @@ libc {
 ld {
   GLIBC_2.0 {
     # variables that must be shared with libc
-    __hurd_sigthread_stack_base; __hurd_sigthread_stack_end;
-    __hurd_sigthread_variables;
     __hurd_threadvar_stack_mask;  __hurd_threadvar_stack_offset;
 
     # functions that must be shared with libc
@@ -33,5 +32,6 @@ ld {
 
     # functions that must be shared with libc
     __libc_read; __libc_write; __libc_lseek64;
+    __libc_lock_self0;
   }
 }
diff --git a/sysdeps/mach/hurd/cthreads.c b/sysdeps/mach/hurd/cthreads.c
index e0cf4dd..2d61642 100644
--- a/sysdeps/mach/hurd/cthreads.c
+++ b/sysdeps/mach/hurd/cthreads.c
@@ -19,6 +19,8 @@
 #include <errno.h>
 #include <stdlib.h>
 
+char __libc_lock_self0[0];
+
 /* Placeholder for key creation routine from Hurd cthreads library.  */
 int
 weak_function
diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c
index c46342b..1815d2f 100644
--- a/sysdeps/mach/hurd/dl-sysdep.c
+++ b/sysdeps/mach/hurd/dl-sysdep.c
@@ -69,25 +69,6 @@ void *_dl_random attribute_relro = NULL;
 
 struct hurd_startup_data *_dl_hurd_data;
 
-/* This is used only within ld.so, via dl-minimal.c's __errno_location.  */
-#undef errno
-int errno attribute_hidden;
-
-/* Defining these variables here avoids the inclusion of hurdsig.c.  */
-unsigned long int __hurd_sigthread_stack_base;
-unsigned long int __hurd_sigthread_stack_end;
-unsigned long int *__hurd_sigthread_variables;
-
-/* Defining these variables here avoids the inclusion of init-first.c.
-   We need to provide temporary storage for the per-thread variables
-   of the main user thread here, since it is used for storing the
-   `errno' variable.  Note that this information is lost once we
-   relocate the dynamic linker.  */
-static unsigned long int threadvars[_HURD_THREADVAR_MAX];
-unsigned long int __hurd_threadvar_stack_offset
-  = (unsigned long int) &threadvars;
-unsigned long int __hurd_threadvar_stack_mask;
-
 #define FMH defined(__i386__)
 #if ! FMH
 # define fmh()		((void)0)
diff --git a/sysdeps/mach/hurd/errno-loc.c b/sysdeps/mach/hurd/errno-loc.c
index 7b1e7ce..903d65d 100644
--- a/sysdeps/mach/hurd/errno-loc.c
+++ b/sysdeps/mach/hurd/errno-loc.c
@@ -16,13 +16,21 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <hurd/threadvar.h>
-
-int *
+#if IS_IN (rtld)
+/*
+ * rtld can not access TLS too early, thus rtld_errno.
+ *
+ * Instead of making __open/__close pass errno from TLS to rtld_errno, simply
+ * use a weak __errno_location using rtld_errno, which will be overriden by the
+ * libc definition.
+ */
+static int rtld_errno;
+int * weak_function
 __errno_location (void)
 {
-  return (int *) __hurd_threadvar_location (_HURD_THREADVAR_ERRNO);
+  return &rtld_errno;
 }
-strong_alias (__errno_location, __hurd_errno_location)
-libc_hidden_def (__errno_location)
+libc_hidden_weak (__errno_location)
+#else
+#include <../../../csu/errno-loc.c>
+#endif
diff --git a/sysdeps/mach/hurd/errno.c b/sysdeps/mach/hurd/errno.c
deleted file mode 100644
index a29091b..0000000
--- a/sysdeps/mach/hurd/errno.c
+++ /dev/null
@@ -1 +0,0 @@
-/* No definition of `errno' variable on the Hurd.  */
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 984ef60..14dd17c 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <hurd.h>
 #include <hurd/signal.h>
+#include <hurd/threadvar.h>
 #include <setjmp.h>
 #include <thread_state.h>
 #include <sysdep.h>		/* For stack growth direction.  */
@@ -512,19 +513,17 @@ __fork (void)
 				    (natural_t *) &state, &statecount))
 	LOSE;
 #ifdef STACK_GROWTH_UP
-#define THREADVAR_SPACE (__hurd_threadvar_max \
-			 * sizeof *__hurd_sightread_variables)
       if (__hurd_sigthread_stack_base == 0)
 	{
 	  state.SP &= __hurd_threadvar_stack_mask;
-	  state.SP += __hurd_threadvar_stack_offset + THREADVAR_SPACE;
+	  state.SP += __hurd_threadvar_stack_offset;
 	}
       else
 	state.SP = __hurd_sigthread_stack_base;
 #else
       if (__hurd_sigthread_stack_end == 0)
 	{
-	  /* The signal thread has a normal stack assigned by cthreads.
+	  /* The signal thread has a stack assigned by cthreads.
 	     The threadvar_stack variables conveniently tell us how
 	     to get to the highest address in the stack, just below
 	     the per-thread variables.  */
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index d75f24c..7d0ea1b 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -147,15 +147,6 @@ init (int *data)
   char **argv = (void *) (data + 1);
   char **envp = &argv[argc + 1];
   struct hurd_startup_data *d;
-  unsigned long int threadvars[_HURD_THREADVAR_MAX];
-
-  /* Provide temporary storage for thread-specific variables on the
-     startup stack so the cthreads initialization code can use them
-     for malloc et al, or so we can use malloc below for the real
-     threadvars array.  */
-  memset (threadvars, 0, sizeof threadvars);
-  threadvars[_HURD_THREADVAR_LOCALE] = (unsigned long int) &_nl_global_locale;
-  __hurd_threadvar_stack_offset = (unsigned long int) threadvars;
 
   /* Since the cthreads initialization code uses malloc, and the
      malloc initialization code needs to get at the environment, make
@@ -203,13 +194,6 @@ init (int *data)
     __pthread_initialize_minimal ();
 #endif
 
-  /* The user might have defined a value for this, to get more variables.
-     Otherwise it will be zero on startup.  We must make sure it is set
-     properly before before cthreads initialization, so cthreads can know
-     how much space to leave for thread variables.  */
-  if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
-    __hurd_threadvar_max = _HURD_THREADVAR_MAX;
-
 
   /* After possibly switching stacks, call `init1' (above) with the user
      code as the return address, and the argument data immediately above
@@ -225,11 +209,6 @@ init (int *data)
 
       __libc_stack_end = newsp;
 
-      /* Copy per-thread variables from that temporary
-	 area onto the new cthread stack.  */
-      memcpy (__hurd_threadvar_location_from_sp (0, newsp),
-	      threadvars, sizeof threadvars);
-
       /* Copy the argdata from the old stack to the new one.  */
       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
 		      (char *) d - (char *) data);
@@ -270,25 +249,10 @@ init (int *data)
     }
   else
     {
-      /* We are not using cthreads, so we will have just a single allocated
-	 area for the per-thread variables of the main user thread.  */
-      unsigned long int *array;
-      unsigned int i;
       int usercode;
 
       void call_init1 (void);
 
-      array = malloc (__hurd_threadvar_max * sizeof (unsigned long int));
-      if (array == NULL)
-	__libc_fatal ("Can't allocate single-threaded thread variables.");
-
-      /* Copy per-thread variables from the temporary array into the
-	 newly malloc'd space.  */
-      memcpy (array, threadvars, sizeof threadvars);
-      __hurd_threadvar_stack_offset = (unsigned long int) array;
-      for (i = _HURD_THREADVAR_MAX; i < __hurd_threadvar_max; ++i)
-	array[i] = 0;
-
       /* The argument data is just above the stack frame we will unwind by
 	 returning.  Mutate our own return address to run the code below.  */
       /* The following expression would typically be written as
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
index 8ec1d4b..07633e1 100644
--- a/sysdeps/mach/hurd/i386/sigreturn.c
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
@@ -68,7 +68,7 @@ __sigreturn (struct sigcontext *scp)
 
   if (scp->sc_onstack)
     {
-      ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
+      ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
       /* XXX cannot unlock until off sigstack */
       abort ();
     }
@@ -77,8 +77,7 @@ __sigreturn (struct sigcontext *scp)
 
   /* Destroy the MiG reply port used by the signal handler, and restore the
      reply port in use by the thread when interrupted.  */
-  reply_port =
-    (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+  reply_port = &__hurd_local_reply_port;
   if (*reply_port)
     {
       mach_port_t port = *reply_port;
diff --git a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
index 0ff0474..adaa580 100644
--- a/sysdeps/mach/hurd/i386/tls.h
+++ b/sysdeps/mach/hurd/i386/tls.h
@@ -43,6 +43,10 @@ typedef struct
   void *__private_tm[4];
   /* GCC split stack support.  */
   void *__private_ss;
+
+  /* Keep this field last */
+  mach_port_t reply_port;      /* This thread's reply port.  */
+  struct hurd_sigstate *_hurd_sigstate;
 } tcbhead_t;
 #endif
 
@@ -89,6 +93,17 @@ typedef struct
       | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */		      \
     }
 
+# define HURD_DESC_TLS(desc)						      \
+  ({									      \
+   (tcbhead_t *) (   (desc->low_word >> 16)				      \
+                  | ((desc->high_word & 0xff) << 16)			      \
+                  |  (desc->high_word & 0xff000000)			      \
+     );})
+
+#define __LIBC_NO_TLS()							      \
+  ({ unsigned short ds, gs;						      \
+     asm ("movw %%ds,%w0; movw %%gs,%w1" : "=q" (ds), "=q" (gs));	      \
+     ds == gs; })
 
 static inline const char * __attribute__ ((unused))
 _hurd_tls_init (tcbhead_t *tcb)
@@ -139,6 +154,20 @@ _hurd_tls_init (tcbhead_t *tcb)
 	      : "i" (offsetof (tcbhead_t, tcb)));			      \
      __tcb;})
 
+/* Return the TCB address of a thread given its state.  */
+# define THREAD_TCB(thread, thread_state)				      \
+  ({ int __sel = (thread_state)->basic.gs;				      \
+     struct descriptor __desc, *___desc = &__desc;			      \
+     unsigned int __count = 1;						      \
+     kern_return_t __err;						      \
+     if (__builtin_expect (__sel, 0x48) & 4) /* LDT selector */		      \
+       __err = __i386_get_ldt ((thread), __sel, 1, &___desc, &__count);	      \
+     else								      \
+       __err = __i386_get_gdt ((thread), __sel, &__desc);		      \
+     assert_perror (__err);						      \
+     assert (__count == 1);						      \
+     HURD_DESC_TLS(___desc);})
+
 /* Install new dtv for current thread.  */
 # define INSTALL_NEW_DTV(dtvp)						      \
   ({ asm volatile ("movl %0,%%gs:%P1"					      \
diff --git a/sysdeps/mach/hurd/libc-lock.h b/sysdeps/mach/hurd/libc-lock.h
index 2811b64..b7fffd0 100644
--- a/sysdeps/mach/hurd/libc-lock.h
+++ b/sysdeps/mach/hurd/libc-lock.h
@@ -24,7 +24,6 @@
 #  include <tls.h>
 # endif
 #include <cthreads.h>
-#include <hurd/threadvar.h>
 
 /* The locking here is very inexpensive, even for inlining.  */
 #define _IO_lock_inexpensive  1
@@ -38,7 +37,8 @@ typedef struct
 } __libc_lock_recursive_t;
 typedef __libc_lock_recursive_t __rtld_lock_recursive_t;
 
-#define __libc_lock_owner_self() ((void *) __hurd_threadvar_location (0))
+extern char __libc_lock_self0[0];
+#define __libc_lock_owner_self() (__LIBC_NO_TLS() ? &__libc_lock_self0 : THREAD_SELF)
 
 #else
 typedef struct __libc_lock_opaque__ __libc_lock_t;
diff --git a/sysdeps/mach/hurd/libc-tsd.h b/sysdeps/mach/hurd/libc-tsd.h
deleted file mode 100644
index fa131a2..0000000
--- a/sysdeps/mach/hurd/libc-tsd.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* libc-internal interface for thread-specific data.  Hurd version.
-   Copyright (C) 1998-2018 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, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef _LIBC_TSD_H
-#define _LIBC_TSD_H 1
-
-#include <hurd/threadvar.h>
-
-#define __libc_tsd_define(CLASS, TYPE, KEY) /* nothing, always have threadvars */
-
-#define __libc_tsd_address(TYPE, KEY) \
-  ((TYPE *) __hurd_threadvar_location (_HURD_THREADVAR_##KEY))
-
-#define __libc_tsd_get(TYPE, KEY) \
-  (*__libc_tsd_address (TYPE, KEY))
-#define __libc_tsd_set(TYPE, KEY, VALUE) \
-  (*__libc_tsd_address (TYPE, KEY) = (VALUE))
-
-#endif	/* libc-tsd.h */
diff --git a/sysdeps/mach/hurd/mig-reply.c b/sysdeps/mach/hurd/mig-reply.c
index ed3705d..ddad12e 100644
--- a/sysdeps/mach/hurd/mig-reply.c
+++ b/sysdeps/mach/hurd/mig-reply.c
@@ -18,26 +18,20 @@
 #include <mach.h>
 #include <hurd/threadvar.h>
 
-#define GETPORT \
-  mach_port_t *portloc = \
-    (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY)
-#define reply_port (*(use_threadvar ? portloc : &global_reply_port))
-
-static int use_threadvar;
-static mach_port_t global_reply_port;
-
 /* These functions are called by MiG-generated code.  */
 
+mach_port_t __hurd_reply_port0;
+
 /* Called by MiG to get a reply port.  */
 mach_port_t
 __mig_get_reply_port (void)
 {
-  GETPORT;
-
-  if (reply_port == MACH_PORT_NULL)
-    reply_port = __mach_reply_port ();
+  if (__hurd_local_reply_port == MACH_PORT_NULL ||
+      (&__hurd_local_reply_port != &__hurd_reply_port0
+       && __hurd_local_reply_port == __hurd_reply_port0))
+    __hurd_local_reply_port = __mach_reply_port ();
 
-  return reply_port;
+  return __hurd_local_reply_port;
 }
 weak_alias (__mig_get_reply_port, mig_get_reply_port)
 
@@ -45,12 +39,8 @@ weak_alias (__mig_get_reply_port, mig_get_reply_port)
 void
 __mig_dealloc_reply_port (mach_port_t arg)
 {
-  mach_port_t port;
-
-  GETPORT;
-
-  port = reply_port;
-  reply_port = MACH_PORT_NULL;	/* So the mod_refs RPC won't use it.  */
+  mach_port_t port = __hurd_local_reply_port;
+  __hurd_local_reply_port = MACH_PORT_NULL;	/* So the mod_refs RPC won't use it.  */
 
   if (MACH_PORT_VALID (port))
     __mach_port_mod_refs (__mach_task_self (), port,
@@ -73,15 +63,6 @@ weak_alias (__mig_put_reply_port, mig_put_reply_port)
 void
 __mig_init (void *stack)
 {
-  use_threadvar = stack != 0;
-
-  if (use_threadvar)
-    {
-      /* Recycle the reply port used before multithreading was enabled.  */
-      mach_port_t *portloc = (mach_port_t *)
-	__hurd_threadvar_location_from_sp (_HURD_THREADVAR_MIG_REPLY, stack);
-      *portloc = global_reply_port;
-      global_reply_port = MACH_PORT_NULL;
-    }
+  /* Do nothing.  */
 }
 weak_alias (__mig_init, mig_init)
diff --git a/sysdeps/mach/hurd/profil.c b/sysdeps/mach/hurd/profil.c
index 7206345..45f83a9 100644
--- a/sysdeps/mach/hurd/profil.c
+++ b/sysdeps/mach/hurd/profil.c
@@ -141,7 +141,7 @@ __profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
 weak_alias (__profil, profil)
 
 /* Fetch PC samples.  This function must be very careful not to depend
-   on Hurd threadvar variables.  We arrange that by using a special
+   on Hurd TLS variables.  We arrange that by using a special
    stub arranged for at the end of this file. */
 static void
 fetch_samples (void)
@@ -177,7 +177,7 @@ fetch_samples (void)
 }
 
 
-/* This function must be very careful not to depend on Hurd threadvar
+/* This function must be very careful not to depend on Hurd TLS
    variables.  We arrange that by using special stubs arranged for at the
    end of this file. */
 static void
@@ -268,7 +268,7 @@ text_set_element (_hurd_fork_child_hook, fork_profil_child);
    are fatal in profile_waiter anyhow. */
 #define __mig_put_reply_port(foo)
 
-/* Use our static variable instead of the usual threadvar mechanism for
+/* Use our static variable instead of the usual TLS mechanism for
    this. */
 #define __mig_get_reply_port() profil_reply_port
 

-----------------------------------------------------------------------

Summary of changes:
 hurd/Makefile                       |    1 +
 hurd/Versions                       |   14 ++-
 hurd/hurd/signal.h                  |   23 ++--
 hurd/hurd/threadvar.h               |   76 +-----------
 hurd/hurdlock.c                     |  215 ++++++++++++++++++++++++++++++++++
 hurd/hurdlock.h                     |  124 ++++++++++++++++++++
 hurd/hurdpid.c                      |    3 +
 hurd/hurdsig.c                      |   55 +++++----
 hurd/hurdstartup.c                  |    1 -
 hurd/setauth.c                      |    5 +-
 hurd/sigunwind.c                    |    4 +-
 include/errno.h                     |    2 +-
 mach/Makefile                       |    2 +-
 mach/lock-intern.h                  |   74 ++++++++-----
 mach/lowlevellock.h                 |   80 +++++++++++++
 mach/mutex-init.c                   |    7 +-
 sysdeps/mach/Makefile               |   21 ++++
 sysdeps/mach/hurd/Versions          |    4 +-
 sysdeps/mach/hurd/bits/errno.h      |    6 +-
 sysdeps/mach/hurd/cthreads.c        |    2 +
 sysdeps/mach/hurd/dl-sysdep.c       |   19 ---
 sysdeps/mach/hurd/errno-loc.c       |   22 +++-
 sysdeps/mach/hurd/errno.c           |    1 -
 sysdeps/mach/hurd/fork.c            |    7 +-
 sysdeps/mach/hurd/i386/init-first.c |   36 ------
 sysdeps/mach/hurd/i386/sigreturn.c  |    5 +-
 sysdeps/mach/hurd/i386/tls.h        |   29 +++++
 sysdeps/mach/hurd/libc-lock.h       |  219 -----------------------------------
 sysdeps/mach/hurd/libc-tsd.h        |   34 ------
 sysdeps/mach/hurd/mig-reply.c       |   39 ++-----
 sysdeps/mach/hurd/profil.c          |    6 +-
 sysdeps/mach/hurd/setpgid.c         |   10 +--
 sysdeps/mach/hurd/setsid.c          |   10 +--
 sysdeps/mach/libc-lock.h            |  170 +++++++++++++++++++++-------
 34 files changed, 765 insertions(+), 561 deletions(-)
 create mode 100644 hurd/hurdlock.c
 create mode 100644 hurd/hurdlock.h
 create mode 100644 mach/lowlevellock.h
 delete mode 100644 sysdeps/mach/hurd/errno.c
 delete mode 100644 sysdeps/mach/hurd/libc-lock.h
 delete mode 100644 sysdeps/mach/hurd/libc-tsd.h


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]