This is the mail archive of the libc-alpha@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]

Re: [PATCH] Unify pthread_once (bug 15215)


David, Marcus, Joseph, Mike, Andreas, Steve, Chris,

We would like to unify all C-based pthread_once implmentations
per the plan in bug 15215 for glibc 2.20.

Your machines are on the list of C-based pthread_once implementations.

See this for the intial discussions on the unified pthread_once:
https://sourceware.org/ml/libc-alpha/2013-05/msg00210.html

The goal is to provide a single and correct C implementation of 
pthread_once. Architectures can then build on that if they need more 
optimal implementations, but I don't encourage that and I'd rather
see deep discussions on how to make one unified solution where
possible.

I've also just reviewed Torvald's new pthread_once microbenchmark which
you can use to compare your previous C implementation with the new
standard C implementation (measures pthread_once latency). The primary
use of this test is to help provide objective proof for or against the
i386 and x86_64 assembly implementations.

We are not presently converting any of the machines with custom
implementations, but that will be a next step after testing with the
help of the maintainers for sh, i386, x86_64, powerpc, s390 and alpha.

If we don't hear any objections we will go forward with this change
in one week and unify ia64, hppa, mips, tile, sparc, m68k, arm
and aarch64 on a single pthread_once implementation based on sparc's C
implementation.

Any objections to this cleanup for 2.20?

On 10/07/2013 05:53 PM, Torvald Riegel wrote:
> On Mon, 2013-10-07 at 16:04 +0000, Joseph S. Myers wrote:
>> > I have no comments on the substance of this patch, but note that ports/ 
>> > has a separate ChangeLog file for each architecture.
> Sorry. The attached patch now has separate ChangeLog entries for each of
> the affected archs.

Torvald,

Sorry for the late review.

This looks good to me. 

Please resend a v2 and to libc-alpha with the minor nits fixed.
 
> diff --git a/nptl/ChangeLog b/nptl/ChangeLog
> index a089153..ea161a3 100644
> --- a/nptl/ChangeLog
> +++ b/nptl/ChangeLog
> @@ -1,3 +1,10 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/sparc/pthread_once.c: Moved to ...
> +	* sysdeps/unix/sysv/linux/pthread_once.c: ... here.  Add missing
> +	memory barriers.  Add comments.

Two things.

(1) Don't include the ChangeLog diff in the diff sent to the list.

See:
https://sourceware.org/glibc/wiki/Contribution%20checklist

(2) This ChangeLog now goes directly into glibc/ChangeLog with
    leading nptl/ path parts since we got rid of hte nptl/ChangeLog
    in an effort to make life easier.

> diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/pthread_once.c
> new file mode 100644
> index 0000000..f9b0953
> --- /dev/null
> +++ b/nptl/sysdeps/unix/sysv/linux/pthread_once.c
> @@ -0,0 +1,128 @@
> +/* Copyright (C) 2003-2013 Free Software Foundation, Inc.

Update copyright to 2014 (sorry that one is my fault for not
reviewing sooner, but it should be fixed <hides>).

> +   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>

Missing `#include <atomic.h>' for the use of atomic_read_barrier.

All files must include the headers for the interfaces they depend upon.

> +
> +
> +unsigned long int __fork_generation attribute_hidden;

OK.

> +
> +
> +static void
> +clear_once_control (void *arg)
> +{
> +  pthread_once_t *once_control = (pthread_once_t *) arg;
> +
> +  /* Reset to the uninitialized state here (see __pthread_once).  Also, we

s/Also, we/We/g.

> +     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.  */

Why don't we need to make any of our writes visible to other threads that
see this value?

I'm being the devil's advocate and we need to expand this comment a little more.

> +  *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.

OK.

> +   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 (30b of once_control

What's "30b?" 30 bits? Please spell it out.

> +   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.  */

Would you mind filing a bug for this in the upstream bugzilla?

It's a distinct bug from this unification work, but a valid problem.

Can this be fixed by detecting generation counter overflow in fork
and failing the function call?

> +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();

OK.

> +      do
> +	{
> +	  /* Check if the initialization has already been done.  */
> +	  if (__builtin_expect ((val & 2) != 0, 1))

Use __glibc_likely.

e.g. if (__glibc_likely ((val & 2) != 0))

This is the fast path that we are testing for in the microbenchmark?

> +	    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;

OT: I wonder if Valgrind will report a benign race in accessing __fork_generation.

> +	  /* 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 (__builtin_expect (val != oldval, 0));

Use __glibc_unlikely.

e.g. while (__glibc_unlikely (val != oldval))

We assume the contested case is unlikely.

> +
> +      /* 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.)  */

Remove parenthetical in last setence of comment.

> +	  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);

OK.

> +
> +      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();

OK.

> +      *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)

