1998-03-13 00:46  Ulrich Drepper  <drepper@cygnus.com>

	* attr.c: Implement pthread_attr_[gs]etguardsize,
	pthread_attr_[gs]setstackaddr, pthread_attr_[gs]etstacksize.
	Change pthread_attr_init to have two interfaces.
	* internals.h (struct _pthread_descr_struct): Add new fields for
	above functions.
	* libpthread.map: Add names in GLIBC_2.1 section.
	* manager.c (pthread_handle_create): Implement guardsize and
	user stack.
	(pthread_free): Likewise.
	* pthread.c (pthread_create): Add new interface for changed
	pthread_attr_t.
	* sysdeps/pthread/pthread.h: Add prototypes for new functions.
	* sysdeps/unix/sysv/linux/bits/local_lim.h: Add definition of
	PTHREAD_STACK_MIN.

	* manager.c: Enable resetting of the thread scheduling policy
	to SCHED_OTHER when the parent thread has a different one.
This commit is contained in:
Ulrich Drepper 1998-03-13 00:56:15 +00:00
parent 441e41325e
commit 5d409851a3
9 changed files with 292 additions and 26 deletions

View File

@ -1,8 +1,24 @@
1998-03-13 00:46 Ulrich Drepper <drepper@cygnus.com>
* attr.c: Implement pthread_attr_[gs]etguardsize,
pthread_attr_[gs]setstackaddr, pthread_attr_[gs]etstacksize.
Change pthread_attr_init to have two interfaces.
* internals.h (struct _pthread_descr_struct): Add new fields for
above functions.
* libpthread.map: Add names in GLIBC_2.1 section.
* manager.c (pthread_handle_create): Implement guardsize and
user stack.
(pthread_free): Likewise.
* pthread.c (pthread_create): Add new interface for changed
pthread_attr_t.
* sysdeps/pthread/pthread.h: Add prototypes for new functions.
* sysdeps/unix/sysv/linux/bits/local_lim.h: Add definition of
PTHREAD_STACK_MIN.
1998-03-11 00:42 Wolfram Gloger <wmglo@dent.med.uni-muenchen.de>
* linuxthreads/manager.c: Enable resetting of the thread
scheduling policy to SCHED_OTHER when the parent thread
has a different one.
* manager.c: Enable resetting of the thread scheduling policy
to SCHED_OTHER when the parent thread has a different one.
1998-02-01 13:51 Ulrich Drepper <drepper@cygnus.com>

View File

@ -71,7 +71,7 @@ STATUS:
- libc 6 (glibc 2) provides much better thread support than libc 5,
and comes with a specially-adapted version of LinuxThreads.
For serious multithreaded programming, you should consider switching
to glibc 2. It is available from prep.ai.mit.edu:/pub/gnu and its mirrors.
to glibc 2. It is available from ftp.gnu.org:/pub/gnu and its mirrors.
WARNING:
@ -107,6 +107,9 @@ KNOWN BUGS AND LIMITATIONS:
threads blocked on mutexes or conditions; the other is for thread
cancellation.
*** This is not anymore true when the application runs on a kernel
newer than approximately 2.1.60.
- The stacks for the threads are allocated high in the memory space,
below the stack of the initial process, and spaced 2M apart.
Stacks are allocated with the "grow on demand" flag, so they don't

View File

