diff mbox series

[RFC,htl,v2,2/4] htl: Reimplement GSCOPE

Message ID 20210830152636.1334678-3-bugaevc@gmail.com
State Superseded
Headers show
Series Rewrite THREAD_GSCOPE | expand

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Sergey Bugaev Aug. 30, 2021, 3:26 p.m. UTC
This is a new implementation of GSCOPE which largely mirrors its NPTL
counterpart. Same as in NPTL, instead of a global flag shared between
threads, there is now a per-thread GSCOPE flag stored in each thread's
TCB. This makes entering and exiting a GSCOPE faster at the expense of
making THREAD_GSCOPE_WAIT () slower.

The largest win is the elimination of many redundant gsync_wake () RPC
calls; previously, even simplest programs would make dozens of fully
redundant gsync_wake () calls.

Despite all ports now putting GSCOPE flag into TCP, this patch keeps
the THREAD_GSCOPE_IN_TCB preprocessor definition, with value 0 for HTL
and 1 for NPTL. It turns out that although originally this definition
was indeed used to distinguish between the cases where the GSCOPE flag
was stored in TCB or not, it has since become used as a general way to
distinguish between HTL and NPTL. It may be worthwhile to get rid of
this flag, or at least rename it to better reflect what it's used for.
This patch does neither, though.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---
 elf/dl-support.c                    |  1 -
 sysdeps/generic/ldsodefs.h          |  4 ---
 sysdeps/htl/dl-thread_gscope_wait.c | 55 +++++++++++++++++++++++++++++
 sysdeps/mach/hurd/i386/tls.h        | 19 ++++++++++
 sysdeps/mach/hurd/tls.h             | 20 +----------
 5 files changed, 75 insertions(+), 24 deletions(-)
 create mode 100644 sysdeps/htl/dl-thread_gscope_wait.c
diff mbox series

Patch

diff --git a/elf/dl-support.c b/elf/dl-support.c
index 0155718175..68abf606ca 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -195,7 +195,6 @@  int _dl_stack_cache_lock;
    when it was not, we do it by calling this function.
    It returns an errno code or zero on success.  */
 int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable;
-int _dl_thread_gscope_count;
 void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
 #endif
 struct dl_scope_free_list *_dl_scope_free_list;
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 31c7d3945b..5a779ae1a3 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -487,8 +487,6 @@  struct rtld_global
   /* Mutex protecting the stack lists.  */
   EXTERN int _dl_stack_cache_lock;
 #else
-  EXTERN int _dl_thread_gscope_count;
-
   /* The total number of thread IDs currently in use, or on the list of
      available thread IDs.  */
   EXTERN int _dl_pthread_num_threads;
@@ -1379,10 +1377,8 @@  __rtld_mutex_init (void)
 }
 #endif /* !PTHREAD_IN_LIBC */
 
-#if THREAD_GSCOPE_IN_TCB
 void __thread_gscope_wait (void) attribute_hidden;
 # define THREAD_GSCOPE_WAIT() __thread_gscope_wait ()
-#endif
 
 __END_DECLS
 
diff --git a/sysdeps/htl/dl-thread_gscope_wait.c b/sysdeps/htl/dl-thread_gscope_wait.c
new file mode 100644
index 0000000000..b277217b8e
--- /dev/null
+++ b/sysdeps/htl/dl-thread_gscope_wait.c
@@ -0,0 +1,55 @@ 
+/* Out-of-line notification function for the GSCOPE locking mechanism.
+   Copyright (C) 2007-2021 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <pthread.h>
+#include <htl/pt-internal.h>
+
+void
+__thread_gscope_wait (void)
+{
+  size_t i;
+  struct __pthread *t;
+  int *gscope_flagp;
+
+  lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
+
+  /* Iterate over the list of threads.  */
+  for (i = 0; i < GL (dl_pthread_num_threads); ++i)
+    {
+      t = GL (dl_pthread_threads[i]);
+      if (t == NULL || t->tcb->gscope_flag == THREAD_GSCOPE_FLAG_UNUSED)
+        continue;
+
+      gscope_flagp = &t->tcb->gscope_flag;
+
+      /* We have to wait until this thread is done with the global
+         scope.  First tell the thread that we are waiting and
+         possibly have to be woken.  */
+      if (atomic_compare_and_exchange_bool_acq (gscope_flagp,
+                                                THREAD_GSCOPE_FLAG_WAIT,
+                                                THREAD_GSCOPE_FLAG_USED))
+        continue;
+
+      do
+        lll_wait (gscope_flagp, THREAD_GSCOPE_FLAG_WAIT, LLL_PRIVATE);
+      while (*gscope_flagp == THREAD_GSCOPE_FLAG_WAIT);
+    }
+
+  lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
+}
diff --git a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
index 057b2613f3..c70ea73a81 100644
--- a/sysdeps/mach/hurd/i386/tls.h
+++ b/sysdeps/mach/hurd/i386/tls.h
@@ -369,6 +369,25 @@  _hurd_tls_new (thread_t child, struct i386_thread_state *state, tcbhead_t *tcb)
   return err;
 }
 
+/* Global scope switch support.  */
+# define THREAD_GSCOPE_FLAG_UNUSED 0
+# define THREAD_GSCOPE_FLAG_USED   1
+# define THREAD_GSCOPE_FLAG_WAIT   2
+
+# define THREAD_GSCOPE_SET_FLAG() \
+  THREAD_SETMEM (THREAD_SELF, gscope_flag, THREAD_GSCOPE_FLAG_USED)
+
+# define THREAD_GSCOPE_RESET_FLAG() \
+  ({                                                                         \
+    int __flag;                                                              \
+    asm volatile ("xchgl %0, %%gs:%P1"                                       \
+                  : "=r" (__flag)                                            \
+                  : "i" (offsetof (tcbhead_t, gscope_flag)),                 \
+                    "0" (THREAD_GSCOPE_FLAG_UNUSED));                        \
+    if (__flag == THREAD_GSCOPE_FLAG_WAIT)                                   \
+      lll_wake (THREAD_SELF->gscope_flag, LLL_PRIVATE);                      \
+  })
+
 #endif	/* !__ASSEMBLER__ */
 
 #endif	/* i386/tls.h */
diff --git a/sysdeps/mach/hurd/tls.h b/sysdeps/mach/hurd/tls.h
index f83956d3d7..98dc319745 100644
--- a/sysdeps/mach/hurd/tls.h
+++ b/sysdeps/mach/hurd/tls.h
@@ -52,25 +52,7 @@ 
 # define GET_DTV(descr) \
   (((tcbhead_t *) (descr))->dtv)
 
-/* Global scope switch support.  */
-#define THREAD_GSCOPE_IN_TCB      0
-#define THREAD_GSCOPE_GLOBAL
-#define THREAD_GSCOPE_SET_FLAG() \
-  atomic_exchange_and_add_acq (&GL(dl_thread_gscope_count), 1)
-#define THREAD_GSCOPE_RESET_FLAG() \
-  do 									      \
-    if (atomic_exchange_and_add_rel (&GL(dl_thread_gscope_count), -1) == 1)   \
-      lll_wake (GL(dl_thread_gscope_count), 0);				      \
-  while (0)
-#define THREAD_GSCOPE_WAIT() \
-  do 									      \
-    {									      \
-      int count;							      \
-      atomic_write_barrier ();						      \
-      while ((count = GL(dl_thread_gscope_count)))			      \
-        lll_wait (GL(dl_thread_gscope_count), count, 0);		      \
-    }									      \
-  while (0)
+# define THREAD_GSCOPE_IN_TCB 0
 
 #endif /* !ASSEMBLER */