Use growable stacks for thread stacks that are the default stack size.

Cache discarded default thread stacks for use in subsequent thread creations.

Create a red zone at the end of each stack (including the initial thread
stack), with the hope of causing a segfault if a stack overflows.

To activate these modifications, add -D_PTHREAD_GSTACK to CFLAGS in
src/lib/libc_r/Makefile.  Since the modifications depend on the VM_STACK
kernel option, I'm not sure how to safely use growable stacks by default.

Testing, as well as algorithmic and stylistic comments are welcome.
This commit is contained in:
jasone 1999-07-05 00:35:19 +00:00
parent a84623740c
commit 6f85900aff
14 changed files with 462 additions and 64 deletions

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.14 1998/12/10 20:27:52 jb Exp $
# $Id: Makefile,v 1.15 1999/06/20 08:32:37 jb Exp $
#
# All library objects contain rcsid strings by default; they may be
# excluded as a space-saving measure. To produce a library that does
@ -13,7 +13,10 @@ CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE -I${.CURDIR}/uthread
# Uncomment this if you want libc_r to contain debug information for
# thread locking.
#CFLAGS+=-D_LOCK_DEBUG
CFLAGS+=-D_LOCK_DEBUG
# Uncomment this if you want libc_r to use growable stacks.
CFLAGS+= -D_PTHREAD_GSTACK
AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/uthread
PRECIOUSLIB= yes

View File

