fix some O(N) problems for N threads

Repairs include GC setup, thread finalization, and place
synchronization.
This commit is contained in:
Matthew Flatt 2012-08-10 11:49:47 -06:00
parent b5f0c97762
commit c89fa0cda7
7 changed files with 123 additions and 104 deletions

View File

@ -1046,6 +1046,8 @@ typedef struct Scheme_Thread {
Scheme_Object *dead_box; /* contains non-zero when the thread is dead */ Scheme_Object *dead_box; /* contains non-zero when the thread is dead */
Scheme_Object *running_box; /* contains pointer to thread when it's running */ Scheme_Object *running_box; /* contains pointer to thread when it's running */
struct Scheme_Thread *gc_prep_chain;
struct Scheme_Thread *nester, *nestee; struct Scheme_Thread *nester, *nestee;
struct future_t *current_ft; struct future_t *current_ft;

View File

@ -230,6 +230,7 @@ typedef struct Thread_Local_Variables {
struct Scheme_Thread *scheme_current_thread_; struct Scheme_Thread *scheme_current_thread_;
struct Scheme_Thread *scheme_main_thread_; struct Scheme_Thread *scheme_main_thread_;
struct Scheme_Thread *scheme_first_thread_; struct Scheme_Thread *scheme_first_thread_;
struct Scheme_Thread *gc_prep_thread_chain_;
struct Scheme_Thread_Set *scheme_thread_set_top_; struct Scheme_Thread_Set *scheme_thread_set_top_;
struct Scheme_Current_LWC *scheme_current_lwc_; struct Scheme_Current_LWC *scheme_current_lwc_;
int num_running_threads_; int num_running_threads_;
@ -333,6 +334,7 @@ typedef struct Thread_Local_Variables {
int place_evts_array_size_; int place_evts_array_size_;
struct Evt **place_evts_; struct Evt **place_evts_;
struct Scheme_Place_Object *place_object_; struct Scheme_Place_Object *place_object_;
struct Scheme_Place *all_child_places_;
struct Scheme_Object **reusable_ifs_stack_; struct Scheme_Object **reusable_ifs_stack_;
struct Scheme_Object *empty_self_shift_cache_; struct Scheme_Object *empty_self_shift_cache_;
struct Scheme_Bucket_Table *scheme_module_code_cache_; struct Scheme_Bucket_Table *scheme_module_code_cache_;
@ -575,6 +577,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#define scheme_current_thread XOA (scheme_get_thread_local_variables()->scheme_current_thread_) #define scheme_current_thread XOA (scheme_get_thread_local_variables()->scheme_current_thread_)
#define scheme_main_thread XOA (scheme_get_thread_local_variables()->scheme_main_thread_) #define scheme_main_thread XOA (scheme_get_thread_local_variables()->scheme_main_thread_)
#define scheme_first_thread XOA (scheme_get_thread_local_variables()->scheme_first_thread_) #define scheme_first_thread XOA (scheme_get_thread_local_variables()->scheme_first_thread_)
#define gc_prep_thread_chain XOA (scheme_get_thread_local_variables()->gc_prep_thread_chain_)
#define scheme_thread_set_top XOA (scheme_get_thread_local_variables()->scheme_thread_set_top_) #define scheme_thread_set_top XOA (scheme_get_thread_local_variables()->scheme_thread_set_top_)
#define scheme_current_lwc XOA (scheme_get_thread_local_variables()->scheme_current_lwc_) #define scheme_current_lwc XOA (scheme_get_thread_local_variables()->scheme_current_lwc_)
#define num_running_threads XOA (scheme_get_thread_local_variables()->num_running_threads_) #define num_running_threads XOA (scheme_get_thread_local_variables()->num_running_threads_)
@ -678,6 +681,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL;
#define place_evts_array_size XOA (scheme_get_thread_local_variables()->place_evts_array_size_) #define place_evts_array_size XOA (scheme_get_thread_local_variables()->place_evts_array_size_)
#define place_evts XOA (scheme_get_thread_local_variables()->place_evts_) #define place_evts XOA (scheme_get_thread_local_variables()->place_evts_)
#define place_object XOA (scheme_get_thread_local_variables()->place_object_) #define place_object XOA (scheme_get_thread_local_variables()->place_object_)
#define all_child_places XOA (scheme_get_thread_local_variables()->all_child_places_)
#define reusable_ifs_stack XOA (scheme_get_thread_local_variables()->reusable_ifs_stack_) #define reusable_ifs_stack XOA (scheme_get_thread_local_variables()->reusable_ifs_stack_)
#define empty_self_shift_cache XOA (scheme_get_thread_local_variables()->empty_self_shift_cache_) #define empty_self_shift_cache XOA (scheme_get_thread_local_variables()->empty_self_shift_cache_)
#define scheme_module_code_cache XOA (scheme_get_thread_local_variables()->scheme_module_code_cache_) #define scheme_module_code_cache XOA (scheme_get_thread_local_variables()->scheme_module_code_cache_)

View File

@ -57,6 +57,8 @@ static int place_val_MARK(void *p, struct NewGC *gc) {
gcMARK2(pr->mref, gc); gcMARK2(pr->mref, gc);
gcMARK2(pr->pumper_threads, gc); gcMARK2(pr->pumper_threads, gc);
gcMARK2(pr->place_obj, gc); gcMARK2(pr->place_obj, gc);
gcMARK2(pr->prev, gc);
gcMARK2(pr->next, gc);
return return
gcBYTES_TO_WORDS(sizeof(Scheme_Place)); gcBYTES_TO_WORDS(sizeof(Scheme_Place));
@ -68,6 +70,8 @@ static int place_val_FIXUP(void *p, struct NewGC *gc) {
gcFIXUP2(pr->mref, gc); gcFIXUP2(pr->mref, gc);
gcFIXUP2(pr->pumper_threads, gc); gcFIXUP2(pr->pumper_threads, gc);
gcFIXUP2(pr->place_obj, gc); gcFIXUP2(pr->place_obj, gc);
gcFIXUP2(pr->prev, gc);
gcFIXUP2(pr->next, gc);
return return
gcBYTES_TO_WORDS(sizeof(Scheme_Place)); gcBYTES_TO_WORDS(sizeof(Scheme_Place));

View File

@ -1497,6 +1497,8 @@ place_val {
gcMARK2(pr->mref, gc); gcMARK2(pr->mref, gc);
gcMARK2(pr->pumper_threads, gc); gcMARK2(pr->pumper_threads, gc);
gcMARK2(pr->place_obj, gc); gcMARK2(pr->place_obj, gc);
gcMARK2(pr->prev, gc);
gcMARK2(pr->next, gc);
size: size:
gcBYTES_TO_WORDS(sizeof(Scheme_Place)); gcBYTES_TO_WORDS(sizeof(Scheme_Place));

View File

@ -45,6 +45,7 @@ static mzrt_mutex *id_counter_mutex;
SHARED_OK mz_proc_thread *scheme_master_proc_thread; SHARED_OK mz_proc_thread *scheme_master_proc_thread;
THREAD_LOCAL_DECL(static struct Scheme_Place_Object *place_object); THREAD_LOCAL_DECL(static struct Scheme_Place_Object *place_object);
THREAD_LOCAL_DECL(static Scheme_Place *all_child_places);
THREAD_LOCAL_DECL(static uintptr_t force_gc_for_place_accounting); THREAD_LOCAL_DECL(static uintptr_t force_gc_for_place_accounting);
static Scheme_Object *scheme_place(int argc, Scheme_Object *args[]); static Scheme_Object *scheme_place(int argc, Scheme_Object *args[]);
static Scheme_Object *place_pumper_threads(int argc, Scheme_Object *args[]); static Scheme_Object *place_pumper_threads(int argc, Scheme_Object *args[]);
@ -144,6 +145,8 @@ void scheme_init_place(Scheme_Env *env)
PLACE_PRIM_W_ARITY("place-dead-evt", make_place_dead, 1, 1, plenv); PLACE_PRIM_W_ARITY("place-dead-evt", make_place_dead, 1, 1, plenv);
scheme_finish_primitive_module(plenv); scheme_finish_primitive_module(plenv);
REGISTER_SO(all_child_places);
} }
static Scheme_Object* scheme_place_enabled(int argc, Scheme_Object *args[]) { static Scheme_Object* scheme_place_enabled(int argc, Scheme_Object *args[]) {
@ -458,6 +461,11 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
place_data->ready = NULL; place_data->ready = NULL;
place_data->place_obj = NULL; place_data->place_obj = NULL;
place->next = all_child_places;
if (place->next)
place->next->prev = place;
all_child_places = place;
{ {
Scheme_Custodian_Reference *mref; Scheme_Custodian_Reference *mref;
mref = scheme_add_managed(NULL, mref = scheme_add_managed(NULL,
@ -528,6 +536,14 @@ static void do_place_kill(Scheme_Place *place)
} }
scheme_remove_managed(place->mref, (Scheme_Object *)place); scheme_remove_managed(place->mref, (Scheme_Object *)place);
if (place->next)
place->next->prev = place->prev;
if (place->prev)
place->prev->next = place->next;
else
all_child_places = place->next;
if (!refcount) { if (!refcount) {
destroy_place_object_locks(place_obj); destroy_place_object_locks(place_obj);
} }
@ -2206,7 +2222,7 @@ static void *place_start_proc(void *data_arg) {
return rc; return rc;
} }
void scheme_pause_one_place(Scheme_Place *p) static void pause_one_place(Scheme_Place *p)
{ {
Scheme_Place_Object *place_obj = p->place_obj; Scheme_Place_Object *place_obj = p->place_obj;
@ -2234,7 +2250,7 @@ static void resume_one_place_with_lock(Scheme_Place_Object *place_obj)
} }
} }
void scheme_resume_one_place(Scheme_Place *p) static void resume_one_place(Scheme_Place *p)
{ {
Scheme_Place_Object *place_obj = p->place_obj; Scheme_Place_Object *place_obj = p->place_obj;
@ -2245,6 +2261,24 @@ void scheme_resume_one_place(Scheme_Place *p)
} }
} }
static void pause_all_child_places()
{
Scheme_Place *p = all_child_places;
while (p) {
pause_one_place(p);
p = p->next;
}
}
static void resume_all_child_places()
{
Scheme_Place *p = all_child_places;
while (p) {
resume_one_place(p);
p = p->next;
}
}
void destroy_place_object_locks(Scheme_Place_Object *place_obj) { void destroy_place_object_locks(Scheme_Place_Object *place_obj) {
mzrt_mutex_destroy(place_obj->lock); mzrt_mutex_destroy(place_obj->lock);
if (place_obj->pause) if (place_obj->pause)
@ -2279,10 +2313,10 @@ void scheme_place_check_for_interruption()
mzrt_mutex_unlock(place_obj->lock); mzrt_mutex_unlock(place_obj->lock);
if (local_pause) { if (local_pause) {
scheme_pause_all_places(); pause_all_child_places();
mzrt_sema_wait(local_pause); mzrt_sema_wait(local_pause);
mzrt_sema_destroy(local_pause); mzrt_sema_destroy(local_pause);
scheme_resume_all_places(); resume_all_child_places();
} else } else
break; break;
} }
@ -2311,7 +2345,7 @@ void scheme_place_set_memory_use(intptr_t mem_use)
custodian limits that will kill this place; pause this custodian limits that will kill this place; pause this
place and its children to give the original place time place and its children to give the original place time
to kill this one */ to kill this one */
scheme_pause_all_places(); pause_all_child_places();
mzrt_ensure_max_cas(place_obj->parent_need_gc, 1); mzrt_ensure_max_cas(place_obj->parent_need_gc, 1);
scheme_signal_received_at(place_obj->parent_signal_handle); scheme_signal_received_at(place_obj->parent_signal_handle);
} else if (mem_use > (1 + place_obj->use_factor) * place_obj->prev_notify_memory_use) { } else if (mem_use > (1 + place_obj->use_factor) * place_obj->prev_notify_memory_use) {
@ -2334,7 +2368,7 @@ void scheme_place_check_memory_use()
if (force_gc_for_place_accounting) { if (force_gc_for_place_accounting) {
force_gc_for_place_accounting = 0; force_gc_for_place_accounting = 0;
scheme_collect_garbage(); scheme_collect_garbage();
scheme_resume_all_places(); resume_all_child_places();
} }
} }

View File

@ -3815,6 +3815,8 @@ typedef struct Scheme_Place {
struct GC_Thread_Info *gc_info; /* managed by the GC */ struct GC_Thread_Info *gc_info; /* managed by the GC */
#endif #endif
Scheme_Object *pumper_threads; /* Scheme_Vector of scheme threads */ Scheme_Object *pumper_threads; /* Scheme_Vector of scheme threads */
struct Scheme_Place *prev, *next; /* keeping a list of child places */
} Scheme_Place; } Scheme_Place;
typedef struct Scheme_Place_Object { typedef struct Scheme_Place_Object {
@ -3882,9 +3884,4 @@ void scheme_place_set_memory_use(intptr_t amt);
void scheme_place_check_memory_use(); void scheme_place_check_memory_use();
void scheme_clear_place_ifs_stack(); void scheme_clear_place_ifs_stack();
void scheme_pause_all_places();
void scheme_pause_one_place(Scheme_Place *p);
void scheme_resume_all_places();
void scheme_resume_one_place(Scheme_Place *p);
#endif /* __mzscheme_private__ */ #endif /* __mzscheme_private__ */

View File

@ -156,6 +156,7 @@ THREAD_LOCAL_DECL(static int buffer_init_size);
THREAD_LOCAL_DECL(Scheme_Thread *scheme_current_thread = NULL); THREAD_LOCAL_DECL(Scheme_Thread *scheme_current_thread = NULL);
THREAD_LOCAL_DECL(Scheme_Thread *scheme_main_thread = NULL); THREAD_LOCAL_DECL(Scheme_Thread *scheme_main_thread = NULL);
THREAD_LOCAL_DECL(Scheme_Thread *scheme_first_thread = NULL); THREAD_LOCAL_DECL(Scheme_Thread *scheme_first_thread = NULL);
THREAD_LOCAL_DECL(static Scheme_Thread *gc_prep_thread_chain = NULL);
XFORM_NONGCING Scheme_Thread *scheme_get_current_thread() { return scheme_current_thread; } XFORM_NONGCING Scheme_Thread *scheme_get_current_thread() { return scheme_current_thread; }
XFORM_NONGCING intptr_t scheme_get_multiple_count() { return scheme_current_thread->ku.multiple.count; } XFORM_NONGCING intptr_t scheme_get_multiple_count() { return scheme_current_thread->ku.multiple.count; }
@ -292,10 +293,16 @@ typedef struct {
# define MALLOC_MREF() (Scheme_Custodian_Reference *)scheme_make_late_weak_box(NULL) # define MALLOC_MREF() (Scheme_Custodian_Reference *)scheme_make_late_weak_box(NULL)
# define CUSTODIAN_FAM(x) ((Scheme_Custodian_Weak_Box *)x)->val # define CUSTODIAN_FAM(x) ((Scheme_Custodian_Weak_Box *)x)->val
# define xCUSTODIAN_FAM(x) SCHEME_BOX_VAL(x) # define xCUSTODIAN_FAM(x) SCHEME_BOX_VAL(x)
# define SET_MREF_POSITION(mref, i) (((Scheme_Custodian_Weak_Box *)mref)->hash_key = (i & 0xFFFF))
# define EXTRACT_MREF_START_POSITION(mref, c) (((Scheme_Custodian_Weak_Box *)mref)->hash_key | ((c) & ~0xFFFF))
# define EXTRACT_MREF_POSITION_DELTA(mref, c) 0x10000
#else #else
# define MALLOC_MREF() MALLOC_ONE_WEAK(Scheme_Custodian_Reference) # define MALLOC_MREF() MALLOC_ONE_WEAK(Scheme_Custodian_Reference)
# define CUSTODIAN_FAM(x) (*(x)) # define CUSTODIAN_FAM(x) (*(x))
# define xCUSTODIAN_FAM(x) (*(x)) # define xCUSTODIAN_FAM(x) (*(x))
# define SET_MREF_POSITION(mref, i) /* empty */
# define EXTRACT_MREF_START_POSITION(mref, c) ((c)-1)
# define EXTRACT_MREF_POSITION_DELTA(mref, c) 1
#endif #endif
typedef struct Proc_Global_Rec { typedef struct Proc_Global_Rec {
@ -891,7 +898,7 @@ static void add_managed_box(Scheme_Custodian *m,
Scheme_Object **box, Scheme_Custodian_Reference *mref, Scheme_Object **box, Scheme_Custodian_Reference *mref,
Scheme_Close_Custodian_Client *f, void *data) Scheme_Close_Custodian_Client *f, void *data)
{ {
int i; int i, saw = 0;
for (i = m->count; i--; ) { for (i = m->count; i--; ) {
if (!m->boxes[i]) { if (!m->boxes[i]) {
@ -899,11 +906,16 @@ static void add_managed_box(Scheme_Custodian *m,
m->closers[i] = f; m->closers[i] = f;
m->data[i] = data; m->data[i] = data;
m->mrefs[i] = mref; m->mrefs[i] = mref;
SET_MREF_POSITION(mref, i);
m->elems++; m->elems++;
adjust_limit_table(m); adjust_limit_table(m);
return; return;
} else {
saw++;
if (i + saw == m->elems)
break; /* no empty spaces left */
} }
} }
@ -913,6 +925,7 @@ static void add_managed_box(Scheme_Custodian *m,
m->closers[m->count] = f; m->closers[m->count] = f;
m->data[m->count] = data; m->data[m->count] = data;
m->mrefs[m->count] = mref; m->mrefs[m->count] = mref;
SET_MREF_POSITION(mref, m->count);
m->elems++; m->elems++;
adjust_limit_table(m); adjust_limit_table(m);
@ -924,7 +937,7 @@ static void remove_managed(Scheme_Custodian_Reference *mr, Scheme_Object *o,
Scheme_Close_Custodian_Client **old_f, void **old_data) Scheme_Close_Custodian_Client **old_f, void **old_data)
{ {
Scheme_Custodian *m; Scheme_Custodian *m;
int i; int i, delta;
if (!mr) if (!mr)
return; return;
@ -932,21 +945,27 @@ static void remove_managed(Scheme_Custodian_Reference *mr, Scheme_Object *o,
if (!m) if (!m)
return; return;
for (i = m->count; i--; ) { i = EXTRACT_MREF_START_POSITION(mr, m->count);
if (m->boxes[i] && SAME_OBJ((xCUSTODIAN_FAM(m->boxes[i])), o)) { delta = EXTRACT_MREF_POSITION_DELTA(mr, m->count);
xCUSTODIAN_FAM(m->boxes[i]) = 0;
m->boxes[i] = NULL; while (i >= 0) {
CUSTODIAN_FAM(m->mrefs[i]) = 0; if (i < m->count) {
m->mrefs[i] = NULL; if (m->boxes[i] && SAME_OBJ((xCUSTODIAN_FAM(m->boxes[i])), o)) {
if (old_f) xCUSTODIAN_FAM(m->boxes[i]) = 0;
*old_f = m->closers[i]; m->boxes[i] = NULL;
if (old_data) CUSTODIAN_FAM(m->mrefs[i]) = 0;
*old_data = m->data[i]; m->mrefs[i] = NULL;
m->data[i] = NULL; if (old_f)
--m->elems; *old_f = m->closers[i];
adjust_limit_table(m); if (old_data)
break; *old_data = m->data[i];
m->data[i] = NULL;
--m->elems;
adjust_limit_table(m);
break;
}
} }
i -= delta;
} }
while (m->count && !m->boxes[m->count - 1]) { while (m->count && !m->boxes[m->count - 1]) {
@ -1265,11 +1284,12 @@ Scheme_Thread *scheme_do_close_managed(Scheme_Custodian *m, Scheme_Exit_Closer_F
CUSTODIAN_FAM(m->mrefs[i]) = NULL; CUSTODIAN_FAM(m->mrefs[i]) = NULL;
/* Set m->count to i in case a GC happens while /* Set m->count to i in case a GC happens while
the closer is running. If there's a GC, then the closer is running. */
for_each_managed will be called. */
m->count = i; m->count = i;
if (is_thread && !the_thread) { if (!o) {
/* weak link disappeared */
} else if (is_thread && !the_thread) {
/* Thread is already collected, so skip */ /* Thread is already collected, so skip */
} else if (cf) { } else if (cf) {
cf(o, f, data); cf(o, f, data);
@ -1357,53 +1377,6 @@ Scheme_Thread *scheme_do_close_managed(Scheme_Custodian *m, Scheme_Exit_Closer_F
return kill_self; return kill_self;
} }
typedef void (*Scheme_For_Each_Func)(Scheme_Object *);
static void for_each_managed(Scheme_Type type, Scheme_For_Each_Func cf)
XFORM_SKIP_PROC
/* This function must not allocate. */
{
Scheme_Custodian *m;
int i;
if (SAME_TYPE(type, scheme_thread_type))
type = scheme_thread_hop_type;
/* back to front so children are first: */
m = last_custodian;
while (m) {
for (i = m->count; i--; ) {
if (m->boxes[i]) {
Scheme_Object *o;
o = xCUSTODIAN_FAM(m->boxes[i]);
if (SAME_TYPE(SCHEME_TYPE(o), type)) {
if (SAME_TYPE(type, scheme_thread_hop_type)) {
/* We've added an indirection and made it weak. See mr_hop note above. */
Scheme_Thread *t;
t = (Scheme_Thread *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
if (!t) {
/* The thread is already collected */
continue;
} else if (SAME_OBJ(t->mref, m->mrefs[i]))
o = (Scheme_Object *)t;
else {
/* The main custodian for this thread is someone else */
continue;
}
}
cf(o);
}
}
}
m = CUSTODIAN_FAM(m->global_prev);
}
}
static void do_close_managed(Scheme_Custodian *m) static void do_close_managed(Scheme_Custodian *m)
/* The trick is that we may need to kill the thread /* The trick is that we may need to kill the thread
that is running us. If so, delay it to the very that is running us. If so, delay it to the very
@ -1483,30 +1456,6 @@ static Scheme_Object *extract_thread(Scheme_Object *o)
return (Scheme_Object *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p); return (Scheme_Object *)WEAKIFIED(((Scheme_Thread_Custodian_Hop *)o)->p);
} }
static void pause_place(Scheme_Object *o)
{
#ifdef MZ_USE_PLACES
scheme_pause_one_place((Scheme_Place *)o);
#endif
}
void scheme_pause_all_places()
{
for_each_managed(scheme_place_type, pause_place);
}
static void resume_place(Scheme_Object *o)
{
#ifdef MZ_USE_PLACES
scheme_resume_one_place((Scheme_Place *)o);
#endif
}
void scheme_resume_all_places()
{
for_each_managed(scheme_place_type, resume_place);
}
void scheme_init_custodian_extractors() void scheme_init_custodian_extractors()
{ {
if (!extractors) { if (!extractors) {
@ -2053,6 +2002,9 @@ static Scheme_Thread *make_thread(Scheme_Config *config,
process->prev = NULL; process->prev = NULL;
process->next = NULL; process->next = NULL;
gc_prep_thread_chain = process;
scheme_current_thread->gc_prep_chain = process;
process->suspend_break = 1; /* until start-up finished */ process->suspend_break = 1; /* until start-up finished */
process->error_buf = NULL; process->error_buf = NULL;
@ -2444,7 +2396,6 @@ static void do_swap_thread()
} }
#endif #endif
if (!swap_no_setjmp && SETJMP(scheme_current_thread)) { if (!swap_no_setjmp && SETJMP(scheme_current_thread)) {
/* We're back! */ /* We're back! */
/* See also initial swap in in start_child() */ /* See also initial swap in in start_child() */
@ -2537,6 +2488,10 @@ static void do_swap_thread()
#endif #endif
scheme_current_thread = new_thread; scheme_current_thread = new_thread;
if (!new_thread->gc_prep_chain) {
new_thread->gc_prep_chain = gc_prep_thread_chain;
gc_prep_thread_chain = new_thread;
}
/* Fixup current pointers in thread sets */ /* Fixup current pointers in thread sets */
if (!scheme_current_thread->return_marks_to) { if (!scheme_current_thread->return_marks_to) {
@ -3240,6 +3195,9 @@ Scheme_Object *scheme_call_as_nested_thread(int argc, Scheme_Object *argv[], voi
scheme_first_thread->prev = np; scheme_first_thread->prev = np;
scheme_first_thread = np; scheme_first_thread = np;
np->gc_prep_chain = gc_prep_thread_chain;
gc_prep_thread_chain = np;
np->t_set_parent = p->t_set_parent; np->t_set_parent = p->t_set_parent;
schedule_in_set((Scheme_Object *)np, np->t_set_parent); schedule_in_set((Scheme_Object *)np, np->t_set_parent);
@ -8095,6 +8053,8 @@ static void prepare_thread_for_GC(Scheme_Object *t)
{ {
Scheme_Thread *p = (Scheme_Thread *)t; Scheme_Thread *p = (Scheme_Thread *)t;
if (!p->running) return;
/* zero ununsed part of env stack in each thread */ /* zero ununsed part of env stack in each thread */
if (!p->nestee) { if (!p->nestee) {
@ -8267,7 +8227,20 @@ static void get_ready_for_GC()
} }
#endif #endif
for_each_managed(scheme_thread_type, prepare_thread_for_GC); /* Prepare each thread that has run: */
if (gc_prep_thread_chain) {
Scheme_Thread *p, *next;
p = gc_prep_thread_chain;
while (p != p->gc_prep_chain) {
prepare_thread_for_GC((Scheme_Object *)p);
next = p->gc_prep_chain;
p->gc_prep_chain = NULL;
p = next;
}
prepare_thread_for_GC((Scheme_Object *)p);
p->gc_prep_chain = NULL;
gc_prep_thread_chain = NULL;
}
#ifdef MZ_PRECISE_GC #ifdef MZ_PRECISE_GC
scheme_flush_stack_copy_cache(); scheme_flush_stack_copy_cache();
@ -8318,6 +8291,9 @@ static void done_with_GC()
end_this_gc_real_time = scheme_get_inexact_milliseconds(); end_this_gc_real_time = scheme_get_inexact_milliseconds();
scheme_total_gc_time += (end_this_gc_time - start_this_gc_time); scheme_total_gc_time += (end_this_gc_time - start_this_gc_time);
gc_prep_thread_chain = scheme_current_thread;
scheme_current_thread->gc_prep_chain = scheme_current_thread;
run_gc_callbacks(0); run_gc_callbacks(0);
#ifdef MZ_USE_FUTURES #ifdef MZ_USE_FUTURES