handle escapes in futures

svn: r16910
This commit is contained in:
Matthew Flatt 2009-11-20 00:47:44 +00:00
parent 2781f1a4b8
commit 1224ad19be
2 changed files with 56 additions and 4 deletions

View File

@ -153,6 +153,15 @@ void *g_funcargs[5];
void *func_retval = NULL; void *func_retval = NULL;
#ifdef MZ_PRECISE_GC
# define scheme_future_setjmp(newbuf) scheme_jit_setjmp((newbuf).jb)
# define scheme_future_longjmp(newbuf, v) scheme_jit_longjmp((newbuf).jb, v)
#else
# define scheme_future_setjmp(newbuf) scheme_setjmp(newbuf)
# define scheme_future_longjmp(newbuf, v) scheme_longjmp(newbuf, v)
#endif
/**********************************************************************/ /**********************************************************************/
/* Helpers for debugging */ /* Helpers for debugging */
/**********************************************************************/ /**********************************************************************/
@ -582,7 +591,9 @@ int future_ready(Scheme_Object *obj)
} }
static void dequeue_future(future_t *ft) static void dequeue_future(future_t *ft)
/* called from both future and runtime threads */
{ {
START_XFORM_SKIP;
if (ft->prev == NULL) if (ft->prev == NULL)
{ {
//Set next to be the head of the queue //Set next to be the head of the queue
@ -596,6 +607,7 @@ static void dequeue_future(future_t *ft)
if (NULL != ft->next) if (NULL != ft->next)
ft->next->prev = ft->prev; ft->next->prev = ft->prev;
} }
END_XFORM_SKIP;
} }
@ -647,8 +659,6 @@ Scheme_Object *touch(int argc, Scheme_Object *argv[])
LOG("Successfully touched future %d\n", ft->id); LOG("Successfully touched future %d\n", ft->id);
// fflush(stdout); // fflush(stdout);
dequeue_future(ft);
//Increment the number of available pool threads //Increment the number of available pool threads
g_num_avail_threads++; g_num_avail_threads++;
pthread_mutex_unlock(&g_future_queue_mutex); pthread_mutex_unlock(&g_future_queue_mutex);
@ -671,6 +681,10 @@ Scheme_Object *touch(int argc, Scheme_Object *argv[])
goto wait_for_rtcall_or_completion; goto wait_for_rtcall_or_completion;
} }
if (!retval) {
scheme_signal_error("touch: future previously aborted");
}
return retval; return retval;
} }
@ -731,6 +745,7 @@ void *worker_thread_future_loop(void *arg)
Scheme_Object* (*jitcode)(Scheme_Object*, int, Scheme_Object**); Scheme_Object* (*jitcode)(Scheme_Object*, int, Scheme_Object**);
future_t *ft; future_t *ft;
int id = *(int *)arg; int id = *(int *)arg;
mz_jmp_buf newbuf;
scheme_init_os_thread(); scheme_init_os_thread();
@ -811,7 +826,15 @@ void *worker_thread_future_loop(void *arg)
//If jitcode asks the runrtime thread to do work, then //If jitcode asks the runrtime thread to do work, then
//a GC can occur. //a GC can occur.
LOG("Running JIT code at %p...\n", ft->code); LOG("Running JIT code at %p...\n", ft->code);
scheme_current_thread->error_buf = &newbuf;
if (scheme_future_setjmp(newbuf)) {
/* failed */
v = NULL;
} else {
v = jitcode(ft->orig_lambda, 0, NULL); v = jitcode(ft->orig_lambda, 0, NULL);
}
LOG("Finished running JIT code at %p.\n", ft->code); LOG("Finished running JIT code at %p.\n", ft->code);
// Get future again, since a GC may have occurred // Get future again, since a GC may have occurred
@ -827,6 +850,8 @@ void *worker_thread_future_loop(void *arg)
//Update the status //Update the status
ft->status = FINISHED; ft->status = FINISHED;
dequeue_future(ft);
scheme_signal_received_at(g_signal_handle); scheme_signal_received_at(g_signal_handle);
pthread_mutex_unlock(&g_future_queue_mutex); pthread_mutex_unlock(&g_future_queue_mutex);
@ -922,6 +947,11 @@ void future_do_runtimecall(void *func,
pthread_mutex_unlock(&g_future_queue_mutex); pthread_mutex_unlock(&g_future_queue_mutex);
if (future->no_retval) {
future->no_retval = 0;
scheme_future_longjmp(*scheme_current_thread->error_buf, 1);
}
END_XFORM_SKIP; END_XFORM_SKIP;
} }
@ -993,7 +1023,7 @@ static void send_special_result(future_t *f, Scheme_Object *retval)
//Does the work of actually invoking a primitive on behalf of a //Does the work of actually invoking a primitive on behalf of a
//future. This function is always invoked on the main (runtime) //future. This function is always invoked on the main (runtime)
//thread. //thread.
void invoke_rtcall(future_t *future) static void do_invoke_rtcall(future_t *future)
/* Called in runtime thread */ /* Called in runtime thread */
{ {
#ifdef DEBUG_FUTURES #ifdef DEBUG_FUTURES
@ -1035,6 +1065,27 @@ void invoke_rtcall(future_t *future)
pthread_mutex_unlock(&g_future_queue_mutex); pthread_mutex_unlock(&g_future_queue_mutex);
} }
static void invoke_rtcall(future_t * volatile future)
{
Scheme_Thread *p = scheme_current_thread;
mz_jmp_buf newbuf, * volatile savebuf;
savebuf = p->error_buf;
p->error_buf = &newbuf;
if (scheme_setjmp(newbuf)) {
pthread_mutex_lock(&g_future_queue_mutex);
future->no_retval = 1;
//Signal the waiting worker thread that it
//can continue running machine code
pthread_cond_signal(future->can_continue_cv);
pthread_mutex_unlock(&g_future_queue_mutex);
scheme_longjmp(*savebuf, 1);
} else {
do_invoke_rtcall(future);
}
p->error_buf = savebuf;
}
/**********************************************************************/ /**********************************************************************/
/* Helpers for manipulating the futures queue */ /* Helpers for manipulating the futures queue */

View File

@ -85,6 +85,7 @@ typedef struct future_t {
Scheme_Object *retval_s; Scheme_Object *retval_s;
void *retval_p; /* use only with conservative GC */ void *retval_p; /* use only with conservative GC */
MZ_MARK_STACK_TYPE retval_m; MZ_MARK_STACK_TYPE retval_m;
int no_retval;
Scheme_Object **multiple_array; Scheme_Object **multiple_array;
int multiple_count; int multiple_count;