OK.

> 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
> index 5879f44..0000000
> --- a/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c
> +++ /dev/null
> @@ -1,93 +0,0 @@
> -/* Copyright (C) 2003-2013 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)

OK.

The following ChangeLog's should not be inline with the patch,
and they should be mreged with your main ChangeLog entry since
we've moved all of them (except hppa) into the main tree.

> diff --git a/ports/ChangeLog.aarch64 b/ports/ChangeLog.aarch64
> index cebf505..13d2a72 100644
> --- a/ports/ChangeLog.aarch64
> +++ b/ports/ChangeLog.aarch64
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c: Remove file.
> +
>  2013-09-30  Andrew Pinski <andrew.pinski@caviumnetworks.com>
>  
>  	* sysdeps/unix/sysv/linux/aarch64/sysdep.h (SYSCALL_ERROR_HANDLER):
> diff --git a/ports/ChangeLog.arm b/ports/ChangeLog.arm
> index 6707d2e..cc876e5 100644
> --- a/ports/ChangeLog.arm
> +++ b/ports/ChangeLog.arm
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c: Remove file.
> +
>  2013-10-04  Will Newton  <will.newton@linaro.org>
>  
>  	* sysdeps/arm/__longjmp.S (NO_THUMB): Remove define.
> diff --git a/ports/ChangeLog.hppa b/ports/ChangeLog.hppa
> index 3e7c162..53ade36 100644
> --- a/ports/ChangeLog.hppa
> +++ b/ports/ChangeLog.hppa
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c: Remove file.
> +

>  2013-09-11  Andreas Schwab  <schwab@suse.de>
>  
>  	* sysdeps/unix/sysv/linux/hppa/bits/fcntl.h (__O_TMPFILE): Define.
> diff --git a/ports/ChangeLog.ia64 b/ports/ChangeLog.ia64
> index 272f73a..f149373 100644
> --- a/ports/ChangeLog.ia64
> +++ b/ports/ChangeLog.ia64
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c: Remove file.
> +
>  2013-09-22  Carlos O'Donell  <carlos@redhat.com>
>  
>  	[BZ #15754]
> diff --git a/ports/ChangeLog.m68k b/ports/ChangeLog.m68k
> index 4f933c6..0982588 100644
> --- a/ports/ChangeLog.m68k
> +++ b/ports/ChangeLog.m68k
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: Remove file.
> +
>  2013-09-20  Andreas Schwab  <schwab@linux-m68k.org>
>  
>  	* sysdeps/m68k/ffs.c (__ffs): Define as hidden.
> diff --git a/ports/ChangeLog.mips b/ports/ChangeLog.mips
> index eaa6ade..f52a80d 100644
> --- a/ports/ChangeLog.mips
> +++ b/ports/ChangeLog.mips
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c: Remove file.
> +
>  2013-09-26  Steve Ellcey  <sellcey@mips.com>
>  
>  	[BZ #15632]
> diff --git a/ports/ChangeLog.tile b/ports/ChangeLog.tile
> index dc2e7e4..3821ded 100644
> --- a/ports/ChangeLog.tile
> +++ b/ports/ChangeLog.tile
> @@ -1,3 +1,8 @@
> +2013-10-07  Torvald Riegel  <triegel@redhat.com>
> +
> +	[BZ #15215]
> +	* sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c: Remove file.
> +
>  2013-09-22  Carlos O'Donell  <carlos@redhat.com>
>  
>  	[BZ #15754]
> diff --git a/ports/sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c
> deleted file mode 100644
> index 2fb9b85..0000000
> --- a/ports/sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,90 +0,0 @@
> -/* Copyright (C) 2004-2013 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/ports/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c
> deleted file mode 100644
> index 0c897ab..0000000
> --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,89 +0,0 @@
> -/* Copyright (C) 2004-2013 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/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
> index b032f29..0000000
> --- a/ports/sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,93 +0,0 @@
> -/* Copyright (C) 2003-2013 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/ports/sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c
> deleted file mode 100644
> index 5879f44..0000000
> --- a/ports/sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,93 +0,0 @@
> -/* Copyright (C) 2003-2013 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/ports/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
> deleted file mode 100644
> index 8a1f307..0000000
> --- a/ports/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,90 +0,0 @@
> -/* Copyright (C) 2010-2013 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/ports/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c
> deleted file mode 100644
> index 97f1ddf..0000000
> --- a/ports/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,93 +0,0 @@
> -/* Copyright (C) 2003-2013 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/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c
> deleted file mode 100644
> index 68456f0..0000000
> --- a/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c
> +++ /dev/null
> @@ -1,94 +0,0 @@
> -/* Copyright (C) 2011-2013 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)

OK.

Cheers,
Carlos.


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