@ -31,7 +31,7 @@
*
* Private thread definitions for the uthread kernel.
*
* $Id$
* $Id: pthread_private.h,v 1.20 1999/06/20 08:28:08 jb Exp $
*/
#ifndef _PTHREAD_PRIVATE_H
@ -335,6 +335,24 @@ struct pthread_attr {
* Miscellaneous definitions.
*/
#define PTHREAD_STACK_DEFAULT 65536
#ifdef _PTHREAD_GSTACK
/* Size of red zone at the end of each stack. */
#define PTHREAD_STACK_GUARD 4096
/* Maximum size of initial thread's stack. This perhaps deserves to be larger
* than the stacks of other threads, since legacy applications are likely to run
* almost entirely on this stack. */
#define PTHREAD_STACK_INITIAL 0x100000
/* Address immediately beyond the beginning of the initial thread stack. */
#if defined(__FreeBSD__)
# if defined(__alpha__)
# define PTHREAD_STACK_TOP 0x160022000
# else
# define PTHREAD_STACK_TOP 0xbfbde000
# endif
#else
# error "Don't recognize this operating system!"
#endif
#endif
#define PTHREAD_DEFAULT_PRIORITY 64
#define PTHREAD_MAX_PRIORITY 126
#define PTHREAD_MIN_PRIORITY 0
@ -655,6 +673,13 @@ struct pthread {
int lineno; /* Source line number. */
};
#ifdef _PTHREAD_GSTACK
/* Spare thread stack. */
struct stack {
SLIST_ENTRY(stack) qe; /* Queue entry for this stack. */
};
#endif
/*
* Global variables for the uthread kernel.
*/
@ -864,6 +889,24 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
#endif
;
#ifdef _PTHREAD_GSTACK
/* Spare stack queue. Stacks of default size are cached in order to reduce
* thread creation time. Spare stacks are used in LIFO order to increase cache
* locality. */
SCLASS SLIST_HEAD(, stack) _stackq;
/* Base address of next unallocated default-size stack. Stacks are allocated
* contiguously, starting below the beginning of the main stack. When a new
* stack is created, a guard page is created just above it in order to (usually)
* detect attempts by the adjacent stack to trounce the next thread stack. */
SCLASS void * _next_stack
#ifdef GLOBAL_PTHREAD_PRIVATE
/* main stack top - main stack size - stack size - (red zone + main stack red zone) */
= (void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL - PTHREAD_STACK_DEFAULT - (2 * PTHREAD_STACK_GUARD)
#endif
;
#endif
/* Used for _PTHREADS_INVARIANTS checking. */
SCLASS int _thread_kern_new_state
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -871,7 +914,6 @@ SCLASS int _thread_kern_new_state
#endif
;
/* Undefine the storage class specifier: */
#undef SCLASS

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: uthread_create.c,v 1.13 1999/06/20 08:28:14 jb Exp $
*/
#include <errno.h>
#include <stdlib.h>
@ -37,6 +37,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -77,12 +81,64 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Check if a stack was specified in the thread attributes: */
if ((stack = pattr->stackaddr_attr) != NULL) {
}
#ifdef _PTHREAD_GSTACK
/* Allocate memory for a default-size stack: */
else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
struct stack * spare_stack;
/* Allocate or re-use a default-size stack. */
/* Use the garbage collector mutex for synchronization
* of the spare stack list.
*
* XXX This may not be ideal. */
if (pthread_mutex_lock(&_gc_mutex) != 0)
PANIC("Cannot lock gc mutex");
if (NULL != (spare_stack = SLIST_FIRST(&_stackq))) {
/* Use the spare stack. */
SLIST_REMOVE_HEAD(&_stackq, qe);
stack = sizeof(struct stack) + (void *) spare_stack - PTHREAD_STACK_DEFAULT;
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
/* Even if stack allocation fails, we don't want to try to use this location again, so unconditionally
* decrement _next_stack. Under normal operating conditions, the most likely reason for an mmap()
* error is a stack overflow of the adjacent thread stack. */
_next_stack -= (PTHREAD_STACK_DEFAULT + PTHREAD_STACK_GUARD);
/* Red zone: */
if (MAP_FAILED == mmap(_next_stack, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
ret = EAGAIN;
free(new_thread);
}
/* Stack: */
else if (MAP_FAILED == mmap(stack, PTHREAD_STACK_DEFAULT, PROT_READ | PROT_WRITE, MAP_STACK, -1, 0)) {
ret = EAGAIN;
munmap(_next_stack, PTHREAD_STACK_GUARD);
free(new_thread);
}
}
/* Unlock the garbage collector mutex. */
if (pthread_mutex_unlock(&_gc_mutex) != 0)
PANIC("Cannot unlock gc mutex");
}
/* The user wants a stack of a particular size. Lets hope they really know what they want, and simply malloc the
* stack. */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#else
/* Allocate memory for the stack: */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#endif
/* Check for errors: */
if (ret != 0) {
} else {

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: uthread_gc.c,v 1.3 1999/03/23 05:07:55 jb Exp $
* $Id: uthread_gc.c,v 1.4 1999/06/20 08:28:25 jb Exp $
*
* Garbage collector thread. Frees memory allocated for dead threads.
*
@ -38,6 +38,10 @@
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#include <pthread.h>
#include "pthread_private.h"
@ -132,11 +136,23 @@ _thread_gc(pthread_addr_t arg)
*/
if (pthread->attr.stackaddr_attr == NULL &&
pthread->stack != NULL) {
#ifdef _PTHREAD_GSTACK
if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) {
/* Default-size stack. Cache it: */
struct stack * spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT
- sizeof(struct stack));
SLIST_INSERT_HEAD(&_stackq, spare_stack, qe);
} else {
/* Non-standard stack size. free() it outside the locks: */
p_stack = pthread->stack;
}
#else
/*
* Point to the stack that must
* be freed outside the locks:
*/
p_stack = pthread->stack;
#endif
}
/*
@ -156,12 +172,24 @@ _thread_gc(pthread_addr_t arg)
*/
if (pthread->attr.stackaddr_attr == NULL &&
pthread->stack != NULL) {
#ifdef _PTHREAD_GSTACK
if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) {
/* Default-size stack. Cache it: */
struct stack * spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT
- sizeof(struct stack));
SLIST_INSERT_HEAD(&_stackq, spare_stack, qe);
} else {
/* Non-standard stack size. free() it outside the locks: */
p_stack = pthread->stack;
}
#else
/*
* Point to the stack that must
* be freed outside the locks:
*/
p_stack = pthread->stack;
#endif
/*
* NULL the stack pointer now
* that the memory has been freed:

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: uthread_init.c,v 1.11 1999/06/20 08:28:28 jb Exp $
* $Id: uthread_init.c,v 1.12 1999/06/23 15:01:21 dt Exp $
*/
/* Allocate space for global thread variables here: */
@ -45,6 +45,10 @@
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/ttycom.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -57,8 +61,8 @@ extern void __set_dynamic_handler_allocator(dynamic_handler_allocator);
static pthread_key_t except_head_key;
typedef struct {
void **__dynamic_handler_chain;
void *top_elt[2];
void **__dynamic_handler_chain;
void *top_elt[2];
} except_struct;
static void ***dynamic_allocator_handler_fn()
@ -103,26 +107,26 @@ _thread_init(void)
* Setup a new session for this process which is
* assumed to be running as root.
*/
if (setsid() == -1)
if (setsid() == -1)
PANIC("Can't set session ID");
if (revoke(_PATH_CONSOLE) != 0)
if (revoke(_PATH_CONSOLE) != 0)
PANIC("Can't revoke console");
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
PANIC("Can't open console");
if (setlogin("root") == -1)
if (setlogin("root") == -1)
PANIC("Can't set login to root");
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal");
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
PANIC("Can't dup2");
}
/* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++)
if ((_pthread_stdio_flags[i] =
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
PANIC("Cannot get stdio flags");
/*
@ -178,6 +182,15 @@ _thread_init(void)
/* Initialize the scheduling switch hook routine: */
_sched_switch_hook = NULL;
#ifdef _PTHREAD_GSTACK
/* Initialize the thread stack cache: */
SLIST_INIT(&_stackq);
/* Create the red zone for the main stack. */
if (MAP_FAILED == mmap((void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
PANIC("Cannot allocate red zone for initial thread");
}
#endif
/*
* Write a magic value to the thread structure
* to help identify valid ones:
@ -228,7 +241,7 @@ _thread_init(void)
/* Get the signal handler details: */
else if (_thread_sys_sigaction(i, NULL,
&_thread_sigact[i - 1]) != 0) {
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
@ -296,7 +309,7 @@ _thread_init(void)
(_thread_fd_table_init(1) != 0) ||
(_thread_fd_table_init(2) != 0)) {
PANIC("Cannot initialize stdio file descriptor "
"table entries");
"table entries");
}
}
}
@ -304,7 +317,7 @@ _thread_init(void)
#ifdef GCC_2_8_MADE_THREAD_AWARE
/* Create the thread-specific data for the exception linked list. */
if(pthread_key_create(&except_head_key, NULL) != 0)
PANIC("Failed to create thread specific execption head");
PANIC("Failed to create thread specific execption head");
/* Setup the gcc exception handler per thread. */
__set_dynamic_handler_allocator( dynamic_allocator_handler_fn );

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.14 1998/12/10 20:27:52 jb Exp $
# $Id: Makefile,v 1.15 1999/06/20 08:32:37 jb Exp $
#
# All library objects contain rcsid strings by default; they may be
# excluded as a space-saving measure. To produce a library that does
@ -13,7 +13,10 @@ CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE -I${.CURDIR}/uthread
# Uncomment this if you want libc_r to contain debug information for
# thread locking.
#CFLAGS+=-D_LOCK_DEBUG
CFLAGS+=-D_LOCK_DEBUG
# Uncomment this if you want libc_r to use growable stacks.
CFLAGS+= -D_PTHREAD_GSTACK
AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/uthread
PRECIOUSLIB= yes

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: uthread_create.c,v 1.13 1999/06/20 08:28:14 jb Exp $
*/
#include <errno.h>
#include <stdlib.h>
@ -37,6 +37,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -77,12 +81,64 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Check if a stack was specified in the thread attributes: */
if ((stack = pattr->stackaddr_attr) != NULL) {
}
#ifdef _PTHREAD_GSTACK
/* Allocate memory for a default-size stack: */
else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
struct stack * spare_stack;
/* Allocate or re-use a default-size stack. */
/* Use the garbage collector mutex for synchronization
* of the spare stack list.
*
* XXX This may not be ideal. */
if (pthread_mutex_lock(&_gc_mutex) != 0)
PANIC("Cannot lock gc mutex");
if (NULL != (spare_stack = SLIST_FIRST(&_stackq))) {
/* Use the spare stack. */
SLIST_REMOVE_HEAD(&_stackq, qe);
stack = sizeof(struct stack) + (void *) spare_stack - PTHREAD_STACK_DEFAULT;
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
/* Even if stack allocation fails, we don't want to try to use this location again, so unconditionally
* decrement _next_stack. Under normal operating conditions, the most likely reason for an mmap()
* error is a stack overflow of the adjacent thread stack. */
_next_stack -= (PTHREAD_STACK_DEFAULT + PTHREAD_STACK_GUARD);
/* Red zone: */
if (MAP_FAILED == mmap(_next_stack, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
ret = EAGAIN;
free(new_thread);
}
/* Stack: */
else if (MAP_FAILED == mmap(stack, PTHREAD_STACK_DEFAULT, PROT_READ | PROT_WRITE, MAP_STACK, -1, 0)) {
ret = EAGAIN;
munmap(_next_stack, PTHREAD_STACK_GUARD);
free(new_thread);
}
}
/* Unlock the garbage collector mutex. */
if (pthread_mutex_unlock(&_gc_mutex) != 0)
PANIC("Cannot unlock gc mutex");
}
/* The user wants a stack of a particular size. Lets hope they really know what they want, and simply malloc the
* stack. */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#else
/* Allocate memory for the stack: */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#endif
/* Check for errors: */
if (ret != 0) {
} else {

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: uthread_init.c,v 1.11 1999/06/20 08:28:28 jb Exp $
* $Id: uthread_init.c,v 1.12 1999/06/23 15:01:21 dt Exp $
*/
/* Allocate space for global thread variables here: */
@ -45,6 +45,10 @@
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/ttycom.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -57,8 +61,8 @@ extern void __set_dynamic_handler_allocator(dynamic_handler_allocator);
static pthread_key_t except_head_key;
typedef struct {
void **__dynamic_handler_chain;
void *top_elt[2];
void **__dynamic_handler_chain;
void *top_elt[2];
} except_struct;
static void ***dynamic_allocator_handler_fn()
@ -103,26 +107,26 @@ _thread_init(void)
* Setup a new session for this process which is
* assumed to be running as root.
*/
if (setsid() == -1)
if (setsid() == -1)
PANIC("Can't set session ID");
if (revoke(_PATH_CONSOLE) != 0)
if (revoke(_PATH_CONSOLE) != 0)
PANIC("Can't revoke console");
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
PANIC("Can't open console");
if (setlogin("root") == -1)
if (setlogin("root") == -1)
PANIC("Can't set login to root");
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal");
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
PANIC("Can't dup2");
}
/* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++)
if ((_pthread_stdio_flags[i] =
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
PANIC("Cannot get stdio flags");
/*
@ -178,6 +182,15 @@ _thread_init(void)
/* Initialize the scheduling switch hook routine: */
_sched_switch_hook = NULL;
#ifdef _PTHREAD_GSTACK
/* Initialize the thread stack cache: */
SLIST_INIT(&_stackq);
/* Create the red zone for the main stack. */
if (MAP_FAILED == mmap((void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
PANIC("Cannot allocate red zone for initial thread");
}
#endif
/*
* Write a magic value to the thread structure
* to help identify valid ones:
@ -228,7 +241,7 @@ _thread_init(void)
/* Get the signal handler details: */
else if (_thread_sys_sigaction(i, NULL,
&_thread_sigact[i - 1]) != 0) {
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
@ -296,7 +309,7 @@ _thread_init(void)
(_thread_fd_table_init(1) != 0) ||
(_thread_fd_table_init(2) != 0)) {
PANIC("Cannot initialize stdio file descriptor "
"table entries");
"table entries");
}
}
}
@ -304,7 +317,7 @@ _thread_init(void)
#ifdef GCC_2_8_MADE_THREAD_AWARE
/* Create the thread-specific data for the exception linked list. */
if(pthread_key_create(&except_head_key, NULL) != 0)
PANIC("Failed to create thread specific execption head");
PANIC("Failed to create thread specific execption head");
/* Setup the gcc exception handler per thread. */
__set_dynamic_handler_allocator( dynamic_allocator_handler_fn );

