about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog13
-rw-r--r--nptl/Makefile3
-rw-r--r--nptl/allocatestack.c13
-rw-r--r--nptl/pthread_create.c26
-rw-r--r--nptl/sysdeps/pthread/createthread.c49
-rw-r--r--nptl/tst-sched1.c98
6 files changed, 167 insertions, 35 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index d86cb428ab..a8b7d743c0 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,5 +1,18 @@
 2003-08-02  Ulrich Drepper  <drepper@redhat.com>
 
+	* sysdeps/pthread/createthread.c (do_clone): If __ASSUME_CLONE_STOPPED
+	is not defined, do explicit synchronization.
+	(create_thread): Do not lock pd->lock here.  If __ASSUME_CLONE_STOPPED
+	is not defined also unlock pd->lock for non-debugging case in case
+	it is necessary.
+	* pthread_create.c (start_thread): Always get and release pd->lock
+	if __ASSUME_CLONE_STOPPED is not defined.
+	(start_thread_debug): Removed.  Adjust users.
+	* allocatestack.c (allocate_stack): Always initialize lock if
+	__ASSUME_CLONE_STOPPED is not defined.
+	* Makefile (tests): Add tst-sched1.
+	* tst-sched1.c: New file.
+
 	* sysdeps/pthread/createthread.c (do_clone): Only use
 	sched_setschduler and pass correct parameters.
 
diff --git a/nptl/Makefile b/nptl/Makefile
index cfb82e920b..63b477f30d 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -231,7 +231,8 @@ tests = tst-attr1 tst-attr2 \
 	tst-umask1 \
 	tst-popen1 \
 	tst-clock1 tst-clock2 \
-	tst-context1
+	tst-context1 \
+	tst-sched1
 
 distribute = eintr.c
 
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 729f3b8542..6ada1fe138 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -308,7 +308,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       /* The first TSD block is included in the TCB.  */
       pd->specific[0] = pd->specific_1stblock;
 
-#if LLL_LOCK_INITIALIZER != 0
+#if defined __ASSUME_CLONE_STOPPED && LLL_LOCK_INITIALIZER != 0
       /* Initialize the lock.  */
       pd->lock = LLL_LOCK_INITIALIZER;
 #endif
@@ -451,7 +451,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	     descriptor.  */
 	  pd->specific[0] = pd->specific_1stblock;
 
-#if LLL_LOCK_INITIALIZER != 0
+#if defined __ASSUME_CLONE_STOPPED && LLL_LOCK_INITIALIZER != 0
 	  /* Initialize the lock.  */
 	  pd->lock = LLL_LOCK_INITIALIZER;
 #endif
@@ -564,6 +564,13 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	}
     }
 
+#ifndef __ASSUME_CLONE_STOPPED
+  /* Initialize the lock.  We have to do this unconditionally if the
+     CLONE_STOPPED flag is not available since then the stillborn
+     thread could be canceled while the lock is taken.  */
+  pd->lock = LLL_LOCK_INITIALIZER;
+#endif
+
   /* We place the thread descriptor at the end of the stack.  */
   *pdp = pd;
 
@@ -744,7 +751,7 @@ __pthread_init_static_tls (struct link_map *map)
 
   /* Now the list with threads using user-allocated stacks.  */
   list_for_each (runp, &__stack_user)
-    init_one_static_tls (list_entry (runp, struct pthread, list), map);  
+    init_one_static_tls (list_entry (runp, struct pthread, list), map);
 
   lll_unlock (stack_cache_lock);
 }
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index ae97f4a62d..8507c3bf1d 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -33,8 +33,6 @@
 
 /* Local function to start thread and handle cleanup.  */
 static int start_thread (void *arg);
-/* Similar version used when debugging.  */
-static int start_thread_debug (void *arg);
 
 
 /* Nozero if debugging mode is enabled.  */
@@ -232,6 +230,13 @@ start_thread (void *arg)
 
   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;
@@ -331,23 +336,6 @@ start_thread (void *arg)
 }
 
 
-/* Just list start_thread but we do some more things needed for a run
-   with a debugger attached.  */
-static int
-start_thread_debug (void *arg)
-{
-  struct pthread *pd = (struct pthread *) arg;
-
-  /* Get the lock the parent locked to force synchronization.  */
-  lll_lock (pd->lock);
-  /* And give it up right away.  */
-  lll_unlock (pd->lock);
-
-  /* Now do the actual startup.  */
-  return start_thread (arg);
-}
-
-
 /* Default thread attributes for the case when the user does not
    provide any.  */
 static const struct pthread_attr default_attr =
