Skip to content

Commit

Permalink
adding a ctrl-C (SIGINT) handler, starting work on issue #26.
Browse files Browse the repository at this point in the history
a few more things probably need to be made signal safe, but it is usable
now with the caveat that you shouldn't trust the system too much after
hitting ctrl-C.
  • Loading branch information
JeffBezanson committed Jul 10, 2011
1 parent 6614948 commit be5f581
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jl_value_t *jl_an_empty_cell=NULL;
jl_value_t *jl_stackovf_exception;
jl_value_t *jl_divbyzero_exception;
jl_value_t *jl_undefref_exception;
jl_value_t *jl_interrupt_exception;

jl_bits_type_t *jl_pointer_type;
jl_bits_type_t *jl_pointer_void_type;
Expand Down
1 change: 1 addition & 0 deletions src/boot.j
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ type IOError <: Exception end
type StackOverflowError <: Exception end
type EOFError <: Exception end
type UndefRefError <: Exception end
type InterruptException <: Exception end

type UnionTooComplexError <: Exception
types::Tuple
Expand Down
4 changes: 4 additions & 0 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ JL_CALLABLE(jl_f_throw)

void jl_enter_handler(jl_savestate_t *ss, jmp_buf *handlr)
{
JL_SIGATOMIC_BEGIN();
ss->eh_task = jl_current_task->state.eh_task;
ss->eh_ctx = jl_current_task->state.eh_ctx;
ss->ostream_obj = jl_current_task->state.ostream_obj;
Expand All @@ -99,6 +100,9 @@ void jl_enter_handler(jl_savestate_t *ss, jmp_buf *handlr)
jl_current_task->state.prev = ss;
jl_current_task->state.eh_task = jl_current_task;
jl_current_task->state.eh_ctx = handlr;
// TODO: this should really go after setjmp(). see comment in
// ctx_switch in task.c.
JL_SIGATOMIC_END();
}

void jl_pop_handler(int n)
Expand Down
7 changes: 6 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ static void emit_function(jl_lambda_info_t *lam, Function *f);
//static int n_compile=0;
static Function *to_function(jl_lambda_info_t *li)
{
JL_SIGATOMIC_BEGIN();
Function *f = Function::Create(jl_func_sig, Function::ExternalLinkage,
li->name->name, jl_Module);
assert(jl_is_expr(li->ast));
Expand All @@ -187,6 +188,7 @@ static Function *to_function(jl_lambda_info_t *li)
//verifyFunction(*f);
if (old != NULL)
builder.SetInsertPoint(old);
JL_SIGATOMIC_END();
return f;
}