View File

@ -31,7 +31,7 @@
*
* Private thread definitions for the uthread kernel.
*
* $Id$
* $Id: pthread_private.h,v 1.20 1999/06/20 08:28:08 jb Exp $
*/
#ifndef _PTHREAD_PRIVATE_H
@ -335,6 +335,24 @@ struct pthread_attr {
* Miscellaneous definitions.
*/
#define PTHREAD_STACK_DEFAULT 65536
#ifdef _PTHREAD_GSTACK
/* Size of red zone at the end of each stack. */
#define PTHREAD_STACK_GUARD 4096
/* Maximum size of initial thread's stack. This perhaps deserves to be larger
* than the stacks of other threads, since legacy applications are likely to run
* almost entirely on this stack. */
#define PTHREAD_STACK_INITIAL 0x100000
/* Address immediately beyond the beginning of the initial thread stack. */
#if defined(__FreeBSD__)
# if defined(__alpha__)
# define PTHREAD_STACK_TOP 0x160022000
# else
# define PTHREAD_STACK_TOP 0xbfbde000
# endif
#else
# error "Don't recognize this operating system!"
#endif
#endif
#define PTHREAD_DEFAULT_PRIORITY 64
#define PTHREAD_MAX_PRIORITY 126
#define PTHREAD_MIN_PRIORITY 0
@ -655,6 +673,13 @@ struct pthread {
int lineno; /* Source line number. */
};
#ifdef _PTHREAD_GSTACK
/* Spare thread stack. */
struct stack {
SLIST_ENTRY(stack) qe; /* Queue entry for this stack. */
};
#endif
/*
* Global variables for the uthread kernel.
*/
@ -864,6 +889,24 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
#endif
;
#ifdef _PTHREAD_GSTACK
/* Spare stack queue. Stacks of default size are cached in order to reduce
* thread creation time. Spare stacks are used in LIFO order to increase cache
* locality. */
SCLASS SLIST_HEAD(, stack) _stackq;
/* Base address of next unallocated default-size stack. Stacks are allocated
* contiguously, starting below the beginning of the main stack. When a new
* stack is created, a guard page is created just above it in order to (usually)
* detect attempts by the adjacent stack to trounce the next thread stack. */
SCLASS void * _next_stack
#ifdef GLOBAL_PTHREAD_PRIVATE
/* main stack top - main stack size - stack size - (red zone + main stack red zone) */
= (void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL - PTHREAD_STACK_DEFAULT - (2 * PTHREAD_STACK_GUARD)
#endif
;
#endif
/* Used for _PTHREADS_INVARIANTS checking. */
SCLASS int _thread_kern_new_state
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -871,7 +914,6 @@ SCLASS int _thread_kern_new_state
#endif
;
/* Undefine the storage class specifier: */
#undef SCLASS

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.14 1998/12/10 20:27:52 jb Exp $
# $Id: Makefile,v 1.15 1999/06/20 08:32:37 jb Exp $
#
# All library objects contain rcsid strings by default; they may be
# excluded as a space-saving measure. To produce a library that does
@ -13,7 +13,10 @@ CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE -I${.CURDIR}/uthread
# Uncomment this if you want libc_r to contain debug information for
# thread locking.
#CFLAGS+=-D_LOCK_DEBUG
CFLAGS+=-D_LOCK_DEBUG
# Uncomment this if you want libc_r to use growable stacks.
CFLAGS+= -D_PTHREAD_GSTACK
AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/uthread
PRECIOUSLIB= yes

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: uthread_create.c,v 1.13 1999/06/20 08:28:14 jb Exp $
*/
#include <errno.h>
#include <stdlib.h>
@ -37,6 +37,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -77,12 +81,64 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Check if a stack was specified in the thread attributes: */
if ((stack = pattr->stackaddr_attr) != NULL) {
}
#ifdef _PTHREAD_GSTACK
/* Allocate memory for a default-size stack: */
else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
struct stack * spare_stack;
/* Allocate or re-use a default-size stack. */
/* Use the garbage collector mutex for synchronization
* of the spare stack list.
*
* XXX This may not be ideal. */
if (pthread_mutex_lock(&_gc_mutex) != 0)
PANIC("Cannot lock gc mutex");
if (NULL != (spare_stack = SLIST_FIRST(&_stackq))) {
/* Use the spare stack. */
SLIST_REMOVE_HEAD(&_stackq, qe);
stack = sizeof(struct stack) + (void *) spare_stack - PTHREAD_STACK_DEFAULT;
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
/* Even if stack allocation fails, we don't want to try to use this location again, so unconditionally
* decrement _next_stack. Under normal operating conditions, the most likely reason for an mmap()
* error is a stack overflow of the adjacent thread stack. */
_next_stack -= (PTHREAD_STACK_DEFAULT + PTHREAD_STACK_GUARD);
/* Red zone: */
if (MAP_FAILED == mmap(_next_stack, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
ret = EAGAIN;
free(new_thread);
}
/* Stack: */
else if (MAP_FAILED == mmap(stack, PTHREAD_STACK_DEFAULT, PROT_READ | PROT_WRITE, MAP_STACK, -1, 0)) {
ret = EAGAIN;
munmap(_next_stack, PTHREAD_STACK_GUARD);
free(new_thread);
}
}
/* Unlock the garbage collector mutex. */
if (pthread_mutex_unlock(&_gc_mutex) != 0)
PANIC("Cannot unlock gc mutex");
}
/* The user wants a stack of a particular size. Lets hope they really know what they want, and simply malloc the
* stack. */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#else
/* Allocate memory for the stack: */
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
}
#endif
/* Check for errors: */
if (ret != 0) {
} else {

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: uthread_gc.c,v 1.3 1999/03/23 05:07:55 jb Exp $
* $Id: uthread_gc.c,v 1.4 1999/06/20 08:28:25 jb Exp $
*
* Garbage collector thread. Frees memory allocated for dead threads.
*
@ -38,6 +38,10 @@
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#include <pthread.h>
#include "pthread_private.h"
@ -132,11 +136,23 @@ _thread_gc(pthread_addr_t arg)
*/
if (pthread->attr.stackaddr_attr == NULL &&
pthread->stack != NULL) {
#ifdef _PTHREAD_GSTACK
if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) {
/* Default-size stack. Cache it: */
struct stack * spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT
- sizeof(struct stack));
SLIST_INSERT_HEAD(&_stackq, spare_stack, qe);
} else {
/* Non-standard stack size. free() it outside the locks: */
p_stack = pthread->stack;
}
#else
/*
* Point to the stack that must
* be freed outside the locks:
*/
p_stack = pthread->stack;
#endif
}
/*
@ -156,12 +172,24 @@ _thread_gc(pthread_addr_t arg)
*/
if (pthread->attr.stackaddr_attr == NULL &&
pthread->stack != NULL) {
#ifdef _PTHREAD_GSTACK
if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) {
/* Default-size stack. Cache it: */
struct stack * spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT
- sizeof(struct stack));
SLIST_INSERT_HEAD(&_stackq, spare_stack, qe);
} else {
/* Non-standard stack size. free() it outside the locks: */
p_stack = pthread->stack;
}
#else
/*
* Point to the stack that must
* be freed outside the locks:
*/
p_stack = pthread->stack;
#endif
/*
* NULL the stack pointer now
* that the memory has been freed:

View File

@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: uthread_init.c,v 1.11 1999/06/20 08:28:28 jb Exp $
* $Id: uthread_init.c,v 1.12 1999/06/23 15:01:21 dt Exp $
*/
/* Allocate space for global thread variables here: */
@ -45,6 +45,10 @@
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/ttycom.h>
#ifdef _PTHREAD_GSTACK
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef _THREAD_SAFE
#include <machine/reg.h>
#include <pthread.h>
@ -57,8 +61,8 @@ extern void __set_dynamic_handler_allocator(dynamic_handler_allocator);
static pthread_key_t except_head_key;
typedef struct {
void **__dynamic_handler_chain;
void *top_elt[2];
void **__dynamic_handler_chain;
void *top_elt[2];
} except_struct;
static void ***dynamic_allocator_handler_fn()
@ -103,26 +107,26 @@ _thread_init(void)
* Setup a new session for this process which is
* assumed to be running as root.
*/
if (setsid() == -1)
if (setsid() == -1)
PANIC("Can't set session ID");
if (revoke(_PATH_CONSOLE) != 0)
if (revoke(_PATH_CONSOLE) != 0)
PANIC("Can't revoke console");
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
PANIC("Can't open console");
if (setlogin("root") == -1)
if (setlogin("root") == -1)
PANIC("Can't set login to root");
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal");
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
if (_thread_sys_dup2(fd,0) == -1 ||
_thread_sys_dup2(fd,1) == -1 ||
_thread_sys_dup2(fd,2) == -1)
PANIC("Can't dup2");
}
/* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++)
if ((_pthread_stdio_flags[i] =
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
_thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
PANIC("Cannot get stdio flags");
/*
@ -178,6 +182,15 @@ _thread_init(void)
/* Initialize the scheduling switch hook routine: */
_sched_switch_hook = NULL;
#ifdef _PTHREAD_GSTACK
/* Initialize the thread stack cache: */
SLIST_INIT(&_stackq);
/* Create the red zone for the main stack. */
if (MAP_FAILED == mmap((void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL, PTHREAD_STACK_GUARD, 0, MAP_ANON, -1, 0)) {
PANIC("Cannot allocate red zone for initial thread");
}
#endif
/*
* Write a magic value to the thread structure
* to help identify valid ones:
@ -228,7 +241,7 @@ _thread_init(void)
/* Get the signal handler details: */
else if (_thread_sys_sigaction(i, NULL,
&_thread_sigact[i - 1]) != 0) {
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
* initialisation fails:
@ -296,7 +309,7 @@ _thread_init(void)
(_thread_fd_table_init(1) != 0) ||
(_thread_fd_table_init(2) != 0)) {
PANIC("Cannot initialize stdio file descriptor "
"table entries");
"table entries");
}
}
}
@ -304,7 +317,7 @@ _thread_init(void)
#ifdef GCC_2_8_MADE_THREAD_AWARE
/* Create the thread-specific data for the exception linked list. */
if(pthread_key_create(&except_head_key, NULL) != 0)
PANIC("Failed to create thread specific execption head");
PANIC("Failed to create thread specific execption head");
/* Setup the gcc exception handler per thread. */
__set_dynamic_handler_allocator( dynamic_allocator_handler_fn );

