diff options
-rw-r--r-- | nptl/ChangeLog | 13 | ||||
-rw-r--r-- | nptl/Makefile | 3 | ||||
-rw-r--r-- | nptl/allocatestack.c | 13 | ||||
-rw-r--r-- | nptl/pthread_create.c | 26 | ||||
-rw-r--r-- | nptl/sysdeps/pthread/createthread.c | 49 | ||||
-rw-r--r-- | nptl/tst-sched1.c | 98 |
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" |