OSDN Git Service

NPTL: fork: relief register pressure on arm thumb1
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / fork.c
index a84b5c2..af40410 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2007, 2008 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -13,9 +13,8 @@
    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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
 #include <stdlib.h>
@@ -58,8 +57,15 @@ fresetlockfiles (void)
 #endif
 }
 
-extern __typeof(fork) __libc_fork;
-pid_t __libc_fork (void)
+pid_t
+#if defined __arm__ && defined __thumb__ && __GNUC_PREREQ (4,6)
+/* GCC PR target/53735
+ * In thumb1 we run out of registers when compiling with Os so relax that
+ * to have more registers available for spilling by using O2 here.
+ */
+attribute_optimize("O2")
+#endif
+fork (void)
 {
   pid_t pid;
   struct used_handler
@@ -73,6 +79,9 @@ pid_t __libc_fork (void)
   struct fork_handler *runp;
   while ((runp = __fork_handlers) != NULL)
     {
+      /* Make sure we read from the current RUNP pointer.  */
+      atomic_full_barrier ();
+
       unsigned int oldval = runp->refcntr;
 
       if (oldval == 0)
@@ -166,6 +175,8 @@ pid_t __libc_fork (void)
       /* Reset locks in the I/O code.  */
       STDIO_INIT_MUTEX(_stdio_openlist_add_lock);
 
+      /* XXX reset any locks in dynamic loader */
+
       /* Run the handlers registered for the child.  */
       while (allp != NULL)
        {
@@ -173,8 +184,11 @@ pid_t __libc_fork (void)
            allp->handler->child_handler ();
 
          /* Note that we do not have to wake any possible waiter.
-            This is the only thread in the new process.  */
-         --allp->handler->refcntr;
+            This is the only thread in the new process.  The count
+            may have been bumped up by other threads doing a fork.
+            We reset it to 1, to avoid waiting for non-existing
+            thread(s) to release the count.  */
+         allp->handler->refcntr = 1;
 
          /* XXX We could at this point look through the object pool
             and mark all objects not on the __fork_handlers list as
@@ -186,7 +200,7 @@ pid_t __libc_fork (void)
        }
 
       /* Initialize the fork lock.  */
-      __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER;
+      __fork_lock = LLL_LOCK_INITIALIZER;
     }
   else
     {
@@ -206,7 +220,7 @@ pid_t __libc_fork (void)
 
          if (atomic_decrement_and_test (&allp->handler->refcntr)
              && allp->handler->need_signal)
-           lll_futex_wake (allp->handler->refcntr, 1);
+           lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE);
 
          allp = allp->next;
        }
@@ -214,7 +228,4 @@ pid_t __libc_fork (void)
 
   return pid;
 }
-weak_alias(__libc_fork,__fork)
-libc_hidden_proto(fork)
-weak_alias(__libc_fork,fork)
-libc_hidden_weak(fork)
+libc_hidden_def(fork)