Fixed and unified pthread_once.
authorTorvald Riegel <triegel@redhat.com>
Wed, 8 May 2013 14:35:10 +0000 (16:35 +0200)
committerTorvald Riegel <triegel@redhat.com>
Fri, 11 Apr 2014 13:54:19 +0000 (15:54 +0200)
[BZ #15215] This unifies various pthread_once architecture-specific
implementations which were using the same algorithm with slightly different
implementations.  It also adds missing memory barriers that are required for
correctness.

ChangeLog
nptl/sysdeps/unix/sysv/linux/pthread_once.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c [deleted file]
ports/ChangeLog.hppa
ports/sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c [deleted file]
sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c [deleted file]

index 5708d4e..0fdc6b5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2014-04-11  Torvald Riegel  <triegel@redhat.com>
+
+       [BZ #15215]
+       * nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c: Moved to ...
+       * nptl/sysdeps/unix/sysv/linux/pthread_once.c: ... here.  Add missing
+       memory barriers.  Add comments.
+       * sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c: Remove file.
+       * sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c: Remove file.
+       * sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c: Remove file.
+       * sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: Remove file.
+       * sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c: Remove file.
+       * sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c: Remove file.
+
 2014-04-11  Stefan Liebler  <stli@linux.vnet.ibm.com>
 
        * sysdeps/s390/s390-32/configure.ac: Unify file with ...
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/pthread_once.c
new file mode 100644 (file)
index 0000000..10c01d6
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   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 "pthreadP.h"
+#include <lowlevellock.h>
+#include <atomic.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  /* Reset to the uninitialized state here.  We don't need a stronger memory
+     order because we do not need to make any other of our writes visible to
+     other threads that see this value: This function will be called if we
+     get interrupted (see __pthread_once), so all we need to relay to other
+     threads is the state being reset again.  */
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+/* This is similar to a lock implementation, but we distinguish between three
+   states: not yet initialized (0), initialization finished (2), and
+   initialization in progress (__fork_generation | 1).  If in the first state,
+   threads will try to run the initialization by moving to the second state;
+   the first thread to do so via a CAS on once_control runs init_routine,
+   other threads block.
+   When forking the process, some threads can be interrupted during the second
+   state; they won't be present in the forked child, so we need to restart
+   initialization in the child.  To distinguish an in-progress initialization
+   from an interrupted initialization (in which case we need to reclaim the
+   lock), we look at the fork generation that's part of the second state: We
+   can reclaim iff it differs from the current fork generation.
+   XXX: This algorithm has an ABA issue on the fork generation: If an
+   initialization is interrupted, we then fork 2^30 times (30 bits of
+   once_control are used for the fork generation), and try to initialize
+   again, we can deadlock because we can't distinguish the in-progress and
+   interrupted cases anymore.  */
+int
+__pthread_once (once_control, init_routine)
+     pthread_once_t *once_control;
+     void (*init_routine) (void);
+{
+  while (1)
+    {
+      int oldval, val, newval;
+
+      /* We need acquire memory order for this load because if the value
+         signals that initialization has finished, we need to be see any
+         data modifications done during initialization.  */
+      val = *once_control;
+      atomic_read_barrier();
+      do
+       {
+         /* Check if the initialization has already been done.  */
+         if (__glibc_likely ((val & 2) != 0))
+           return 0;
+
+         oldval = val;
+         /* We try to set the state to in-progress and having the current
+            fork generation.  We don't need atomic accesses for the fork
+            generation because it's immutable in a particular process, and
+            forked child processes start with a single thread that modified
+            the generation.  */
+         newval = __fork_generation | 1;
+         /* We need acquire memory order here for the same reason as for the
+            load from once_control above.  */
+         val = atomic_compare_and_exchange_val_acq (once_control, newval,
+                                                    oldval);
+       }
+      while (__glibc_unlikely (val != oldval));
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) != 0)
+       {
+         /* Check whether the initializer execution was interrupted by a
+            fork.  We know that for both values, bit 0 is set and bit 1 is
+            not.  */
+         if (oldval == newval)
+           {
+             /* Same generation, some other thread was faster. Wait.  */
+             lll_futex_wait (once_control, newval, LLL_PRIVATE);
+             continue;
+           }
+       }
+
+      /* This thread is the first here.  Do the initialization.
+        Register a cleanup handler so that in case the thread gets
+        interrupted the initialization can be restarted.  */
+      pthread_cleanup_push (clear_once_control, once_control);
+
+      init_routine ();
+
+      pthread_cleanup_pop (0);
+
+
+      /* Mark *once_control as having finished the initialization.  We need
+         release memory order here because we need to synchronize with other
+         threads that want to use the initialized data.  */
+      atomic_write_barrier();
+      *once_control = 2;
+
+      /* Wake up all other threads.  */
+      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+      break;
+    }
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+hidden_def (__pthread_once)
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c
deleted file mode 100644 (file)
index a231e55..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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 "pthreadP.h"
-#include <lowlevellock.h>
-
-
-unsigned long int __fork_generation attribute_hidden;
-
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-
-int
-__pthread_once (once_control, init_routine)
-     pthread_once_t *once_control;
-     void (*init_routine) (void);
-{
-  while (1)
-    {
-      int oldval, val, newval;
-
-      val = *once_control;
-      do
-       {
-         /* Check if the initialized has already been done.  */
-         if ((val & 2) != 0)
-           return 0;
-
-         oldval = val;
-         newval = (oldval & 3) | __fork_generation | 1;
-         val = atomic_compare_and_exchange_val_acq (once_control, newval,
-                                                    oldval);
-       }
-      while (__builtin_expect (val != oldval, 0));
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) != 0)
-       {
-         /* Check whether the initializer execution was interrupted
-            by a fork.  */
-         if (((oldval ^ newval) & -4) == 0)
-           {
-             /* Same generation, some other thread was faster. Wait.  */
-             lll_futex_wait (once_control, newval, LLL_PRIVATE);
-             continue;
-           }
-       }
-
-      /* This thread is the first here.  Do the initialization.
-        Register a cleanup handler so that in case the thread gets
-        interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
-
-      init_routine ();
-
-      pthread_cleanup_pop (0);
-
-
-      /* Add one to *once_control.  */
-      atomic_increment (once_control);
-
-      /* Wake up all other threads.  */
-      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-      break;
-    }
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
index 39c7701..3efd186 100644 (file)
@@ -1,3 +1,8 @@
+2014-04-11  Torvald Riegel  <triegel@redhat.com>
+
+       [BZ #15215]
+       * sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c: Remove file.
+
 2014-04-09  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>
 
        * ports/sysdeps/unix/sysv/linux/hppa/nptl/bits/pthreadtypes.h
diff --git a/ports/sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c
deleted file mode 100644 (file)
index ee6b496..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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 "pthreadP.h"
-#include <lowlevellock.h>
-
-
-unsigned long int __fork_generation attribute_hidden;
-
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_private_futex_wake (once_control, INT_MAX);
-}
-
-
-int
-__pthread_once (once_control, init_routine)
-     pthread_once_t *once_control;
-     void (*init_routine) (void);
-{
-  while (1)
-    {
-      int oldval, val, newval;
-
-      val = *once_control;
-      do
-       {
-         /* Check if the initialized has already been done.  */
-         if ((val & 2) != 0)
-           return 0;
-
-         oldval = val;
-         newval = (oldval & 3) | __fork_generation | 1;
-         val = atomic_compare_and_exchange_val_acq (once_control, newval,
-                                                    oldval);
-       }
-      while (__builtin_expect (val != oldval, 0));
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) != 0)
-       {
-         /* Check whether the initializer execution was interrupted
-            by a fork.  */
-         if (((oldval ^ newval) & -4) == 0)
-           {
-             /* Same generation, some other thread was faster. Wait.  */
-             lll_private_futex_wait (once_control, newval);
-             continue;
-           }
-       }
-
-      /* This thread is the first here.  Do the initialization.
-        Register a cleanup handler so that in case the thread gets
-        interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
-
-      init_routine ();
-
-      pthread_cleanup_pop (0);
-
-
-      /* Add one to *once_control.  */
-      atomic_increment (once_control);
-
-      /* Wake up all other threads.  */
-      lll_private_futex_wake (once_control, INT_MAX);
-      break;
-    }
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c
deleted file mode 100644 (file)
index d1b28ff..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2004-2014 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 "pthreadP.h"
-#include <lowlevellock.h>
-
-unsigned long int __fork_generation attribute_hidden;
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-int
-__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
-{
-  for (;;)
-    {
-      int oldval;
-      int newval;
-
-      /* Pseudo code:
-        newval = __fork_generation | 1;
-        oldval = *once_control;
-        if ((oldval & 2) == 0)
-          *once_control = newval;
-        Do this atomically.
-      */
-      do
-       {
-         newval = __fork_generation | 1;
-         oldval = *once_control;
-         if (oldval & 2)
-           break;
-       } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
-
-      /* Check if the initializer has already been done.  */
-      if ((oldval & 2) != 0)
-       return 0;
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) == 0)
-       break;
-
-      /* Check whether the initializer execution was interrupted by a fork.  */
-      if (oldval != newval)
-       break;
-
-      /* Same generation, some other thread was faster. Wait.  */
-      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
-    }
-
-  /* This thread is the first here.  Do the initialization.
-     Register a cleanup handler so that in case the thread gets
-     interrupted the initialization can be restarted.  */
-  pthread_cleanup_push (clear_once_control, once_control);
-
-  init_routine ();
-
-  pthread_cleanup_pop (0);
-
-  /* Say that the initialisation is done.  */
-  *once_control = __fork_generation | 2;
-
-  /* Wake up all other threads.  */
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c
deleted file mode 100644 (file)
index a063149..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Copyright (C) 2004-2014 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 "pthreadP.h"
-#include <lowlevellock.h>
-
-unsigned long int __fork_generation attribute_hidden;
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-int
-__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
-{
-  for (;;)
-    {
-      int oldval;
-      int newval;
-
-      /* Pseudo code:
-        newval = __fork_generation | 1;
-        oldval = *once_control;
-        if ((oldval & 2) == 0)
-          *once_control = newval;
-        Do this atomically.
-      */
-      do
-       {
-         newval = __fork_generation | 1;
-         oldval = *once_control;
-         if (oldval & 2)
-           break;
-       } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
-
-      /* Check if the initializer has already been done.  */
-      if ((oldval & 2) != 0)
-       return 0;
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) == 0)
-       break;
-
-      /* Check whether the initializer execution was interrupted by a fork.  */
-      if (oldval != newval)
-       break;
-
-      /* Same generation, some other thread was faster. Wait.  */
-      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
-    }
-
-  /* This thread is the first here.  Do the initialization.
-     Register a cleanup handler so that in case the thread gets
-     interrupted the initialization can be restarted.  */
-  pthread_cleanup_push (clear_once_control, once_control);
-
-  init_routine ();
-
-  pthread_cleanup_pop (0);
-
-  /* Say that the initialisation is done.  */
-  *once_control = __fork_generation | 2;
-
-  /* Wake up all other threads.  */
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c
deleted file mode 100644 (file)
index a231e55..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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 "pthreadP.h"
-#include <lowlevellock.h>
-
-
-unsigned long int __fork_generation attribute_hidden;
-
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-
-int
-__pthread_once (once_control, init_routine)
-     pthread_once_t *once_control;
-     void (*init_routine) (void);
-{
-  while (1)
-    {
-      int oldval, val, newval;
-
-      val = *once_control;
-      do
-       {
-         /* Check if the initialized has already been done.  */
-         if ((val & 2) != 0)
-           return 0;
-
-         oldval = val;
-         newval = (oldval & 3) | __fork_generation | 1;
-         val = atomic_compare_and_exchange_val_acq (once_control, newval,
-                                                    oldval);
-       }
-      while (__builtin_expect (val != oldval, 0));
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) != 0)
-       {
-         /* Check whether the initializer execution was interrupted
-            by a fork.  */
-         if (((oldval ^ newval) & -4) == 0)
-           {
-             /* Same generation, some other thread was faster. Wait.  */
-             lll_futex_wait (once_control, newval, LLL_PRIVATE);
-             continue;
-           }
-       }
-
-      /* This thread is the first here.  Do the initialization.
-        Register a cleanup handler so that in case the thread gets
-        interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
-
-      init_routine ();
-
-      pthread_cleanup_pop (0);
-
-
-      /* Add one to *once_control.  */
-      atomic_increment (once_control);
-
-      /* Wake up all other threads.  */
-      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-      break;
-    }
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
deleted file mode 100644 (file)
index 01542e9..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2010-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
-
-   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 "pthreadP.h"
-#include <lowlevellock.h>
-
-unsigned long int __fork_generation attribute_hidden;
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-int
-__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
-{
-  for (;;)
-    {
-      int oldval;
-      int newval;
-
-      /* Pseudo code:
-        newval = __fork_generation | 1;
-        oldval = *once_control;
-        if ((oldval & 2) == 0)
-          *once_control = newval;
-        Do this atomically.
-      */
-      do
-       {
-         newval = __fork_generation | 1;
-         oldval = *once_control;
-         if (oldval & 2)
-           break;
-       } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
-
-      /* Check if the initializer has already been done.  */
-      if ((oldval & 2) != 0)
-       return 0;
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) == 0)
-       break;
-
-      /* Check whether the initializer execution was interrupted by a fork.  */
-      if (oldval != newval)
-       break;
-
-      /* Same generation, some other thread was faster. Wait.  */
-      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
-    }
-
-  /* This thread is the first here.  Do the initialization.
-     Register a cleanup handler so that in case the thread gets
-     interrupted the initialization can be restarted.  */
-  pthread_cleanup_push (clear_once_control, once_control);
-
-  init_routine ();
-
-  pthread_cleanup_pop (0);
-
-  /* Say that the initialisation is done.  */
-  *once_control = __fork_generation | 2;
-
-  /* Wake up all other threads.  */
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c
deleted file mode 100644 (file)
index 3e3430d..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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 "pthreadP.h"
-#include <lowlevellock.h>
-
-
-unsigned long int __fork_generation attribute_hidden;
-
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-
-int
-__pthread_once (once_control, init_routine)
-     pthread_once_t *once_control;
-     void (*init_routine) (void);
-{
-  while (1)
-    {
-      int oldval, val, newval;
-
-      val = *once_control;
-      do
-       {
-         /* Check if the initialized has already been done.  */
-         if ((val & 2) != 0)
-           return 0;
-
-         oldval = val;
-         newval = (oldval & 3) | __fork_generation | 1;
-         val = atomic_compare_and_exchange_val_acq (once_control, newval,
-                                                    oldval);
-       }
-      while (__builtin_expect (val != oldval, 0));
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) != 0)
-       {
-         /* Check whether the initializer execution was interrupted
-            by a fork.  */
-         if (((oldval ^ newval) & -4) == 0)
-           {
-             /* Same generation, some other thread was faster. Wait.  */
-             lll_futex_wait (once_control, newval, LLL_PRIVATE);
-             continue;
-           }
-       }
-
-      /* This thread is the first here.  Do the initialization.
-        Register a cleanup handler so that in case the thread gets
-        interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
-
-      init_routine ();
-
-      pthread_cleanup_pop (0);
-
-
-      /* Add one to *once_control.  */
-      atomic_increment (once_control);
-
-      /* Wake up all other threads.  */
-      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-      break;
-    }
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)
diff --git a/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c
deleted file mode 100644 (file)
index 1b38999..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
-   Based on work contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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 <nptl/pthreadP.h>
-#include <lowlevellock.h>
-
-
-unsigned long int __fork_generation attribute_hidden;
-
-
-static void
-clear_once_control (void *arg)
-{
-  pthread_once_t *once_control = (pthread_once_t *) arg;
-
-  *once_control = 0;
-  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-}
-
-
-int
-__pthread_once (once_control, init_routine)
-     pthread_once_t *once_control;
-     void (*init_routine) (void);
-{
-  while (1)
-    {
-      int oldval, val, newval;
-
-      val = *once_control;
-      do
-       {
-         /* Check if the initialized has already been done.  */
-         if ((val & 2) != 0)
-           return 0;
-
-         oldval = val;
-         newval = (oldval & 3) | __fork_generation | 1;
-         val = atomic_compare_and_exchange_val_acq (once_control, newval,
-                                                    oldval);
-       }
-      while (__builtin_expect (val != oldval, 0));
-
-      /* Check if another thread already runs the initializer. */
-      if ((oldval & 1) != 0)
-       {
-         /* Check whether the initializer execution was interrupted
-            by a fork.  */
-         if (((oldval ^ newval) & -4) == 0)
-           {
-             /* Same generation, some other thread was faster. Wait.  */
-             lll_futex_wait (once_control, newval, LLL_PRIVATE);
-             continue;
-           }
-       }
-
-      /* This thread is the first here.  Do the initialization.
-        Register a cleanup handler so that in case the thread gets
-        interrupted the initialization can be restarted.  */
-      pthread_cleanup_push (clear_once_control, once_control);
-
-      init_routine ();
-
-      pthread_cleanup_pop (0);
-
-
-      /* Add one to *once_control.  */
-      atomic_increment (once_control);
-
-      /* Wake up all other threads.  */
-      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
-      break;
-    }
-
-  return 0;
-}
-weak_alias (__pthread_once, pthread_once)
-hidden_def (__pthread_once)