version 1.2, 2000/12/01 09:26:13 |
version 1.5, 2002/07/24 08:00:12 |
|
|
*/ |
*/ |
/* Boehm, September 14, 1994 4:44 pm PDT */ |
/* Boehm, September 14, 1994 4:44 pm PDT */ |
|
|
# if defined(SOLARIS_THREADS) |
# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) |
|
|
# include "gc_priv.h" |
# include "private/gc_priv.h" |
# include "solaris_threads.h" |
# include "private/solaris_threads.h" |
# include <thread.h> |
# include <thread.h> |
# include <synch.h> |
# include <synch.h> |
# include <signal.h> |
# include <signal.h> |
|
|
# include <unistd.h> |
# include <unistd.h> |
# include <errno.h> |
# include <errno.h> |
|
|
|
#ifdef HANDLE_FORK |
|
--> Not yet supported. Try porting the code from linux_threads.c. |
|
#endif |
|
|
/* |
/* |
* This is the default size of the LWP arrays. If there are more LWPs |
* This is the default size of the LWP arrays. If there are more LWPs |
* than this when a stop-the-world GC happens, set_max_lwps will be |
* than this when a stop-the-world GC happens, set_max_lwps will be |
Line 361 static void restart_all_lwps() |
|
Line 365 static void restart_all_lwps() |
|
sizeof (prgregset_t)) != 0) { |
sizeof (prgregset_t)) != 0) { |
int j; |
int j; |
|
|
for(j = 0; j < NGREG; j++) |
for(j = 0; j < NPRGREG; j++) |
{ |
{ |
GC_printf3("%i: %x -> %x\n", j, |
GC_printf3("%i: %x -> %x\n", j, |
GC_lwp_registers[i][j], |
GC_lwp_registers[i][j], |
Line 414 GC_bool GC_thr_initialized = FALSE; |
|
Line 418 GC_bool GC_thr_initialized = FALSE; |
|
|
|
size_t GC_min_stack_sz; |
size_t GC_min_stack_sz; |
|
|
size_t GC_page_sz; |
|
|
|
/* |
/* |
* stack_head is stored at the top of free stacks |
* stack_head is stored at the top of free stacks |
Line 456 ptr_t GC_stack_alloc(size_t * stack_size) |
|
Line 459 ptr_t GC_stack_alloc(size_t * stack_size) |
|
GC_stack_free_lists[index] = GC_stack_free_lists[index]->next; |
GC_stack_free_lists[index] = GC_stack_free_lists[index]->next; |
} else { |
} else { |
#ifdef MMAP_STACKS |
#ifdef MMAP_STACKS |
base = (ptr_t)mmap(0, search_sz + GC_page_sz, |
base = (ptr_t)mmap(0, search_sz + GC_page_size, |
PROT_READ|PROT_WRITE, MAP_PRIVATE |MAP_NORESERVE, |
PROT_READ|PROT_WRITE, MAP_PRIVATE |MAP_NORESERVE, |
GC_zfd, 0); |
GC_zfd, 0); |
if (base == (ptr_t)-1) |
if (base == (ptr_t)-1) |
Line 465 ptr_t GC_stack_alloc(size_t * stack_size) |
|
Line 468 ptr_t GC_stack_alloc(size_t * stack_size) |
|
return NULL; |
return NULL; |
} |
} |
|
|
mprotect(base, GC_page_sz, PROT_NONE); |
mprotect(base, GC_page_size, PROT_NONE); |
/* Should this use divHBLKSZ(search_sz + GC_page_sz) ? -- cf */ |
/* Should this use divHBLKSZ(search_sz + GC_page_size) ? -- cf */ |
GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz)); |
GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz)); |
base += GC_page_sz; |
base += GC_page_size; |
|
|
#else |
#else |
base = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz); |
base = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size); |
if (base == NULL) |
if (base == NULL) |
{ |
{ |
*stack_size = 0; |
*stack_size = 0; |
return NULL; |
return NULL; |
} |
} |
|
|
base = (ptr_t)(((word)base + GC_page_sz) & ~(GC_page_sz - 1)); |
base = (ptr_t)(((word)base + GC_page_size) & ~(GC_page_size - 1)); |
/* Protect hottest page to detect overflow. */ |
/* Protect hottest page to detect overflow. */ |
# ifdef SOLARIS23_MPROTECT_BUG_FIXED |
# ifdef SOLARIS23_MPROTECT_BUG_FIXED |
mprotect(base, GC_page_sz, PROT_NONE); |
mprotect(base, GC_page_size, PROT_NONE); |
# endif |
# endif |
GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz)); |
GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz)); |
|
|
base += GC_page_sz; |
base += GC_page_size; |
#endif |
#endif |
} |
} |
*stack_size = search_sz; |
*stack_size = search_sz; |
Line 558 void GC_old_stacks_are_fresh() |
|
Line 561 void GC_old_stacks_are_fresh() |
|
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */ |
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */ |
volatile GC_thread GC_threads[THREAD_TABLE_SZ]; |
volatile GC_thread GC_threads[THREAD_TABLE_SZ]; |
|
|
|
void GC_push_thread_structures GC_PROTO((void)) |
|
{ |
|
GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads)); |
|
} |
|
|
/* Add a thread to GC_threads. We assume it wasn't already there. */ |
/* Add a thread to GC_threads. We assume it wasn't already there. */ |
/* Caller holds allocation lock. */ |
/* Caller holds allocation lock. */ |
GC_thread GC_new_thread(thread_t id) |
GC_thread GC_new_thread(thread_t id) |
Line 573 GC_thread GC_new_thread(thread_t id) |
|
Line 581 GC_thread GC_new_thread(thread_t id) |
|
/* Dont acquire allocation lock, since we may already hold it. */ |
/* Dont acquire allocation lock, since we may already hold it. */ |
} else { |
} else { |
result = (struct GC_Thread_Rep *) |
result = (struct GC_Thread_Rep *) |
GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL); |
GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL); |
} |
} |
if (result == 0) return(0); |
if (result == 0) return(0); |
result -> id = id; |
result -> id = id; |
Line 616 GC_thread GC_lookup_thread(thread_t id) |
|
Line 624 GC_thread GC_lookup_thread(thread_t id) |
|
return(p); |
return(p); |
} |
} |
|
|
|
/* Solaris 2/Intel uses an initial stack size limit slightly bigger than the |
|
SPARC default of 8 MB. Account for this to warn only if the user has |
|
raised the limit beyond the default. |
|
|
|
This is identical to DFLSSIZ defined in <sys/vm_machparam.h>. This file |
|
is installed in /usr/platform/`uname -m`/include, which is not in the |
|
default include directory list, so copy the definition here. */ |
|
#ifdef I386 |
|
# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024 + ((USRSTACK) & 0x3FFFFF)) |
|
#else |
# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024) |
# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024) |
|
#endif |
|
|
word GC_get_orig_stack_size() { |
word GC_get_orig_stack_size() { |
struct rlimit rl; |
struct rlimit rl; |
Line 627 word GC_get_orig_stack_size() { |
|
Line 646 word GC_get_orig_stack_size() { |
|
result = (word)rl.rlim_cur & ~(HBLKSIZE-1); |
result = (word)rl.rlim_cur & ~(HBLKSIZE-1); |
if (result > MAX_ORIG_STACK_SIZE) { |
if (result > MAX_ORIG_STACK_SIZE) { |
if (!warned) { |
if (!warned) { |
WARN("Large stack limit(%ld): only scanning 8 MB", result); |
WARN("Large stack limit(%ld): only scanning 8 MB\n", result); |
warned = 1; |
warned = 1; |
} |
} |
result = MAX_ORIG_STACK_SIZE; |
result = MAX_ORIG_STACK_SIZE; |
Line 649 void GC_my_stack_limits() |
|
Line 668 void GC_my_stack_limits() |
|
/* original thread */ |
/* original thread */ |
/* Empirically, what should be the stack page with lowest */ |
/* Empirically, what should be the stack page with lowest */ |
/* address is actually inaccessible. */ |
/* address is actually inaccessible. */ |
stack_size = GC_get_orig_stack_size() - GC_page_sz; |
stack_size = GC_get_orig_stack_size() - GC_page_size; |
stack = GC_stackbottom - stack_size + GC_page_sz; |
stack = GC_stackbottom - stack_size + GC_page_size; |
} else { |
} else { |
stack = me -> stack; |
stack = me -> stack; |
} |
} |
Line 673 void GC_push_all_stacks() |
|
Line 692 void GC_push_all_stacks() |
|
|
|
# define PUSH(bottom,top) \ |
# define PUSH(bottom,top) \ |
if (GC_dirty_maintained) { \ |
if (GC_dirty_maintained) { \ |
GC_push_dirty((bottom), (top), GC_page_was_ever_dirty, \ |
GC_push_selected((bottom), (top), GC_page_was_ever_dirty, \ |
GC_push_all_stack); \ |
GC_push_all_stack); \ |
} else { \ |
} else { \ |
GC_push_all_stack((bottom), (top)); \ |
GC_push_all_stack((bottom), (top)); \ |
Line 688 void GC_push_all_stacks() |
|
Line 707 void GC_push_all_stacks() |
|
top = p -> stack + p -> stack_size; |
top = p -> stack + p -> stack_size; |
} else { |
} else { |
/* The original stack. */ |
/* The original stack. */ |
bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_sz; |
bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_size; |
top = GC_stackbottom; |
top = GC_stackbottom; |
} |
} |
if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp; |
if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp; |
Line 703 int GC_is_thread_stack(ptr_t addr) |
|
Line 722 int GC_is_thread_stack(ptr_t addr) |
|
register int i; |
register int i; |
register GC_thread p; |
register GC_thread p; |
register ptr_t bottom, top; |
register ptr_t bottom, top; |
struct rlimit rl; |
|
|
|
for (i = 0; i < THREAD_TABLE_SZ; i++) { |
for (i = 0; i < THREAD_TABLE_SZ; i++) { |
for (p = GC_threads[i]; p != 0; p = p -> next) { |
for (p = GC_threads[i]; p != 0; p = p -> next) { |
Line 714 int GC_is_thread_stack(ptr_t addr) |
|
Line 732 int GC_is_thread_stack(ptr_t addr) |
|
} |
} |
} |
} |
} |
} |
|
return 0; |
} |
} |
|
|
/* The only thread that ever really performs a thr_join. */ |
/* The only thread that ever really performs a thr_join. */ |
Line 773 void GC_thr_init(void) |
|
Line 792 void GC_thr_init(void) |
|
GC_thr_initialized = TRUE; |
GC_thr_initialized = TRUE; |
GC_min_stack_sz = ((thr_min_stack() + 32*1024 + HBLKSIZE-1) |
GC_min_stack_sz = ((thr_min_stack() + 32*1024 + HBLKSIZE-1) |
& ~(HBLKSIZE - 1)); |
& ~(HBLKSIZE - 1)); |
GC_page_sz = sysconf(_SC_PAGESIZE); |
|
#ifdef MMAP_STACKS |
#ifdef MMAP_STACKS |
GC_zfd = open("/dev/zero", O_RDONLY); |
GC_zfd = open("/dev/zero", O_RDONLY); |
if (GC_zfd == -1) |
if (GC_zfd == -1) |
Line 807 int GC_thr_suspend(thread_t target_thread) |
|
Line 825 int GC_thr_suspend(thread_t target_thread) |
|
if (result == 0) { |
if (result == 0) { |
t = GC_lookup_thread(target_thread); |
t = GC_lookup_thread(target_thread); |
if (t == 0) ABORT("thread unknown to GC"); |
if (t == 0) ABORT("thread unknown to GC"); |
t -> flags |= SUSPENDED; |
t -> flags |= SUSPNDED; |
} |
} |
UNLOCK(); |
UNLOCK(); |
return(result); |
return(result); |
Line 823 int GC_thr_continue(thread_t target_thread) |
|
Line 841 int GC_thr_continue(thread_t target_thread) |
|
if (result == 0) { |
if (result == 0) { |
t = GC_lookup_thread(target_thread); |
t = GC_lookup_thread(target_thread); |
if (t == 0) ABORT("thread unknown to GC"); |
if (t == 0) ABORT("thread unknown to GC"); |
t -> flags &= ~SUSPENDED; |
t -> flags &= ~SUSPNDED; |
} |
} |
UNLOCK(); |
UNLOCK(); |
return(result); |
return(result); |
Line 895 GC_thr_create(void *stack_base, size_t stack_size, |
|
Line 913 GC_thr_create(void *stack_base, size_t stack_size, |
|
void * stack = stack_base; |
void * stack = stack_base; |
|
|
LOCK(); |
LOCK(); |
if (!GC_thr_initialized) |
if (!GC_is_initialized) GC_init_inner(); |
{ |
|
GC_thr_init(); |
|
} |
|
GC_multithreaded++; |
GC_multithreaded++; |
if (stack == 0) { |
if (stack == 0) { |
if (stack_size == 0) stack_size = 1024*1024; |
if (stack_size == 0) stack_size = 1024*1024; |
Line 912 GC_thr_create(void *stack_base, size_t stack_size, |
|
Line 927 GC_thr_create(void *stack_base, size_t stack_size, |
|
my_flags |= CLIENT_OWNS_STACK; |
my_flags |= CLIENT_OWNS_STACK; |
} |
} |
if (flags & THR_DETACHED) my_flags |= DETACHED; |
if (flags & THR_DETACHED) my_flags |= DETACHED; |
if (flags & THR_SUSPENDED) my_flags |= SUSPENDED; |
if (flags & THR_SUSPENDED) my_flags |= SUSPNDED; |
result = thr_create(stack, stack_size, start_routine, |
result = thr_create(stack, stack_size, start_routine, |
arg, flags & ~THR_DETACHED, &my_new_thread); |
arg, flags & ~THR_DETACHED, &my_new_thread); |
if (result == 0) { |
if (result == 0) { |
Line 933 GC_thr_create(void *stack_base, size_t stack_size, |
|
Line 948 GC_thr_create(void *stack_base, size_t stack_size, |
|
return(result); |
return(result); |
} |
} |
|
|
# else /* SOLARIS_THREADS */ |
# else /* !GC_SOLARIS_THREADS */ |
|
|
#ifndef LINT |
#ifndef LINT |
int GC_no_sunOS_threads; |
int GC_no_sunOS_threads; |