clean up place exit handling

- don't crash on multiple kills or waits
 - allow the OS to reclaim the place thread when it exits on its own
This commit is contained in:
Matthew Flatt 2011-07-01 09:13:12 -06:00
parent 0f42552a0e
commit 3078d5c494
4 changed files with 95 additions and 127 deletions

View File

@ -6,15 +6,16 @@
(printf "Hello from place\n")))
(let ([p (place/base (p1 ch)
(printf "Hello form place 2\n"))])
(printf "Hello form place 2\n")
(exit 99))])
(test #f place? 1)
(test #f place? void)
(test #t place? p)
(err/rt-test (place-wait 1))
(err/rt-test (place-wait void))
(test (void) place-wait p)
)
(test 99 place-wait p)
(test 99 place-wait p))
(arity-test dynamic-place 2 2)
(arity-test place-wait 1 1)
@ -33,6 +34,8 @@
(let ([p (place/base (p1 ch)
(printf "Hello form place 2\n")
(sync never-evt))])
(place-kill p)
(place-kill p)
(place-kill p))
(for ([v (list #t #f null 'a #\a 1 1/2 1.0 (expt 2 100)

View File

@ -319,7 +319,7 @@ typedef struct Thread_Local_Variables {
struct Scheme_Hash_Table *place_local_misc_table_;
int place_evts_array_size_;
struct Evt **place_evts_;
void *place_object_;
struct Scheme_Place_Object *place_object_;
struct Scheme_Object *empty_self_shift_cache_;
struct Scheme_Bucket_Table *scheme_module_code_cache_;
struct Scheme_Object *group_member_cache_;

View File

@ -21,7 +21,7 @@ static int id_counter;
static mzrt_mutex *id_counter_mutex;
SHARED_OK mz_proc_thread *scheme_master_proc_thread;
THREAD_LOCAL_DECL(void *place_object);
THREAD_LOCAL_DECL(struct Scheme_Place_Object *place_object);
static Scheme_Object *scheme_place(int argc, Scheme_Object *args[]);
static Scheme_Object *place_wait(int argc, Scheme_Object *args[]);
static Scheme_Object *place_kill(int argc, Scheme_Object *args[]);
@ -34,7 +34,7 @@ static Scheme_Object *place_channel_p(int argc, Scheme_Object *args[]);
static Scheme_Object *def_place_exit_handler_proc(int argc, Scheme_Object *args[]);
static Scheme_Object *place_channel(int argc, Scheme_Object *args[]);
static Scheme_Object* place_allowed_p(int argc, Scheme_Object *args[]);
static int cust_kill_place(Scheme_Object *pl, void *notused);
static void cust_kill_place(Scheme_Object *pl, void *notused);
static Scheme_Place_Async_Channel *place_async_channel_create();
static Scheme_Place_Bi_Channel *place_bi_channel_create();
@ -145,7 +145,7 @@ typedef struct Place_Start_Data {
Scheme_Object *channel;
Scheme_Object *current_library_collection_paths;
mzrt_sema *ready; /* malloc'ed item */
void *place_obj; /* malloc'ed item */
struct Scheme_Place_Object *place_obj; /* malloc'ed item */
} Place_Start_Data;
static void null_out_runtime_globals() {
@ -174,6 +174,8 @@ typedef struct Scheme_Place_Object {
char ref;
mz_jmp_buf *exit_buf;
void *signal_handle;
void *parent_signal_handle; /* set to NULL when the place terminates */
intptr_t result; /* initialized to 1, reset when parent_signal_handle becomes NULL */
/*Thread_Local_Variables *tlvs; */
} Scheme_Place_Object;
@ -194,6 +196,12 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
place_obj->die = 0;
place_obj->pbreak = 0;
place_obj->ref= 1;
place_obj->result = 1;
{
GC_CAN_IGNORE void *handle;
handle = scheme_get_signal_handle();
place_obj->parent_signal_handle = handle;
}
mzrt_sema_create(&ready, 0);
@ -202,14 +210,14 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
place_data->ready = ready;
place_data->place_obj = place_obj;
if (argc == 2) {
{
Scheme_Object *so;
if (!scheme_is_module_path(args[0]) && !SCHEME_PATHP(args[0])) {
scheme_wrong_type("place", "module-path or path", 0, argc, args);
scheme_wrong_type("dynamic-place", "module-path or path", 0, argc, args);
}
if (!SCHEME_SYMBOLP(args[1])) {
scheme_wrong_type("place", "symbol", 1, argc, args);
scheme_wrong_type("dynamic-place", "symbol", 1, argc, args);
}
so = places_deep_copy_to_master(args[0]);
@ -227,9 +235,6 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
place_data->channel = (Scheme_Object *) channel;
}
}
else {
scheme_wrong_count_m("place", 2, 2, argc, args, 0);
}
collection_paths = scheme_current_library_collection_paths(0, NULL);
collection_paths = places_deep_copy_to_master(collection_paths);
@ -243,6 +248,8 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
scheme_signal_error("place: place creation failed");
}
mz_proc_thread_detach(proc_thread);
/* wait until the place has started and grabbed the value
from `place_data'; it's important that a GC doesn't happen
here until the other place is far enough. */
@ -252,28 +259,28 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
place_data->ready = NULL;
place_data->place_obj = NULL;
place->proc_thread = proc_thread;
{
Scheme_Custodian *cust;
Scheme_Custodian_Reference *mref;
cust = scheme_get_current_custodian();
mref = scheme_add_managed(NULL,
(Scheme_Object *)place,
(Scheme_Close_Custodian_Client *)cust_kill_place,
NULL,
1);
(Scheme_Object *)place,
cust_kill_place,
NULL,
1);
place->mref = mref;
}
return (Scheme_Object*) place;
}
static int do_place_kill(Scheme_Place *place) {
static void do_place_kill(Scheme_Place *place)
{
Scheme_Place_Object *place_obj;
int ref = 0;
place_obj = (Scheme_Place_Object*) place->place_obj;
place_obj = place->place_obj;
if (!place_obj) return;
{
mzrt_mutex_lock(place_obj->lock);
@ -283,15 +290,16 @@ static int do_place_kill(Scheme_Place *place) {
if (ref != 0) { scheme_signal_received_at(place_obj->signal_handle); }
place->result = place_obj->result;
mzrt_mutex_unlock(place_obj->lock);
}
if (ref == 0) { free(place->place_obj); }
else { scheme_signal_received_at(place_obj->signal_handle); }
if (ref == 0)
free(place->place_obj);
scheme_remove_managed(place->mref, (Scheme_Object *)place);
place->place_obj = NULL;
return 0;
}
static int do_place_break(Scheme_Place *place) {
@ -311,33 +319,28 @@ static int do_place_break(Scheme_Place *place) {
return 0;
}
static int cust_kill_place(Scheme_Object *pl, void *notused) {
return do_place_kill((Scheme_Place *)pl);
static void cust_kill_place(Scheme_Object *pl, void *notused) {
do_place_kill((Scheme_Place *)pl);
}
static Scheme_Object *place_kill(int argc, Scheme_Object *args[]) {
Scheme_Place *place;
place = (Scheme_Place *) args[0];
if (argc != 1) {
scheme_wrong_count_m("place-kill", 1, 1, argc, args, 0);
}
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type)) {
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type))
scheme_wrong_type("place-kill", "place", 0, argc, args);
}
return scheme_make_integer(do_place_kill(place));
do_place_kill(place);
return scheme_void;
}
static Scheme_Object *place_break(int argc, Scheme_Object *args[]) {
Scheme_Place *place;
place = (Scheme_Place *) args[0];
if (argc != 1) {
scheme_wrong_count_m("place-break", 1, 1, argc, args, 0);
}
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type)) {
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type))
scheme_wrong_type("place-break", "place", 0, argc, args);
}
return scheme_make_integer(do_place_break(place));
}
@ -790,85 +793,36 @@ static void do_group_signal_fds()
#endif
# if defined(MZ_PRECISE_GC)
/* ---------------------------------------------------------------------- */
/*============= THREAD JOIN HANDLER =============*/
typedef struct {
mz_proc_thread *proc_thread;
Scheme_Place *waiting_place;
int *wake_fd;
int ready;
intptr_t rc;
} proc_thread_wait_data;
static int place_wait_ready(Scheme_Object *_p) {
Scheme_Place *p = (Scheme_Place *)_p;
int done;
if (!p->place_obj) return 1;
static void *mz_proc_thread_wait_worker(void *data) {
void *rc;
proc_thread_wait_data *wd = (proc_thread_wait_data*) data;
mzrt_mutex_lock(p->place_obj->lock);
done = !p->place_obj->parent_signal_handle;
mzrt_mutex_unlock(p->place_obj->lock);
rc = mz_proc_thread_wait(wd->proc_thread);
wd->rc = (intptr_t) rc;
wd->ready = 1;
scheme_signal_received_at(wd->wake_fd);
return NULL;
}
static int place_wait_ready(Scheme_Object *o) {
proc_thread_wait_data *wd = (proc_thread_wait_data*) o;
if (wd->ready) {
if (done) {
do_place_kill(p); /* sets result, frees place */
return 1;
}
return 0;
}
# endif
static Scheme_Object *place_wait(int argc, Scheme_Object *args[]) {
Scheme_Place *place;
place = (Scheme_Place *) args[0];
if (argc != 1) {
scheme_wrong_count_m("place-wait", 1, 1, argc, args, 0);
}
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type)) {
if (!SAME_TYPE(SCHEME_TYPE(args[0]), scheme_place_type))
scheme_wrong_type("place-wait", "place", 0, argc, args);
}
# ifdef MZ_PRECISE_GC
{
Scheme_Object *rc;
mz_proc_thread *worker_thread;
Scheme_Place *waiting_place;
int *wake_fd;
scheme_block_until(place_wait_ready, NULL, (Scheme_Object*)place, 0);
proc_thread_wait_data *wd;
wd = (proc_thread_wait_data*) malloc(sizeof(proc_thread_wait_data));
wd->proc_thread = (mz_proc_thread *)place->proc_thread;
wd->waiting_place = waiting_place;
wake_fd = scheme_get_signal_handle();
wd->wake_fd = wake_fd;
wd->ready = 0;
worker_thread = mz_proc_thread_create(mz_proc_thread_wait_worker, wd);
mz_proc_thread_detach(worker_thread);
scheme_block_until(place_wait_ready, NULL, (Scheme_Object *) wd, 0);
rc = scheme_make_integer((intptr_t)wd->rc);
free(wd);
/*
return rc;
*/
return scheme_void;
}
# else
{
void *rcvoid;
rcvoid = mz_proc_thread_wait((mz_proc_thread *)place->proc_thread);
/*
return scheme_make_integer((intptr_t) rcvoid);
*/
return scheme_void;
}
# endif
return scheme_make_integer(place->result);
}
static Scheme_Object *place_p(int argc, Scheme_Object *args[])
@ -1591,7 +1545,7 @@ void scheme_place_check_for_interruption() {
char local_die;
char local_break;
place_obj = (Scheme_Place_Object *) place_object;
place_obj = place_object;
if (place_obj) {
{
mzrt_mutex_lock(place_obj->lock);
@ -1613,7 +1567,7 @@ void scheme_place_check_for_interruption() {
static void place_release_place_object() {
int ref = 0;
Scheme_Place_Object *place_obj = (Scheme_Place_Object *) place_object;
Scheme_Place_Object *place_obj = place_object;
if (place_obj) {
mzrt_mutex_lock(place_obj->lock);
ref = --place_obj->ref;
@ -1625,24 +1579,36 @@ static void place_release_place_object() {
}
}
static Scheme_Object *def_place_exit_handler_proc(int argc, Scheme_Object *argv[])
static void place_set_result(Scheme_Object *result)
{
intptr_t status;
if (SCHEME_INTP(argv[0])) {
status = SCHEME_INT_VAL(argv[0]);
if (SCHEME_INTP(result)) {
status = SCHEME_INT_VAL(result);
if (status < 1 || status > 255)
status = 0;
} else
status = 0;
mzrt_mutex_lock(place_object->lock);
place_object->result = status;
scheme_signal_received_at(place_object->parent_signal_handle);
place_object->parent_signal_handle = NULL;
mzrt_mutex_unlock(place_object->lock);
}
static Scheme_Object *def_place_exit_handler_proc(int argc, Scheme_Object *argv[])
{
scheme_log(NULL, SCHEME_LOG_DEBUG, 0, "place %d: exiting via (exit)", scheme_current_place_id);
place_set_result(argv[0]);
/*printf("Leavin place: proc thread id%u\n", ptid);*/
scheme_place_instance_destroy();
place_release_place_object();
mz_proc_thread_exit((void *) status);
mz_proc_thread_exit(NULL);
return scheme_void; /* Never get here */
}
@ -1652,7 +1618,6 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
Scheme_Object *place_main;
Scheme_Object *a[2], *channel;
mzrt_thread_id ptid;
intptr_t rc = 0;
ptid = mz_proc_thread_self();
place_data = (Place_Start_Data *) data_arg;
@ -1683,7 +1648,7 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
else {
channel = place_data->channel;
}
place_obj = (Scheme_Place_Object*) place_data->place_obj;
place_obj = place_data->place_obj;
place_object = place_obj;
place_obj->ref++;
@ -1714,6 +1679,8 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
Scheme_Thread * volatile p;
mz_jmp_buf * volatile saved_error_buf;
mz_jmp_buf new_error_buf;
Scheme_Object * volatile rc = scheme_false;
place_obj->exit_buf = &new_error_buf;
@ -1728,11 +1695,14 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
dynamic_require = scheme_builtin_value("dynamic-require");
place_main = scheme_apply(dynamic_require, 2, a);
a[0] = channel;
scheme_apply(place_main, 1, a);
(void)scheme_apply(place_main, 1, a);
rc = scheme_make_integer(0);
} else {
rc = 1;
rc = scheme_make_integer(1);
}
p->error_buf = saved_error_buf;
place_set_result(rc);
}
scheme_log(NULL, SCHEME_LOG_DEBUG, 0, "place %d: exiting", scheme_current_place_id);
@ -1741,7 +1711,8 @@ static void *place_start_proc_after_stack(void *data_arg, void *stack_base) {
scheme_place_instance_destroy();
place_release_place_object();
return (void*) rc;
return NULL;
}
Scheme_Object *places_deep_copy_to_master(Scheme_Object *so) {
@ -2128,18 +2099,12 @@ Scheme_Place_Bi_Channel *place_bi_peer_channel_create(Scheme_Place_Bi_Channel *o
}
static Scheme_Object *place_channel(int argc, Scheme_Object *args[]) {
if (argc == 0) {
Scheme_Place_Bi_Channel *ch;
Scheme_Object *a[2];
ch = place_bi_channel_create();
a[0] = (Scheme_Object *) ch;
a[1] = (Scheme_Object *) place_bi_peer_channel_create(ch);
return scheme_values(2, a);
}
else {
scheme_wrong_count_m("place-channel", 0, 0, argc, args, 0);
}
return scheme_true;
Scheme_Place_Bi_Channel *ch;
Scheme_Object *a[2];
ch = place_bi_channel_create();
a[0] = (Scheme_Object *) ch;
a[1] = (Scheme_Object *) place_bi_peer_channel_create(ch);
return scheme_values(2, a);
}
static Scheme_Object *place_channel_p(int argc, Scheme_Object *args[])

View File

@ -3611,10 +3611,10 @@ typedef struct Scheme_Place_Bi_Channel {
typedef struct Scheme_Place {
Scheme_Object so;
void *proc_thread;
void *place_obj;
struct Scheme_Place_Object *place_obj;
Scheme_Object *channel;
Scheme_Custodian_Reference *mref;
intptr_t result; /* set when place_obj becomes NULL */
} Scheme_Place;
Scheme_Env *scheme_place_instance_init();