Revert "Async-signal safe TLS."
[jlayton/glibc.git] / nptl / allocatestack.c
index 899c0e8eee9fc263d5dcaf8662c3513c62a781d7..7f6094ebb2b99f73fbdc01a2c1c23e95b6dcddb3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002-2007, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2014 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 <errno.h>
@@ -26,7 +25,9 @@
 #include <sys/mman.h>
 #include <sys/param.h>
 #include <dl-sysdep.h>
+#include <dl-tls.h>
 #include <tls.h>
+#include <list.h>
 #include <lowlevellock.h>
 #include <kernel-features.h>
 
@@ -213,6 +214,9 @@ get_cached_stack (size_t *sizep, void **memp)
       return NULL;
     }
 
+  /* Don't allow setxid until cloned.  */
+  result->setxid_futex = -1;
+
   /* Dequeue the entry.  */
   stack_list_del (&result->list);
 
@@ -238,7 +242,7 @@ get_cached_stack (size_t *sizep, void **memp)
 
   /* Clear the DTV.  */
   dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
-  memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+  _dl_clear_dtv (dtv);
 
   /* Re-initialize the TLS.  */
   _dl_allocate_tls_init (TLS_TPADJ (result));
@@ -332,6 +336,10 @@ change_stack_perm (struct pthread *pd
 }
 
 
+/* Returns a usable stack for a new thread either by allocating a
+   new stack or reusing a cached stack of sufficient size.
+   ATTR must be non-NULL and point to a valid pthread_attr.
+   PDP must be non-NULL.  */
 static int
 allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
                ALLOCATE_STACK_PARMS)
@@ -341,13 +349,19 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
   size_t pagesize_m1 = __getpagesize () - 1;
   void *stacktop;
 
-  assert (attr != NULL);
   assert (powerof2 (pagesize_m1 + 1));
   assert (TCB_ALIGNMENT >= STACK_ALIGN);
 
   /* Get the stack size from the attribute if it is set.  Otherwise we
      use the default we determined at start time.  */
-  size = attr->stacksize ?: __default_stacksize;
+  if (attr->stacksize != 0)
+    size = attr->stacksize;
+  else
+    {
+      lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
+      size = __default_pthread_attr.stacksize;
+      lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
+    }
 
   /* Get memory for the stack.  */
   if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
@@ -418,12 +432,15 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       /* The process ID is also the same as that of the caller.  */
       pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
 
+      /* Don't allow setxid until cloned.  */
+      pd->setxid_futex = -1;
+
       /* Allocate the DTV for this thread.  */
       if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
        {
          /* Something went wrong.  */
          assert (errno == ENOMEM);
-         return EAGAIN;
+         return errno;
        }
 
 
@@ -484,12 +501,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
 
          if (__builtin_expect (mem == MAP_FAILED, 0))
-           {
-             if (errno == ENOMEM)
-               __set_errno (EAGAIN);
-
-              return errno;
-           }
+           return errno;
 
          /* SIZE is guaranteed to be greater than zero.
             So we can never get a null pointer back from mmap.  */
@@ -554,6 +566,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
          THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
 #endif
 
+         /* Don't allow setxid until cloned.  */
+         pd->setxid_futex = -1;
+
          /* The process ID is also the same as that of the caller.  */
          pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
 
@@ -566,7 +581,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
              /* Free the stack memory we just allocated.  */
              (void) munmap (mem, size);
 
-             return EAGAIN;
+             return errno;
            }
 
 
@@ -621,10 +636,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 #endif
          if (mprotect (guard, guardsize, PROT_NONE) != 0)
            {
-             int err;
            mprot_error:
-             err = errno;
-
              lll_lock (stack_cache_lock, LLL_PRIVATE);
 
              /* Remove the thread from the list.  */
@@ -642,7 +654,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
                 is nothing we could do.  */
              (void) munmap (mem, size);
 
-             return err;
+             return errno;
            }
 
          pd->guardsize = guardsize;
@@ -810,7 +822,7 @@ __reclaim_stacks (void)
   if (in_flight_stack != 0)
     {
       bool add_p = in_flight_stack & 1;
-      list_t *elem = (list_t *) (in_flight_stack & ~UINTMAX_C (1));
+      list_t *elem = (list_t *) (in_flight_stack & ~(uintptr_t) 1);
 
       if (add_p)
        {
@@ -910,8 +922,9 @@ __reclaim_stacks (void)
 
   in_flight_stack = 0;
 
-  /* Initialize the lock.  */
+  /* Initialize locks.  */
   stack_cache_lock = LLL_LOCK_INITIALIZER;
+  __default_pthread_attr_lock = LLL_LOCK_INITIALIZER;
 }
 
 
@@ -985,7 +998,16 @@ setxid_mark_thread (struct xid_command *cmdp, struct pthread *t)
 
       /* If the thread is exiting right now, ignore it.  */
       if ((ch & EXITING_BITMASK) != 0)
-       return;
+       {
+         /* Release the futex if there is no other setxid in
+            progress.  */
+         if ((ch & SETXID_BITMASK) == 0)
+           {
+             t->setxid_futex = 1;
+             lll_futex_wake (&t->setxid_futex, 1, LLL_PRIVATE);
+           }
+         return;
+       }
     }
   while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
                                               ch | SETXID_BITMASK, ch));
@@ -1022,18 +1044,8 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
 
   int val;
   INTERNAL_SYSCALL_DECL (err);
-#if __ASSUME_TGKILL
   val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
                          t->tid, SIGSETXID);
-#else
-# ifdef __NR_tgkill
-  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
-                         t->tid, SIGSETXID);
-  if (INTERNAL_SYSCALL_ERROR_P (val, err)
-      && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
-# endif
-    val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
-#endif
 
   /* If this failed, it must have had not started yet or else exited.  */
   if (!INTERNAL_SYSCALL_ERROR_P (val, err))