Expand All @@ -196,8 +198,11 @@ extern "C" void jl_generate_fptr(jl_function_t *f)
jl_lambda_info_t *li = f->linfo;
assert(li->functionObject);
Function *llvmf = (Function*)li->functionObject;
if (li->fptr == NULL)
if (li->fptr == NULL) {
JL_SIGATOMIC_BEGIN();
li->fptr = (jl_fptr_t)jl_ExecutionEngine->getPointerToFunction(llvmf);
JL_SIGATOMIC_END();
}
assert(li->fptr != NULL);
f->fptr = li->fptr;
llvmf->deleteBody();
Expand Down
2 changes: 2 additions & 0 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,7 @@ void jl_save_system_image(char *fname, char *startscriptname)
jl_serialize_value(&f, jl_stackovf_exception);
jl_serialize_value(&f, jl_divbyzero_exception);
jl_serialize_value(&f, jl_undefref_exception);
jl_serialize_value(&f, jl_interrupt_exception);
jl_serialize_value(&f, jl_append_any_func);
jl_serialize_value(&f, jl_method_missing_func);
jl_serialize_value(&f, jl_get_global(jl_system_module,
Expand Down Expand Up @@ -873,6 +874,7 @@ void jl_restore_system_image(char *fname)
jl_stackovf_exception = jl_deserialize_value(&f);
jl_divbyzero_exception = jl_deserialize_value(&f);
jl_undefref_exception = jl_deserialize_value(&f);
jl_interrupt_exception = jl_deserialize_value(&f);
jl_append_any_func = (jl_function_t*)jl_deserialize_value(&f);
jl_method_missing_func = (jl_function_t*)jl_deserialize_value(&f);
jl_idtable_type = (jl_struct_type_t*)jl_deserialize_value(&f);
Expand Down
2 changes: 2 additions & 0 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,10 +647,12 @@ void jl_gc_collect()
{
allocd_bytes = 0;
if (is_gc_enabled) {
JL_SIGATOMIC_BEGIN();
gc_mark();
sweep_weak_refs();
gc_sweep();
run_finalizers();
JL_SIGATOMIC_END();
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,13 +839,15 @@ jl_methlist_t *jl_method_list_insert(jl_methlist_t **pml, jl_tuple_t *type,
while (l != NULL) {
if (sigs_eq((jl_value_t*)type, (jl_value_t*)l->sig)) {
// method overwritten
JL_SIGATOMIC_BEGIN();
l->sig = type;
l->tvars = find_tvars((jl_value_t*)type, jl_null);
l->has_tvars = (l->tvars != jl_null);
l->va = (type->length > 0 &&
jl_is_seq_type(jl_tupleref(type,type->length-1)));
l->invokes = NULL;
l->func = method;
JL_SIGATOMIC_END();
return l;
}
l = l->next;
Expand Down Expand Up @@ -874,8 +876,8 @@ jl_methlist_t *jl_method_list_insert(jl_methlist_t **pml, jl_tuple_t *type,
newrec->func = method;
newrec->invokes = NULL;
newrec->next = l;
JL_SIGATOMIC_BEGIN();
*pl = newrec;
JL_GC_POP();
// if this contains Union types, methods after it might actually be
// more specific than it. we need to re-sort them.
if (has_unions(type)) {
Expand Down Expand Up @@ -903,12 +905,15 @@ jl_methlist_t *jl_method_list_insert(jl_methlist_t **pml, jl_tuple_t *type,
pitem = pnext;
}
}
JL_SIGATOMIC_END();
JL_GC_POP();
return newrec;
}

jl_methlist_t *jl_method_table_insert(jl_methtable_t *mt, jl_tuple_t *type,
jl_function_t *method)
{
JL_SIGATOMIC_BEGIN();
jl_methlist_t *ml = jl_method_list_insert(&mt->defs, type, method, 1);
// invalidate cached methods that overlap this definition
jl_methlist_t *l = mt->cache;
Expand All @@ -934,6 +939,7 @@ jl_methlist_t *jl_method_table_insert(jl_methtable_t *mt, jl_tuple_t *type,
if (na > mt->max_args) {
mt->max_args = na;
}
JL_SIGATOMIC_END();
return ml;
}

Expand Down
30 changes: 30 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,25 @@ void segv_handler(int sig, siginfo_t *info, void *context)
}
}

volatile sig_atomic_t signal_pending = 0;
volatile sig_atomic_t defer_signal = 0;

void sigint_handler(int sig, siginfo_t *info, void *context)
{
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, SIGINT);
sigprocmask(SIG_UNBLOCK, &sset, NULL);

if (defer_signal) {
signal_pending = sig;
}
else {
signal_pending = 0;
jl_raise(jl_interrupt_exception);
}
}

static void jl_get_builtin_hooks();

void *jl_dl_handle;
Expand Down Expand Up @@ -158,6 +177,15 @@ void julia_init(char *imageFile)
exit(1);
}

memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = sigint_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGINT, &act, NULL) < 0) {
ios_printf(ios_stderr, "sigaction: %s\n", strerror(errno));
exit(1);
}

#ifdef JL_GC_MARKSWEEP
jl_gc_enable();
#endif
Expand Down Expand Up @@ -299,6 +327,8 @@ void jl_get_builtin_hooks()
jl_apply((jl_function_t*)global("DivideByZeroError"), NULL, 0);
jl_undefref_exception =
jl_apply((jl_function_t*)global("UndefRefError"),NULL,0);
jl_interrupt_exception =
jl_apply((jl_function_t*)global("InterruptException"),NULL,0);

jl_append_any_func = (jl_function_t*)global("append_any");
jl_method_missing_func = (jl_function_t*)global("method_missing");
Expand Down
20 changes: 19 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ extern jl_struct_type_t *jl_uniontoocomplex_type;
extern jl_value_t *jl_stackovf_exception;
extern jl_value_t *jl_divbyzero_exception;
extern jl_value_t *jl_undefref_exception;
extern jl_value_t *jl_interrupt_exception;
extern jl_value_t *jl_an_empty_cell;

extern jl_struct_type_t *jl_box_type;
Expand Down Expand Up @@ -796,7 +797,22 @@ void *alloc_4w();
#define jl_gc_n_preserved_values() (0)
#endif

// tasks
// asynch signal handling

#include <signal.h>

extern volatile sig_atomic_t signal_pending;
extern volatile sig_atomic_t defer_signal;

#define JL_SIGATOMIC_BEGIN() (defer_signal++)
#define JL_SIGATOMIC_END() \
do { \
defer_signal--; \
if (defer_signal == 0 && signal_pending != 0) \
raise(signal_pending); \
} while(0)

// tasks and exceptions

// context that needs to be restored around a try block
typedef struct _jl_savestate_t {
Expand Down Expand Up @@ -850,6 +866,7 @@ DLLEXPORT jl_array_t *jl_readuntil(ios_t *s, uint8_t delim);

static inline void jl_eh_restore_state(jl_savestate_t *ss)
{
JL_SIGATOMIC_BEGIN();
jl_current_task->state.eh_task = ss->eh_task;
jl_current_task->state.eh_ctx = ss->eh_ctx;
jl_current_task->state.ostream_obj = ss->ostream_obj;
Expand All @@ -858,6 +875,7 @@ static inline void jl_eh_restore_state(jl_savestate_t *ss)
#ifdef JL_GC_MARKSWEEP
jl_current_task->state.gcstack = ss->gcstack;
#endif
JL_SIGATOMIC_END();
}

DLLEXPORT void jl_enter_handler(jl_savestate_t *ss, jmp_buf *handlr);
Expand Down
14 changes: 14 additions & 0 deletions src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,19 @@ static void ctx_switch(jl_task_t *t, jmp_buf *where)
{
if (t == jl_current_task)
return;
/*
making task switching interrupt-safe is going to be challenging.
we need JL_SIGATOMIC_BEGIN in jl_enter_handler, and then
JL_SIGATOMIC_END after every JL_TRY setjmp that returns zero.
also protect jl_eh_restore_state.
then we need JL_SIGATOMIC_BEGIN at the top of this function (ctx_switch).
the JL_SIGATOMIC_END at the end of this function handles the case
of task switching with yieldto().
then we need to handle the case of task switching via raise().
to do that, the top of every catch block must do JL_SIGATOMIC_END
*IF AND ONLY IF* throwing the exception involved a task switch.
*/
//JL_SIGATOMIC_BEGIN();
if (!setjmp(jl_current_task->ctx)) {
#ifdef COPY_STACKS
jl_task_t *lastt = jl_current_task;
Expand All @@ -254,6 +267,7 @@ static void ctx_switch(jl_task_t *t, jmp_buf *where)
longjmp(*where, 1);
#endif
}
//JL_SIGATOMIC_END();
}

static jl_value_t *switchto(jl_task_t *t)
Expand Down

0 comments on commit be5f581

Please sign in to comment.