@ -15,10 +15,30 @@
/* Handling of thread attributes */
#include <unistd.h>
#include <sys/param.h>
#include "pthread.h"
#include "internals.h"
int pthread_attr_init(pthread_attr_t *attr)
int __pthread_attr_init_2_1(pthread_attr_t *attr)
{
size_t ps = __getpagesize ();
attr->detachstate = PTHREAD_CREATE_JOINABLE;
attr->schedpolicy = SCHED_OTHER;
attr->schedparam.sched_priority = 0;
attr->inheritsched = PTHREAD_EXPLICIT_SCHED;
attr->scope = PTHREAD_SCOPE_SYSTEM;
attr->guardsize = ps;
attr->stackaddr = NULL;
attr->stackaddr_set = 0;
attr->stacksize = STACK_SIZE - ps;
return 0;
}
#if defined HAVE_ELF && defined PIC && defined DO_VERSIONING
default_symbol_version (__pthread_attr_init_2_1, pthread_attr_init, GLIBC_2.1);
int __pthread_attr_init_2_0(pthread_attr_t *attr)
{
attr->detachstate = PTHREAD_CREATE_JOINABLE;
attr->schedpolicy = SCHED_OTHER;
@ -27,6 +47,10 @@ int pthread_attr_init(pthread_attr_t *attr)
attr->scope = PTHREAD_SCOPE_SYSTEM;
return 0;
}
symbol_version (__pthread_attr_init_2_0, pthread_attr_init, GLIBC_2.0);
#else
strong_alias (__pthread_attr_init_2_1, pthread_attr_init)
#endif
int pthread_attr_destroy(pthread_attr_t *attr)
{
@ -115,3 +139,67 @@ int pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
*scope = attr->scope;
return 0;
}
int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
{
size_t ps = __getpagesize ();
/* First round up the guard size. */
guardsize = roundup (guardsize, ps);
/* The current implementation of LinuxThreads allocates 2MB stack space
for each thread. So the maximum guardsize is 2MB - pagesize. */
if (guardsize >= STACK_SIZE - ps)
return EINVAL;
attr->guardsize = guardsize;
return 0;
}
weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize)
int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
{
*guardsize = attr->guardsize;
return 0;
}
weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize)
int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
{
attr->stackaddr = stackaddr;
attr->stackaddr_set = 1;
return 0;
}
weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
{
/* XXX This function has a stupid definition. The standard specifies
no error value but what is if no stack address was set? We simply
return the value we have in the member. */
*stackaddr = attr->stackaddr;
return 0;
}
weak_alias (__pthread_attr_getstackaddr, pthread_attr_etstackaddr)
int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
size_t ps = __getpagesize ();
/* We don't accept value smaller than PTHREAD_STACK_MIN or bigger than
2MB - pagesize. */
if (stacksize < PTHREAD_STACK_MIN || stacksize > STACK_SIZE - ps)
return EINVAL;
attr->stacksize = stacksize;
return 0;
}
weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
{
*stacksize = attr->stacksize;
return 0;
}
weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)

View File

@ -84,6 +84,9 @@ struct _pthread_descr_struct {
struct pthread_start_args p_start_args; /* arguments for thread creation */
void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
int p_userstack; /* nonzero if the user provided the thread */
void *p_guardaddr; /* address of guard area or NULL */
size_t p_guardsize; /* size of guard area */
};
/* The type of thread handles. */

View File

