* 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.
This commit is contained in:
Ulrich Drepper 2003-08-03 06:47:02 +00:00
parent 0cbc6c4eba
commit f1205aa71f
6 changed files with 167 additions and 35 deletions

View File

@ -1,5 +1,18 @@
2003-08-02 Ulrich Drepper <drepper@redhat.com> 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 * sysdeps/pthread/createthread.c (do_clone): Only use
sched_setschduler and pass correct parameters. sched_setschduler and pass correct parameters.

View File

@ -231,7 +231,8 @@ tests = tst-attr1 tst-attr2 \
tst-umask1 \ tst-umask1 \
tst-popen1 \ tst-popen1 \
tst-clock1 tst-clock2 \ tst-clock1 tst-clock2 \
tst-context1 tst-context1 \
tst-sched1
distribute = eintr.c distribute = eintr.c

View File

@ -308,7 +308,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* The first TSD block is included in the TCB. */ /* The first TSD block is included in the TCB. */
pd->specific[0] = pd->specific_1stblock; pd->specific[0] = pd->specific_1stblock;
#if LLL_LOCK_INITIALIZER != 0 #if defined __ASSUME_CLONE_STOPPED && LLL_LOCK_INITIALIZER != 0
/* Initialize the lock. */ /* Initialize the lock. */
pd->lock = LLL_LOCK_INITIALIZER; pd->lock = LLL_LOCK_INITIALIZER;
#endif #endif
@ -451,7 +451,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
descriptor. */ descriptor. */
pd->specific[0] = pd->specific_1stblock; pd->specific[0] = pd->specific_1stblock;
#if LLL_LOCK_INITIALIZER != 0 #if defined __ASSUME_CLONE_STOPPED && LLL_LOCK_INITIALIZER != 0
/* Initialize the lock. */ /* Initialize the lock. */
pd->lock = LLL_LOCK_INITIALIZER; pd->lock = LLL_LOCK_INITIALIZER;
#endif #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. */ /* We place the thread descriptor at the end of the stack. */
*pdp = pd; *pdp = pd;

View File

@ -33,8 +33,6 @@
/* Local function to start thread and handle cleanup. */ /* Local function to start thread and handle cleanup. */
static int start_thread (void *arg); static int start_thread (void *arg);
/* Similar version used when debugging. */
static int start_thread_debug (void *arg);
/* Nozero if debugging mode is enabled. */ /* Nozero if debugging mode is enabled. */
@ -232,6 +230,13 @@ start_thread (void *arg)
struct pthread *pd = (struct pthread *) 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 #if HP_TIMING_AVAIL
/* Remember the time when the thread was started. */ /* Remember the time when the thread was started. */
hp_timing_t now; 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 /* Default thread attributes for the case when the user does not
provide any. */ provide any. */
static const struct pthread_attr default_attr = static const struct pthread_attr default_attr =

View File

@ -25,6 +25,8 @@
#include <ldsodefs.h> #include <ldsodefs.h>
#include <tls.h> #include <tls.h>
#include "kernel-features.h"
#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD) #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
@ -55,7 +57,20 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr,
PREPARE_CREATE; PREPARE_CREATE;
#endif #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) pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
/* Failed. */ /* Failed. */
return errno; return errno;
@ -86,8 +101,10 @@ do_clone (struct pthread *pd, const struct pthread_attr *attr,
goto err_out; goto err_out;
} }
#ifdef __ASSUME_CLONE_STOPPED
/* Now start the thread for real. */ /* Now start the thread for real. */
res = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT); res = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCONT);
#endif
/* If something went wrong, kill the thread. */ /* If something went wrong, kill the thread. */
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) 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: err_out:
(void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL); (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
#ifdef __ASSUME_CLONE_STOPPED
/* Then wake it up so that the signal can be processed. */ /* 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); 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] if ((_mask & (__nptl_threads_events.event_bits[_idx]
| pd->eventbuf.eventmask.event_bits[_idx])) != 0) | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
{ {
/* We have to report the new thread. Make sure the thread /* Create the thread. We always create the thread stopped
does not run far by forcing it to get a lock. We lock it so that it does not get far before we tell the debugger. */
here too so that the new thread cannot continue until we int res = do_clone (pd, attr, clone_flags | CLONE_STOPPED,
tell it to. */ start_thread, STACK_VARIABLES_ARGS);
lll_lock (pd->lock);
/* Create the thread. */
int res = do_clone (pd, attr, clone_flags, start_thread_debug,
STACK_VARIABLES_ARGS);
if (res == 0) if (res == 0)
{ {
/* Now fill in the information about the new thread in /* 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 #endif
/* Actually create the thread. */ /* 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;
} }

98
nptl/tst-sched1.c Normal file
View File

@ -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"