View File

@ -31,7 +31,7 @@
*
* Private thread definitions for the uthread kernel.
*
* $Id$
* $Id: pthread_private.h,v 1.20 1999/06/20 08:28:08 jb Exp $
*/
#ifndef _PTHREAD_PRIVATE_H
@ -335,6 +335,24 @@ struct pthread_attr {
* Miscellaneous definitions.
*/
#define PTHREAD_STACK_DEFAULT 65536
#ifdef _PTHREAD_GSTACK
/* Size of red zone at the end of each stack. */
#define PTHREAD_STACK_GUARD 4096
/* Maximum size of initial thread's stack. This perhaps deserves to be larger
* than the stacks of other threads, since legacy applications are likely to run
* almost entirely on this stack. */
#define PTHREAD_STACK_INITIAL 0x100000
/* Address immediately beyond the beginning of the initial thread stack. */
#if defined(__FreeBSD__)
# if defined(__alpha__)
# define PTHREAD_STACK_TOP 0x160022000
# else
# define PTHREAD_STACK_TOP 0xbfbde000
# endif
#else
# error "Don't recognize this operating system!"
#endif
#endif
#define PTHREAD_DEFAULT_PRIORITY 64
#define PTHREAD_MAX_PRIORITY 126
#define PTHREAD_MIN_PRIORITY 0
@ -655,6 +673,13 @@ struct pthread {
int lineno; /* Source line number. */
};
#ifdef _PTHREAD_GSTACK
/* Spare thread stack. */
struct stack {
SLIST_ENTRY(stack) qe; /* Queue entry for this stack. */
};
#endif
/*
* Global variables for the uthread kernel.
*/
@ -864,6 +889,24 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
#endif
;
#ifdef _PTHREAD_GSTACK
/* Spare stack queue. Stacks of default size are cached in order to reduce
* thread creation time. Spare stacks are used in LIFO order to increase cache
* locality. */
SCLASS SLIST_HEAD(, stack) _stackq;
/* Base address of next unallocated default-size stack. Stacks are allocated
* contiguously, starting below the beginning of the main stack. When a new
* stack is created, a guard page is created just above it in order to (usually)
* detect attempts by the adjacent stack to trounce the next thread stack. */
SCLASS void * _next_stack
#ifdef GLOBAL_PTHREAD_PRIVATE
/* main stack top - main stack size - stack size - (red zone + main stack red zone) */
= (void *) PTHREAD_STACK_TOP - PTHREAD_STACK_INITIAL - PTHREAD_STACK_DEFAULT - (2 * PTHREAD_STACK_GUARD)
#endif
;
#endif
/* Used for _PTHREADS_INVARIANTS checking. */
SCLASS int _thread_kern_new_state
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -871,7 +914,6 @@ SCLASS int _thread_kern_new_state
#endif
;
/* Undefine the storage class specifier: */
#undef SCLASS