@ -53,10 +53,19 @@ GLIBC_2.0 {
GLIBC_2.1 {
global:
# Functions with changed interface.
pthread_attr_init; pthread_create;
# Unix98 extensions.
pthread_rwlock_init; pthread_rwlock_destroy; pthread_rwlock_rdlock;
pthread_rwlock_tryrdlock; pthread_rwlock_wrlock; pthread_rwlock_trywrlock;
pthread_rwlock_unlock; pthread_rwlockattr_init; pthread_rwlockattr_destroy;
pthread_rwlockattr_getpshared; pthread_rwlockattr_setpshared;
pthread_rwlockattr_getkind_np; pthread_rwlockattr_setkind_np;
pthread_attr_getguardsize; pthread_attr_setguardsize;
pthread_attr_getstackaddr; pthread_attr_setstackaddr;
pthread_attr_getstacksize; pthread_attr_setstacksize;
pthread_getconcurrency; pthread_setconcurrency;
} GLIBC_2.0;

View File

@ -172,27 +172,54 @@ static int pthread_start_thread(void *arg)
}
static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg,
sigset_t * mask, int father_pid)
void * (*start_routine)(void *), void *arg,
sigset_t * mask, int father_pid)
{
size_t sseg;
int pid;
pthread_descr new_thread;
pthread_t new_thread_id;
int i;
void *guardaddr = NULL;
/* Find a free stack segment for the current stack */
for (sseg = 1; ; sseg++) {
if (sseg >= PTHREAD_THREADS_MAX) return EAGAIN;
if (__pthread_handles[sseg].h_descr != NULL) continue;
new_thread = thread_segment(sseg);
/* Allocate space for stack and thread descriptor. */
if (mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0)
!= MAP_FAILED) break;
/* It seems part of this segment is already mapped. Try the next. */
}
for (sseg = 1; ; sseg++)
{
if (sseg >= PTHREAD_THREADS_MAX)
return EAGAIN;
if (__pthread_handles[sseg].h_descr != NULL)
continue;
if (attr == NULL || !attr->stackaddr_set)
{
new_thread = thread_segment(sseg);
/* Allocate space for stack and thread descriptor. */
if (mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
-1, 0) != MAP_FAILED)
{
/* We manage to get a stack. Now see whether we need a guard
and allocate it if necessary. */
if (attr->guardsize != 0)
{
guardaddr = mmap ((caddr_t)((char *)(new_thread+1)
- 2*1024*1024),
attr->guardsize, 0, MAP_FIXED, -1, 0);
if (guardaddr == MAP_FAILED)
/* We don't make this an error. */
guardaddr = NULL;
}
break;
}
/* It seems part of this segment is already mapped. Try the next. */
}
else
{
new_thread = (pthread_descr) attr->stackaddr - 1;
break;
}
}
/* Allocate new thread identifier */
pthread_threads_counter += PTHREAD_THREADS_MAX;
new_thread_id = sseg + pthread_threads_counter;
@ -217,6 +244,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
new_thread->p_errno = 0;
new_thread->p_h_errnop = &new_thread->p_h_errno;
new_thread->p_h_errno = 0;
new_thread->p_guardaddr = guardaddr;
new_thread->p_guardsize = (attr == NULL || !attr->stackaddr_set
? attr->guardsize : 0);
new_thread->p_userstack = attr != NULL && attr->stackaddr_set;
for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
new_thread->p_specific[i] = NULL;
/* Initialize the thread handle */
@ -249,9 +280,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
new_thread);
/* Check if cloning succeeded */
if (pid == -1) {
/* Free the stack */
munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
INITIAL_STACK_SIZE);
/* Free the stack if we allocated it */
if (attr == NULL || !attr->stackaddr_set)
{
munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
INITIAL_STACK_SIZE);
if (attr->guardsize != 0)
munmap(new_thread->p_guardaddr, new_thread->p_guardsize);
}
__pthread_handles[sseg].h_descr = NULL;
return errno;
}
@ -268,6 +304,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
return 0;
}
/* Free the resources of a thread. */
static void pthread_free(pthread_descr th)
@ -281,8 +318,13 @@ static void pthread_free(pthread_descr th)
release(&handle->h_spinlock);
/* If initial thread, nothing to free */
if (th == &__pthread_initial_thread) return;
/* Free the stack and thread descriptor area */
munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
if (!th->p_userstack)
{
/* Free the stack and thread descriptor area */
munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
if (th->p_guardsize != 0)
munmap(th->p_guardaddr, th->p_guardsize);
}
}
/* Handle threads that have exited */

View File

@ -234,8 +234,8 @@ static int pthread_initialize_manager(void)
/* Thread creation */
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg)
int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg)
{
pthread_descr self = thread_self();
struct pthread_request request;
@ -255,6 +255,35 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
return self->p_retcode;
}
#if defined HAVE_ELF && defined PIC && defined DO_VERSIONING
default_symbol_version (__pthread_create_2_1, pthread_create, GLIBC_2.1);
int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg)
{
/* The ATTR attribute is not really of type `pthread_attr_t *'. It has
the old size and access to the new members might crash the program.
We convert the struct now. */
pthread_attr_t new_attr;
if (attr != NULL)
{
size_t ps = __getpagesize ();
memcpy (&new_attr, attr, (size_t) &(((pthread_attr_t*)NULL)->guardsize));
new_attr.guardsize = ps;
new_attr.stackaddr_set = 0;
new_attr.stackaddr = NULL;
new_attr.stacksize = STACK_SIZE - ps;
attr = &new_attr;
}
return __pthread_create_2_1 (thread, attr, start_routine, arg);
}
symbol_version (__pthread_create_2_0, pthread_create, GLIBC_2.0);
#else
strong_alias (__pthread_create_2_1, pthread_create)
#endif
/* Simple operations on thread identifiers */
pthread_t pthread_self(void)
@ -417,6 +446,23 @@ void __pthread_kill_other_threads_np(void)
}
weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
/* Concurrency symbol level. */
static int current_level;
int __pthread_setconcurrency(int level)
{
/* We don't do anything unless we have found a useful interpretation. */
current_level = level;
return 0;
}
weak_alias (__pthread_setconcurrency, pthread_setconcurrency)
int __pthread_getconcurrency(void)
{
return current_level;
}
weak_alias (__pthread_getconcurrency, pthread_getconcurrency)
/* Debugging aid */
#ifdef DEBUG