diff --git a/nptl/sysdeps/pthread/createthread.c b/nptl/sysdeps/pthread/createthread.c
index dd5bb5a25b..23012bb476 100644
--- a/nptl/sysdeps/pthread/createthread.c
+++ b/nptl/sysdeps/pthread/createthread.c
@@ -25,6 +25,8 @@
 #include <ldsodefs.h>
 #include <tls.h>
 
+#include "kernel-features.h"
+
 
 #define CLONE_SIGNAL    	(CLONE_SIGHAND | CLONE_THREAD)
 
@@ -55,7 +57,20 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr,
   PREPARE_CREATE;
 #endif
 
-  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
+  /* Lame old kernels do not have CLONE_STOPPED support.  For those do
+     not pass the flag, not instead use the futex method.  */
+#ifndef __ASSUME_CLONE_STOPPED
+# define final_clone_flags clone_flags & ~CLONE_STOPPED
+  if (clone_flags & CLONE_STOPPED)
+    /* We Make sure the thread does not run far by forcing it to get a
+       lock.  We lock it here too so that the new thread cannot continue
+       until we tell it to.  */
+    lll_lock (pd->lock);
+#else
+# define final_clone_flags clone_flags
+#endif
+
+  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, final_clone_flags,
 		  pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
     /* Failed.  */
     return errno;
@@ -86,8 +101,10 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr,
 	    goto err_out;
 	}
 
+#ifdef __ASSUME_CLONE_STOPPED
       /* Now start the thread for real.  */
       res = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
+#endif
 
       /* If something went wrong, kill the thread.  */
       if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
@@ -98,8 +115,10 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr,
 	err_out:
 	  (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
 
+#ifdef __ASSUME_CLONE_STOPPED
 	  /* Then wake it up so that the signal can be processed.  */
-	  (void) INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
+	  (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCONT);
+#endif
 
 	  return INTERNAL_SYSCALL_ERRNO (res, err);
 	}
@@ -175,15 +194,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
       if ((_mask & (__nptl_threads_events.event_bits[_idx]
 		    | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
 	{
-	  /* We have to report the new thread.  Make sure the thread
-	     does not run far by forcing it to get a lock.  We lock it
-	     here too so that the new thread cannot continue until we
-	     tell it to.  */
-	  lll_lock (pd->lock);
-
-	  /* Create the thread.  */
-	  int res = do_clone (pd, attr, clone_flags, start_thread_debug,
-			      STACK_VARIABLES_ARGS);
+	  /* Create the thread.  We always create the thread stopped
+	     so that it does not get far before we tell the debugger.  */
+	  int res = do_clone (pd, attr, clone_flags | CLONE_STOPPED,
+			      start_thread, STACK_VARIABLES_ARGS);
 	  if (res == 0)
 	    {
 	      /* Now fill in the information about the new thread in
@@ -216,5 +230,16 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr,
 #endif
 
   /* Actually create the thread.  */
-  return do_clone (pd, attr, clone_flags, start_thread, STACK_VARIABLES_ARGS);
+  int res = do_clone (pd, attr, clone_flags, start_thread,
+		      STACK_VARIABLES_ARGS);
+
+#ifndef __ASSUME_CLONE_STOPPED
+  if (res == 0 && (clone_flags & CLONE_STOPPED))
+    {
+      /* And finally restart the new thread.  */
+      lll_unlock (pd->lock);
+    }
+#endif
+
+  return res;
 }
diff --git a/nptl/tst-sched1.c b/nptl/tst-sched1.c
new file mode 100644
index 0000000000..4d0702c79b
--- /dev/null
+++ b/nptl/tst-sched1.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+static int global;
+
+static void *
+tf (void *a)
+{
+  global = 1;
+
+  return 0;
+}
+
+
+int
+do_test (void)
+{
+  pthread_t th;
+  pthread_attr_t at;
+
+  if (pthread_attr_init (&at) != 0)
+    {
+      puts ("attr_init failed");
+      return 1;
+    }
+
+  if (pthread_attr_setschedpolicy (&at, SCHED_OTHER) != 0)
+    {
+      puts ("attr_setschedpolicy failed");
+      return 1;
+    }
+
+  struct sched_param pa;
+  if (sched_getparam (getpid (), &pa) != 0)
+    {
+      puts ("sched_getschedparam failed");
+      return 1;
+    }
+
+  if (pthread_attr_setschedparam (&at, &pa) != 0)
+    {
+      puts ("attr_setschedparam failed");
+      return 1;
+    }
+
+  if (pthread_attr_setinheritsched (&at, PTHREAD_EXPLICIT_SCHED) != 0)
+    {
+      puts ("attr_setinheritsched failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, &at, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int e = pthread_join (th, NULL);
+  if (e != 0)
+    {
+      printf ("join failed: %d\n", e);
+      return 1;
+    }
+
+  if (global == 0)
+    {
+      puts ("thread didn't run");
+      return 1;
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"