2004-11-09 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / nptl / pthread_create.c
index 8507c3b..82a3c68 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -60,9 +60,6 @@ struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
   __attribute__ ((nocommon));
 hidden_data_def (__pthread_keys)
 
-/* This is for libthread_db only.  */
-const int __pthread_pthread_sizeof_descr = sizeof (struct pthread);
-
 struct pthread *
 internal_function
 __find_in_stack_list (pd)
@@ -105,9 +102,9 @@ __find_in_stack_list (pd)
 
 
 /* Deallocate POSIX thread-local-storage.  */
-static void
-internal_function
-deallocate_tsd (void)
+void
+attribute_hidden
+__nptl_deallocate_tsd (void)
 {
   struct pthread *self = THREAD_SELF;
 
@@ -225,18 +222,8 @@ __free_tcb (struct pthread *pd)
 static int
 start_thread (void *arg)
 {
-  /* One more thread.  */
-  atomic_increment (&__nptl_nthreads);
-
   struct pthread *pd = (struct pthread *) arg;
 
-#ifndef __ASSUME_CLONE_STOPPED
-  /* Get the lock the parent locked to force synchronization.  */
-  lll_lock (pd->lock);
-  /* And give it up right away.  */
-  lll_unlock (pd->lock);
-#endif
-
 #if HP_TIMING_AVAIL
   /* Remember the time when the thread was started.  */
   hp_timing_t now;
@@ -262,6 +249,18 @@ start_thread (void *arg)
       /* Store the new cleanup handler info.  */
       THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
 
+      if (__builtin_expect (pd->stopped_start, 0))
+       {
+         int oldtype = CANCEL_ASYNC ();
+
+         /* Get the lock the parent locked to force synchronization.  */
+         lll_lock (pd->lock);
+         /* And give it up right away.  */
+         lll_unlock (pd->lock);
+
+         CANCEL_RESET (oldtype);
+       }
+
       /* Run the code the user provided.  */
 #ifdef CALL_THREAD_FCT
       THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd));
@@ -271,7 +270,7 @@ start_thread (void *arg)
     }
 
   /* Run the destructor for the thread-local data.  */
-  deallocate_tsd ();
+  __nptl_deallocate_tsd ();
 
   /* Clean up any state libc stored in thread-local variables.  */
   __libc_thread_freeres ();
@@ -389,7 +388,9 @@ __pthread_create_2_1 (newthread, attr, start_routine, arg)
   pd->arg = arg;
 
   /* Copy the thread attribute flags.  */
-  pd->flags = iattr->flags;
+  struct pthread *self = THREAD_SELF;
+  pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
+              | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
 
   /* Initialize the field for the ID of the thread which is waiting
      for us.  This is a self-reference in case the thread is created
@@ -397,37 +398,70 @@ __pthread_create_2_1 (newthread, attr, start_routine, arg)
   pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
 
   /* The debug events are inherited from the parent.  */
-  pd->eventbuf = THREAD_SELF->eventbuf;
+  pd->eventbuf = self->eventbuf;
 
 
-  /* Determine scheduling parameters for the thread.
-     XXX How to determine whether scheduling handling is needed?  */
-  if (0 && attr != NULL)
+  /* Copy the parent's scheduling parameters.  The flags will say what
+     is valid and what is not.  */
+  pd->schedpolicy = self->schedpolicy;
+  pd->schedparam = self->schedparam;
+
+  /* Determine scheduling parameters for the thread.  */
+  if (attr != NULL
+      && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
+      && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
     {
-      if (iattr->flags & ATTR_FLAG_NOTINHERITSCHED)
+      INTERNAL_SYSCALL_DECL (err);
+
+      /* Use the scheduling parameters the user provided.  */
+      if (iattr->flags & ATTR_FLAG_POLICY_SET)
+       pd->schedpolicy = iattr->schedpolicy;
+      else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
+       {
+         pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, err, 1, 0);
+         pd->flags |= ATTR_FLAG_POLICY_SET;
+       }
+
+      if (iattr->flags & ATTR_FLAG_SCHED_SET)
+       memcpy (&pd->schedparam, &iattr->schedparam,
+               sizeof (struct sched_param));
+      else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
        {
-         /* Use the scheduling parameters the user provided.  */
-         pd->schedpolicy = iattr->schedpolicy;
-         memcpy (&pd->schedparam, &iattr->schedparam,
-                 sizeof (struct sched_param));
+         INTERNAL_SYSCALL (sched_getparam, err, 2, 0, &pd->schedparam);
+         pd->flags |= ATTR_FLAG_SCHED_SET;
        }
-      else
+
+      /* Check for valid priorities.  */
+      int minprio = INTERNAL_SYSCALL (sched_get_priority_min, err, 1,
+                                     iattr->schedpolicy);
+      int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, err, 1,
+                                     iattr->schedpolicy);
+      if (pd->schedparam.sched_priority < minprio
+         || pd->schedparam.sched_priority > maxprio)
        {
-         /* Just store the scheduling attributes of the parent.  */
-         pd->schedpolicy = __sched_getscheduler (0);
-         __sched_getparam (0, &pd->schedparam);
+         err = EINVAL;
+         goto errout;
        }
     }
 
   /* Pass the descriptor to the caller.  */
   *newthread = (pthread_t) pd;
 
+  /* Remember whether the thread is detached or not.  In case of an
+     error we have to free the stacks of non-detached stillborn
+     threads.  */
+  bool is_detached = IS_DETACHED (pd);
+
   /* Start the thread.  */
   err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
   if (err != 0)
     {
       /* Something went wrong.  Free the resources.  */
-      __deallocate_stack (pd);
+      if (!is_detached)
+       {
+       errout:
+         __deallocate_stack (pd);
+       }
       return err;
     }
 
@@ -464,6 +498,7 @@ __pthread_create_2_0 (newthread, attr, start_routine, arg)
       new_attr.guardsize = ps;
       new_attr.stackaddr = NULL;
       new_attr.stacksize = 0;
+      new_attr.cpuset = NULL;
 
       /* We will pass this value on to the real implementation.  */
       attr = (pthread_attr_t *) &new_attr;
@@ -474,3 +509,7 @@ __pthread_create_2_0 (newthread, attr, start_routine, arg)
 compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
               GLIBC_2_0);
 #endif
+\f
+/* Information for libthread_db.  */
+
+#include "../nptl_db/db_info.c"