View File

@ -119,6 +119,10 @@ typedef struct
struct sched_param schedparam;
int inheritsched;
int scope;
size_t guardsize;
int stackaddr_set;
void *stackaddr;
size_t stacksize;
} pthread_attr_t;
enum
@ -272,6 +276,49 @@ extern int pthread_attr_setscope __P ((pthread_attr_t *__attr, int __scope));
extern int pthread_attr_getscope __P ((__const pthread_attr_t *__attr,
int *__scope));
#ifdef __USE_UNIX98
/* Set the size of the guard area at the bottom of the thread. */
extern int __pthread_attr_setguardsize __P ((pthread_attr_t *__attr,
size_t __guardsize));
extern int pthread_attr_setguardsize __P ((pthread_attr_t *__attr,
size_t __guardsize));
/* Get the size of the guard area at the bottom of the thread. */
extern int __pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr,
size_t *__guardsize));
extern int pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr,
size_t *__guardsize));
/* Set the starting address of the stack of the thread to be created.
Depending on whether the stack grows up or doen the value must either
be higher or lower than all the address in the memory block. The
minimal size of the block must be PTHREAD_STACK_SIZE. */
extern int __pthread_attr_setstackaddr __P ((pthread_attr_t *__attr,
void *__stackaddr));
extern int pthread_attr_setstackaddr __P ((pthread_attr_t *__attr,
void *__stackaddr));
/* Return the previously set address for the stack. */
extern int __pthread_attr_getstackaddr __P ((__const pthread_attr_t *__attr,
void **__stackaddr));
extern int pthread_attr_getstackaddr __P ((__const pthread_attr_t *__attr,
void **__stackaddr));
/* Add information about the minimum stack size needed for the thread
to be started. This size must never be less than PTHREAD_STACK_SIZE
and must also not exceed the system limits. */
extern int __pthread_attr_setstacksize __P ((pthread_attr_t *__attr,
size_t __stacksize));
extern int pthread_attr_setstacksize __P ((pthread_attr_t *__attr,
size_t __stacksize));
/* Return the currently used minimal stack size. */
extern int __pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr,
size_t *__stacksize));
extern int pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr,
size_t *__stacksize));
#endif
/* Functions for scheduling control. */
/* Set the scheduling parameters for TARGET_THREAD according to POLICY
@ -284,6 +331,15 @@ extern int pthread_getschedparam __P ((pthread_t __target_thread,
int *__policy,
struct sched_param *__param));
#ifdef __USE_UNIX98
/* Determine level of concurrency. */
extern int __pthread_getconcurrency __P ((void));
extern int pthread_getconcurrency __P ((void));
/* Set new concurrency level to LEVEL. */
extern int __pthread_setconcurrency __P ((int __level));
extern int pthread_setconcurrency __P ((int __level));
#endif
/* Functions for mutex handling. */

View File

@ -1,5 +1,5 @@
/* Minimum guaranteed maximum values for system limits. Linux version.
Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -38,3 +38,6 @@
/* Maximum amount by which a process can descrease its asynchronous I/O
priority level. */
#define AIO_PRIO_DELTA_MAX 20
/* Minimum size for a thread. We are free to choose a reasonable value. */
#define PTHREAD_STACK_MIN 16384