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:
parent
a84623740c
commit
6f85900aff
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user