From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10634 invoked by alias); 7 Oct 2013 21:53:37 -0000 Mailing-List: contact libc-ports-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: libc-ports-owner@sourceware.org Received: (qmail 10557 invoked by uid 89); 7 Oct 2013 21:53:36 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-4.1 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 07 Oct 2013 21:53:10 +0000 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r97Lr8sP004746 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 7 Oct 2013 17:53:08 -0400 Received: from [10.36.7.187] (vpn1-7-187.ams2.redhat.com [10.36.7.187]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r97Lr4gc001606; Mon, 7 Oct 2013 17:53:05 -0400 Subject: Re: [PATCH] Unify pthread_once (bug 15215) From: Torvald Riegel To: "Joseph S. Myers" Cc: "Carlos O'Donell" , GLIBC Devel , libc-ports In-Reply-To: References: <1368024237.7774.794.camel@triegel.csb> <519D97E4.4030808@redhat.com> <1381018836.8757.3598.camel@triegel.csb> Content-Type: multipart/mixed; boundary="=-fSJ68NZcS7Ean4gLbAzo" Date: Mon, 07 Oct 2013 21:53:00 -0000 Message-ID: <1381182784.18547.138.camel@triegel.csb> Mime-Version: 1.0 X-IsSubscribed: yes X-SW-Source: 2013-10/txt/msg00011.txt.bz2 --=-fSJ68NZcS7Ean4gLbAzo Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 282 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. --=-fSJ68NZcS7Ean4gLbAzo Content-Disposition: attachment; filename="patch" Content-Type: text/x-patch; name="patch"; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 32258 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 + + [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. + 2013-10-04 Maciej W. Rozycki * tst-mutex8.c (check_type) [ENABLE_PI]: Handle ENOTSUP failure 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. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 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 + . */ + +#include "pthreadP.h" +#include + + +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 (see __pthread_once). Also, 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. */ + *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 (30b 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 (__builtin_expect ((val & 2) != 0, 1)) + 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 (__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. (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 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 , 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 - . */ - -#include "pthreadP.h" -#include - - -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/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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/aarch64/nptl/pthread_once.c: Remove file. + 2013-09-30 Andrew Pinski * 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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c: Remove file. + 2013-10-04 Will Newton * 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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/hppa/nptl/pthread_once.c: Remove file. + 2013-09-11 Andreas Schwab * 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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/ia64/nptl/pthread_once.c: Remove file. + 2013-09-22 Carlos O'Donell [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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: Remove file. + 2013-09-20 Andreas Schwab * 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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c: Remove file. + 2013-09-26 Steve Ellcey [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 + + [BZ #15215] + * sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c: Remove file. + 2013-09-22 Carlos O'Donell [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 - . */ - -#include "pthreadP.h" -#include - -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 - . */ - -#include "pthreadP.h" -#include - -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 , 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 - . */ - -#include "pthreadP.h" -#include - - -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 , 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 - . */ - -#include "pthreadP.h" -#include - - -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 , 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 - . */ - -#include "pthreadP.h" -#include - -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 , 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 - . */ - -#include "pthreadP.h" -#include - - -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 , 2011. - Based on work contributed by Jakub Jelinek , 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 - . */ - -#include -#include - - -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) --=-fSJ68NZcS7Ean4gLbAzo--