Fix failure handling for thread creation
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / createthread.c
index 7ddaf9c..1917152 100644 (file)
 
 #include <tls.h>
 #include <ucontext.h>
 
 #include <tls.h>
 #include <ucontext.h>
-#include <sys/segments.h>
 #include <sys/stack.h>
 #include <sys/stack.h>
 #include <sys/regset.h>
 #include <sys/stack.h>
 #include <sys/stack.h>
 #include <sys/regset.h>
-#include <sys/segments.h>
+#include <sys/lwp.h>
 #include <inline-syscall.h>
 #include <inline-syscall.h>
-#include <sched_priv.h>
+#include <schedP.h>
 #include <createthread_arch.c>
 
 DECLARE_INLINE_SYSCALL (int, lwp_create, ucontext_t *ucp, int flags,
 #include <createthread_arch.c>
 
 DECLARE_INLINE_SYSCALL (int, lwp_create, ucontext_t *ucp, int flags,
@@ -55,6 +54,9 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
   if (errval != 0)
     return errval;
 
   if (errval != 0)
     return errval;
 
+  /* Threads inherit the parent's sigmask.  */
+  pthread_sigmask (SIG_SETMASK, NULL, &ctx.uc_sigmask);
+
   /* One more thread.  We cannot have the thread do this itself, since it
      might exist but not have been scheduled yet by the time we've returned
      and need to check the value to behave correctly.  We must do it before
   /* One more thread.  We cannot have the thread do this itself, since it
      might exist but not have been scheduled yet by the time we've returned
      and need to check the value to behave correctly.  We must do it before
@@ -68,10 +70,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
   /* We set the thread to be initially suspended so that we can set
      scheduling magic.  */
   int lwp_flags =
   /* We set the thread to be initially suspended so that we can set
      scheduling magic.  */
   int lwp_flags =
-      ((attr->flags & ATTR_FLAG_DAEMON) ? THR_DAEMON : 0) |
-      ((attr->flags & ATTR_FLAG_DETACHSTATE) ? THR_DETACHED : 0);
-  if (attr->flags & ATTR_FLAG_THR_CREATE == 0)
-    lwp_flags |= THR_SUSPENDED;
+      ((attr->flags & ATTR_FLAG_DAEMON) ? LWP_DAEMON : 0) |
+      ((attr->flags & ATTR_FLAG_DETACHSTATE) ? LWP_DETACHED : 0);
+  if ((attr->flags & ATTR_FLAG_THR_CREATE) == 0)
+    lwp_flags |= LWP_SUSPENDED;
   errval = INLINE_SYSCALL (lwp_create, 3, &ctx, lwp_flags, &pd->tid);
   if (errval == 0 && (attr->flags & ATTR_FLAG_THR_CREATE) == 0)
     {
   errval = INLINE_SYSCALL (lwp_create, 3, &ctx, lwp_flags, &pd->tid);
   if (errval == 0 && (attr->flags & ATTR_FLAG_THR_CREATE) == 0)
     {
@@ -96,28 +98,36 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
             errval = EPERM;
         }
 
             errval = EPERM;
         }
 
-      /* Resume thread if requested.  */
-      if (errval == 0)
+      if (errval == 0 && !(attr->flags & ATTR_FLAG_SUSPENDED))
         {
         {
-          if (!(attr->flags & ATTR_FLAG_SUSPENDED))
-            errval = INLINE_SYSCALL (lwp_continue, 1, pd->tid);
+          errval = INLINE_SYSCALL (lwp_continue, 1, pd->tid);
         }
         }
+      else if (errval != 0)
+        {
+          pd->flags |= ATTR_FLAG_CREATE_FAILED;
+          INLINE_SYSCALL (lwp_continue, 1, pd->tid);
+
+          if (!IS_DETACHED (pd))
+            {
+              int result;
+              lll_wait_tid (pd->tid);
+            }
 
 
-      /* Kill the thread if we didn't succeed above.  */
-      if (errval != 0)
-        INLINE_SYSCALL (lwp_kill, 2, pd->tid, SIGKILL);
+          /* Note: if the thread is detached, start_thread will free pd;
+             otherwise the caller of create_thread will free pd.  */
+        }
     }
 
     }
 
-  if (errval != 0)
+  if (errval == 0)
+    {
+      /* We now have for sure more than one thread.  The main thread might
+         not yet have the flag set.  No need to set the global variable
+         again if this is what we use.  */
+      THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+    }
+  else
     {
       atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */
     {
       atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */
-
-      /* Failed.  If the thread is detached, remove the TCB here since
-         the caller cannot do this.  The caller remembered the thread
-         as detached and cannot reverify that it is not since it must
-         not access the thread descriptor again.  */
-      if (IS_DETACHED (pd))
-        __deallocate_stack (pd);
     }
 
   return errval;
     }
 
   return errval;