# New Ticket Created by Leopold Toetsch # Please include the string: [perl #23039] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=23039 >
OK here it is. Again the description for the record: 1) Initialization: - normal core: build op_func_table with all opcode #4 [1] - CG core: build ops_addr[] filled with this opcode - prederef cores: build a list of (backward) branch instructions and the opcode at that offset 2) When an events gets scheduled (signal handler) it calls the running core with: interpreter->op_func_table = init_func(interpreter, OPLIB_SET_CHK_EV_FT)->op_func_table; This replaces for normal and CG core the op_func_table or the ops_addr with that from 1) Prederefed cores get on all branch instruction from the list built in 1) an opcode #4 patched. 3) So when the next instruction (normal, CG core) or the branch instruction (prederefed cores) gets executed, first the op_func_table or the patched instructions are restored and then the event handler can be called. This now works for all cores (except JIT[2]). It doesn't have any runtime penalty for an extra check if events are due. [1] This opcode (check_event__) calls the actual event handling code and returns the same address, i.e. doesn't advance the PC. [2] We could do the same here, but this needs cache sync for ARM and PPC, which may or may not be allowed in signal code. Still needs some cleanup ... leo -- attachment 1 ------------------------------------------------------ url: http://rt.perl.org/rt2/attach/61323/45267/aa640c/event handling-2.patch
--- parrot/classes/timer.pmc Thu Jul 17 15:46:23 2003 +++ parrot-leo/classes/timer.pmc Thu Jul 17 17:55:17 2003 @@ -54,6 +54,7 @@ * for now we keep all stuff inside the pmc */ +void do_alarm_handler(void); /* XXX s. events.c */ /* interface constants */ /* &gen_from_enum(timer.pasm) */ typedef enum { @@ -203,7 +204,7 @@ stop_sys_timer_ms(handle); } -static void +void do_alarm_handler(void) { parrot_timer_t *t; @@ -211,6 +212,8 @@ int recalc = 0; ms = get_sys_timer_ms(handle); + if (!ms) /* no timer running */ + return; for (t = rtimer; t; t = t->next) { if (!--t->ticks) { t->state = TIMER_STATE_FIRE; --- parrot/config/gen/config_h/config_h.in Sun Mar 16 12:12:04 2003 +++ parrot-leo/config/gen/config_h/config_h.in Fri Jul 18 13:33:42 2003 @@ -106,7 +106,11 @@ #define PARROT_CORE_OPLIB_NAME "core" #define PARROT_CORE_OPLIB_INIT Parrot_DynOp_core_${MAJOR}_${MINOR}_${PATCH} + #define PARROT_CORE_PREDEREF_OPLIB_INIT Parrot_DynOp_core_prederef_${MAJOR}_${MINOR}_${PATCH} +#define PARROT_CORE_SWITCH_OPLIB_INIT Parrot_DynOp_core_switch_${MAJOR}_${MINOR}_${PATCH} +#define PARROT_CORE_CG_OPLIB_INIT Parrot_DynOp_core_cg_${MAJOR}_${MINOR}_${PATCH} +#define PARROT_CORE_CG_OPLIB_INIT Parrot_DynOp_core_cg_${MAJOR}_${MINOR}_${PATCH} #define PARROT_CORE_CGP_OPLIB_INIT Parrot_DynOp_core_cgp_${MAJOR}_${MINOR}_${PATCH} #define INTVAL_FMT "${intvalfmt}" --- parrot/core.ops Fri Jul 18 07:34:06 2003 +++ parrot-leo/core.ops Fri Jul 18 16:41:24 2003 @@ -97,7 +97,7 @@ } inline op check_events__() { - opcode_t *this = CUR_OPCODE; + opcode_t *this = CUR_OPCODE; /* repeat the same opcode */ HANDLE_EVENTS(interpreter); goto ADDRESS(this); /* force this being a branch op */ } --- parrot/events.c Sun Jul 13 17:54:46 2003 +++ parrot-leo/events.c Fri Jul 18 16:41:19 2003 @@ -15,30 +15,76 @@ #ifdef HAS_HEADER_SETJMP /* XXX s. exceptions.c */ void do_exception(exception_severity severity, long error); -void Parrot_init_signals(void); #endif +void do_alarm_handler(void); /* XXX s. timer.c */ + +void Parrot_init_signals(Parrot_Interp); +static Parrot_Interp the_interpreter; + +void +Parrot_do_handle_events(Parrot_Interp interpreter) +{ + oplib_init_f init_func = interpreter->op_init_func; + interpreter->op_func_table = + init_func(interpreter, OPLIB_INIT)->op_func_table; + if (interpreter->has_events) { + fprintf(stderr, "got event\n"); + --interpreter->has_events; + /* TODO pop event off the event queue */ + /* case SIGALRM: */ + do_alarm_handler(); + } +} + +/* synchronous event checker from check_event opcode */ +void +Parrot_do_check_events(Parrot_Interp interpreter) +{ +} + +/* + * next 2 are interrupt code + */ + +static void +enable_event_checker(Parrot_Interp interpreter) { + oplib_init_f init_func = interpreter->op_init_func; + interpreter->op_func_table = + init_func(interpreter, OPLIB_SET_CHK_EV_FT)->op_func_table; +} + +#if defined(HAS_HEADER_SIGNAL) && defined(SIGFPE) && defined(SIGALRM) static void sig_handler(int signum) { switch (signum) { - default: -#ifdef HAS_HEADER_SETJMP - /* quick hack to test signals and exceptions - */ + /* can't return from that */ + case SIGFPE: do_exception(0, -signum); -#endif + break; + /* convert signal to an event */ + default: + ++the_interpreter->has_events; + /* TODO place event in event queue */ + enable_event_checker(the_interpreter); + fprintf(stderr, "got signal\n"); break; } } +#endif + void -Parrot_init_signals(void) +Parrot_init_signals(Parrot_Interp interpreter) { - /* quick hack to test signals and exceptions - * s. t/op/hacks_4.pasm - */ - /* Parrot_set_sighandler(SIGFPE, sig_handler);*/ + /* XXX actually the interpreter, that receives signals */ + the_interpreter = interpreter; +#if defined(HAS_HEADER_SIGNAL) && defined(SIGFPE) && defined(SIGALRM) + Parrot_set_sighandler(SIGFPE, sig_handler); + Parrot_set_sighandler(SIGALRM, sig_handler); + /* Parrot_set_sighandler(SIGINT, sig_handler); */ +#endif } /* --- parrot/exceptions.c Wed Jul 16 22:00:36 2003 +++ parrot-leo/exceptions.c Thu Jul 17 11:28:22 2003 @@ -194,7 +194,7 @@ /* translate an absolute location in byte_code to an offset * used for resuming after an exception had occured */ - switch (interpreter->flags) { + switch (interpreter->flags & PARROT_PREDEREF_FLAG) { case PARROT_PREDEREF_FLAG: offset = (void **)dest - interpreter->prederef_code; default: --- parrot/include/parrot/events.h Tue Jul 15 11:40:06 2003 +++ parrot-leo/include/parrot/events.h Thu Jul 17 11:47:04 2003 @@ -13,10 +13,14 @@ #if !defined(PARROT_EVENT_H_GUARD) #define PARROT_EVENT_H_GUARD -#define CHECK_EVENTS(x) -#define HANDLE_EVENTS(x) +#define CHECK_EVENTS(x) \ + if (x->has_events) \ + Parrot_do_check_events(x) +#define HANDLE_EVENTS(x) Parrot_do_handle_events(x) -void Parrot_init_signals(void); +void Parrot_init_signals(struct Parrot_Interp *); +void Parrot_do_check_events(struct Parrot_Interp *); +void Parrot_do_handle_events(struct Parrot_Interp *); #endif --- parrot/include/parrot/interpreter.h Wed Jul 16 22:00:37 2003 +++ parrot-leo/include/parrot/interpreter.h Fri Jul 18 12:57:43 2003 @@ -29,7 +29,9 @@ PARROT_GC_DEBUG_FLAG = 0x80, /* We're debugging memory management */ PARROT_EXTERN_CODE_FLAG = 0x100, /* reusing anothers interps code */ PARROT_SWITCH_FLAG = 0x200, /* We're using the switched runops */ - PARROT_DESTROY_FLAG = 0x400 /* the last interpreter shall cleanup */ + PARROT_DESTROY_FLAG = 0x400, /* the last interpreter shall cleanup */ + PARROT_RUN_CORE_FLAGS= 0x270 /* flags denoting run core */ + } Parrot_Interp_flag; /* &end_gen */ @@ -115,6 +117,7 @@ op_info_t *op_info_table; /* Opcode info table (name, nargs, arg types) */ op_func_t *op_func_table; + oplib_init_f op_init_func; #if 0 str_func_t *string_funcs; @@ -134,6 +137,7 @@ /* the next items point to the real thngs, which are * in the byte_code_segment, that is currently executed */ void **prederef_code; /* The predereferenced code */ + size_t *prederef_branches; /* list of branch ops offsets in above */ void *jit_info; /* JITs data */ size_t current_line; /* Which line we're executing in the * source */ @@ -181,6 +185,8 @@ /* 3: PMC *Env; hash_like Env PMC */ /* 4: PMC *ParrotInterpreter that's me */ int has_early_DOD_PMCs; /* Flag that some want immediate destruction */ + volatile int has_events; /* something arrived in the event queue */ + struct QUEUE *event_queue; /* the event queues */ } Interp; /* &gen_from_enum(iglobals.pasm) */ @@ -233,6 +239,7 @@ void Parrot_compreg(Parrot_Interp interpreter, STRING *type, PMC *func); INTVAL sysinfo_i(Parrot_Interp interpreter, INTVAL info_wanted); STRING *sysinfo_s(Parrot_Interp interpreter, INTVAL info_wanted); +void turn_ev_check(Parrot_Interp interpreter, int on, int flag); #endif /* Parrot core */ --- parrot/include/parrot/oplib.h Fri Jan 17 21:41:38 2003 +++ parrot-leo/include/parrot/oplib.h Fri Jul 18 09:31:47 2003 @@ -29,11 +29,18 @@ size_t op_count; op_info_t * op_info_table; void * op_func_table; + void * orig_func_table; + void * check_func_table; int (*op_code)(const char * name, int full); } op_lib_t; -/* when init = true initialize, else de_initialize */ -typedef op_lib_t *(*oplib_init_f)(int init); +typedef op_lib_t *(*oplib_init_f)(struct Parrot_Interp*, int init); +/* init may have these values: */ +typedef enum { + OPLIB_DEINIT, /* cleanup */ + OPLIB_INIT, /* initialize, set std. func_table */ + OPLIB_SET_CHK_EV_FT /* set all op functions to the event checker */ +} oplib_init_enum_t; #endif --- parrot/interpreter.c Wed Jul 16 22:00:36 2003 +++ parrot-leo/interpreter.c Fri Jul 18 15:53:13 2003 @@ -58,7 +58,7 @@ if (!init_func) internal_exception(1, "Invalid oplib, '%s' not exported\n", init_func_name); - oplib = init_func(1); + oplib = init_func(interpreter, OPLIB_INIT); /* XXX now what * if oplib is a prederefed oplib, and matches the current * oplib, we would run it */ @@ -109,6 +109,7 @@ for (i = 0; i < opinfo->arg_count; i++) { switch (opinfo->types[i]) { case PARROT_ARG_OP: + if (prederef_op_func) pc_prederef[i] = (void *)(ptrcast_t)prederef_op_func[pc[i]]; break; @@ -162,12 +163,6 @@ "Unhandled argtype %d\n",opinfo->types[i]); break; } - - if (pc_prederef[i] == 0) { - internal_exception(INTERP_ERROR, - "Prederef generated a NULL pointer for arg of type %d!\n", - opinfo->types[i]); - } } return pc_prederef; @@ -185,15 +180,18 @@ init_prederef(struct Parrot_Interp *interpreter, int cgp) { #ifdef HAVE_COMPUTED_GOTO - oplib_init_f init_func = cgp ? - PARROT_CORE_CGP_OPLIB_INIT : - PARROT_CORE_PREDEREF_OPLIB_INIT; + oplib_init_f init_func = + cgp == PREDEREF_FOR_SWITCH ? PARROT_CORE_SWITCH_OPLIB_INIT : + cgp ? PARROT_CORE_CGP_OPLIB_INIT : PARROT_CORE_PREDEREF_OPLIB_INIT; #else - oplib_init_f init_func = PARROT_CORE_PREDEREF_OPLIB_INIT; - UNUSED(cgp); + oplib_init_f init_func = + cgp == PREDEREF_FOR_SWITCH ? PARROT_CORE_SWITCH_OPLIB_INIT : + PARROT_CORE_PREDEREF_OPLIB_INIT; #endif - interpreter->op_lib = init_func(1); - interpreter->op_lib->op_code = PARROT_CORE_OPLIB_INIT(1)->op_code; + interpreter->op_lib = init_func(interpreter, OPLIB_INIT); + interpreter->op_init_func = init_func; + interpreter->op_lib->op_code = + PARROT_CORE_OPLIB_INIT(interpreter, OPLIB_INIT)->op_code; if (interpreter->op_lib->op_count != interpreter->op_count) internal_exception(PREDEREF_LOAD_ERROR, "Illegal op count (%d) in prederef oplib\n", @@ -203,39 +201,91 @@ size_t i; void **temp = (void **)Parrot_memalign_if_possible(256, N * sizeof(void *)); + size_t branch_list_size = N / 16; /* estimated size */ + /* TODO branches per code segment like prederef code */ + size_t *branches = mem_sys_allocate(branch_list_size * sizeof(size_t)); + size_t n_branches = 0; - for (i = 0; i < N; i++) { - temp[i] = (void *)(ptrcast_t)prederef; - } + opcode_t *pc = interpreter->code->cur_cs->base.data; + op_info_t *op_info; interpreter->prederef_code = temp; + interpreter->prederef_branches = branches; interpreter->code->cur_cs->prederef_code = temp; - if (cgp == PREDEREF_FOR_SWITCH) { - opcode_t *pc = interpreter->code->cur_cs->base.data; - size_t n; for (i = 0; i < N; ) { + size_t n; + /* prederef immediately all code */ prederef(temp, interpreter); + if (cgp == PREDEREF_FOR_SWITCH) { *temp = (void**) *pc; - n = interpreter->op_info_table[*pc].arg_count; - pc += n; - i += n; - temp += n; - } } #ifdef HAVE_COMPUTED_GOTO - if (cgp == PREDEREF_FOR_CGP) { - opcode_t *pc = interpreter->code->cur_cs->base.data; - size_t n; - for (i = 0; i < N; ) { - prederef(temp, interpreter); + else if (cgp == PREDEREF_FOR_CGP) { *temp = ((void**)(interpreter->op_lib->op_func_table)) [*pc]; - n = interpreter->op_info_table[*pc].arg_count; + } + op_info = &interpreter->op_info_table[*pc]; + n = op_info->arg_count; + /* if this is a backward branch, remember its position in + * the prederef code for event checking + */ + if ((op_info->jump & PARROT_JUMP_RELATIVE) && + op_info->types[n - 1] == PARROT_ARG_IC && + pc[n - 1] < 0) { + if (n_branches >= branch_list_size - 2) { + branch_list_size *= 1.5; + branches = mem_sys_realloc(branches, + branch_list_size * sizeof(size_t)); + } + /* location and opcode pairs */ + branches[n_branches++] = i; + branches[n_branches++] = (size_t)(*temp); + } pc += n; i += n; temp += n; +#endif } + /* mark end of list */ + branches[n_branches] = 0; + } +} + +void +turn_ev_check(Parrot_Interp interpreter, int on, int flag) +{ + size_t i, offs, code; + void *chk_op; + + if (!interpreter->prederef_branches) { + /* called from first init before init_prederef */ + return; + } + switch (flag) { + case PARROT_PREDEREF_FLAG: + case PARROT_PREDEREF_FLAG | PARROT_CGOTO_FLAG: + chk_op = ((void**)(interpreter->op_lib->op_func_table)) [4]; + break; + case PARROT_SWITCH_FLAG: + chk_op = (void *) 4; + break; + } + for (i = 0; interpreter->prederef_branches[i]; i += 2) { + offs = interpreter->prederef_branches[i]; + code = interpreter->prederef_branches[i+1]; + switch (on) { + case 0: + /* disable (or initialize) event checker: + * patch the original code at offset + */ + interpreter->prederef_code[offs] = (void *)code; + break; + default: + /* enable event checker + * THIS CODE GETS CALLED FROM INETERRUPT (signal handler) + */ + interpreter->prederef_code[offs] = chk_op; + break; } -#endif } } @@ -247,7 +297,7 @@ static void stop_prederef(struct Parrot_Interp *interpreter) { - (void) PARROT_CORE_PREDEREF_OPLIB_INIT(0); + (void) PARROT_CORE_PREDEREF_OPLIB_INIT(interpreter, OPLIB_DEINIT); } static opcode_t * @@ -405,6 +455,8 @@ /* clear stacktop, it gets set in runops_cgoto_core beyond the * opfunc table again, if the compiler supports nested funcs */ + interpreter->op_init_func = PARROT_CORE_CG_OPLIB_INIT; + interpreter->op_init_func(interpreter, OPLIB_INIT); /* #ifdef HAVE_NESTED_FUNC */ #ifdef __GNUC__ interpreter->lo_var_ptr = 0; @@ -577,7 +629,8 @@ interpreter->ctx.intstack = intstack_new(interpreter); /* Load the core op func and info tables */ - interpreter->op_lib = PARROT_CORE_OPLIB_INIT(1); + interpreter->op_lib = PARROT_CORE_OPLIB_INIT(interpreter, OPLIB_INIT); + interpreter->op_init_func = PARROT_CORE_OPLIB_INIT; interpreter->op_count = interpreter->op_lib->op_count; interpreter->op_func_table = interpreter->op_lib->op_func_table; interpreter->op_info_table = interpreter->op_lib->op_info_table; @@ -614,7 +667,7 @@ Parrot_unblock_GC(interpreter); /* all sys running, init the signal stuff */ - Parrot_init_signals(); + Parrot_init_signals(interpreter); #ifdef ATEXIT_DESTROY Parrot_on_exit(Parrot_really_destroy, (void*)interpreter); @@ -682,7 +735,7 @@ mem_sys_free(interpreter->profile); /* deinit op_lib */ - (void) PARROT_CORE_OPLIB_INIT(0); + (void) PARROT_CORE_OPLIB_INIT(interpreter, OPLIB_DEINIT); /* XXX move this to register.c */ { --- parrot/ops2c.pl Sun May 18 18:03:32 2003 +++ parrot-leo/ops2c.pl Fri Jul 18 12:21:39 2003 @@ -110,6 +110,17 @@ # Print the preamble for the HEADER and SOURCE files: # +my $core_enum_flag; +if ($suffix eq '_cgp') { + $core_enum_flag = 'PARROT_PREDEREF_FLAG | PARROT_CGOTO_FLAG'; +} +elsif ($suffix eq '_prederef') { + $core_enum_flag = 'PARROT_PREDEREF_FLAG'; +} +elsif ($suffix eq '_switch') { + $core_enum_flag = 'PARROT_SWITCH_FLAG'; +} + my $preamble = <<END_C; /* * !!!!!!! DO NOT EDIT THIS FILE !!!!!!! @@ -123,12 +134,13 @@ END_C + print HEADER $preamble; print HEADER <<END_C; #include "parrot/parrot.h" #include "parrot/oplib.h" -extern op_lib_t *Parrot_DynOp_${base}${suffix}_${major_version}_${minor_version}_${patch_version}(int init); +extern op_lib_t *Parrot_DynOp_${base}${suffix}_${major_version}_${minor_version}_${patch_version}(struct Parrot_Interp *, int init); END_C my $cg_func = $suffix =~ /cgp/ ? 'cgp_' : @@ -142,6 +154,13 @@ } print SOURCE $preamble; +if ($core_enum_flag) { + print SOURCE <<END_C; +#define ENABLE_EV_CHECK(interp) turn_ev_check(interp, 1, $core_enum_flag) +#define DISABLE_EV_CHECK(interp) turn_ev_check(interp, 0, $core_enum_flag) +END_C +} + print SOURCE <<END_C; #include "$include" @@ -164,7 +183,7 @@ opcode_t *cur_opcode = cur_op; #endif - static void *ops_addr[] = { + static void *rops_addr[] = { END_C } elsif ($suffix =~ /switch/) { @@ -267,8 +286,15 @@ NULL }; + static void **ops_addr = rops_addr; + /* #ifdef HAVE_NESTED_FUNC */ #ifdef __GNUC__ + /* + * this nested function is here to reduce the size of + * trace_system_stack - gcc has somewhere the jumptable + * in a stack frame + */ static void _check(void); static void _check(void) { int lo_var_ptr; @@ -277,13 +303,20 @@ } #endif /* #endif */ + + if (cur_opcode == 0) { + /* set and report the default branch table */ + return (opcode_t *)ops_addr = rops_addr; + } + else if (interpreter == (struct Parrot_Interp *) 1) { + /* set branch table to the passed address */ + ops_addr = (void **)cur_opcode; + return cur_opcode; + } END_C } - if ($suffix =~ /cgp/) { print SOURCE <<END_C; - if (cur_opcode == 0) - return (opcode_t *)ops_addr; #ifdef __GNUC__ # ifdef I386 else if (cur_opcode == (opcode_t *) 1) @@ -553,28 +586,91 @@ $num_ops, $op_info, $op_func, + $op_func, + NULL, $getop }; op_lib_t * -Parrot_DynOp_${base}${suffix}_${major_version}_${minor_version}_${patch_version}(int init) { - if (init) { - +Parrot_DynOp_${base}${suffix}_${major_version}_${minor_version}_${patch_version}(Parrot_Interp interpreter, int init) { + switch (init) { END_C -if ($suffix =~ /cgp/) { -print SOURCE <<END_C; - op_lib.op_func_table = (op_func_t *) cgp_$base(0, 0); +if ($suffix eq '_cg') { + print SOURCE <<END_C; + case OPLIB_INIT: + op_lib.op_func_table = op_lib.orig_func_table = + (op_func_t *) $cg_func$base(0, 0); + /* set all op addresses to the event checker */ + if (!op_lib.check_func_table) { + size_t i; + op_lib.check_func_table = mem_sys_allocate( + sizeof(void *) * (1 + op_lib.op_count)); + for (i = 0; i <= op_lib.op_count; i++) + ((void **)op_lib.check_func_table)[i] = + ((void **)op_lib.orig_func_table)[4]; + } + break; + case OPLIB_SET_CHK_EV_FT: + /* tell the core, to switch addr table */ + $cg_func$base(op_lib.check_func_table, (Parrot_Interp)1); + op_lib.op_func_table = op_lib.check_func_table; + break; +END_C +} +elsif ($suffix eq '_cgp') { + print SOURCE <<END_C; + case OPLIB_INIT: + op_lib.op_func_table = op_lib.orig_func_table = + (op_func_t *) $cg_func$base(0, 0); + DISABLE_EV_CHECK(interpreter); + break; + case OPLIB_SET_CHK_EV_FT: + ENABLE_EV_CHECK(interpreter); + break; +END_C +} +elsif ($suffix =~ /switch/ || $suffix eq '_prederef') { + print SOURCE <<END_C; + case OPLIB_INIT: + DISABLE_EV_CHECK(interpreter); + break; + case OPLIB_SET_CHK_EV_FT: + ENABLE_EV_CHECK(interpreter); + break; +END_C +} +else { + print SOURCE <<END_C; + case OPLIB_INIT: + op_lib.op_func_table = op_lib.orig_func_table = + op_func_table; + /* set all op functions to the event checker */ + if (!op_lib.check_func_table) { + size_t i; + op_lib.check_func_table = mem_sys_allocate( + sizeof(op_func_t) * (1 + op_lib.op_count)); + for (i = 0; i <= op_lib.op_count; i++) + ((op_func_t **)op_lib.check_func_table)[i] = + ((op_func_t **)op_lib.orig_func_table)[4]; + } + break; + case OPLIB_SET_CHK_EV_FT: + op_lib.op_func_table = op_lib.check_func_table; + break; END_C } print SOURCE <<END_C; - return &op_lib; - } - else { + case OPLIB_DEINIT: hop_deinit(); + if (op_lib.check_func_table) { + mem_sys_free(op_lib.check_func_table); + op_lib.check_func_table = NULL; + } return NULL; } + return &op_lib; } END_C --- parrot/t/op/hacks.t Sun Jul 13 20:52:59 2003 +++ parrot-leo/t/op/hacks.t Fri Jul 18 17:45:56 2003 @@ -1,6 +1,6 @@ #! perl -w -use Parrot::Test tests => 5; +use Parrot::Test tests => 6; use Test::More; use Parrot::Config; @@ -56,7 +56,7 @@ } SKIP: { -skip("no events yet", 2); +skip("no events yet", 3) unless $^O eq 'linux'; output_is(<<'CODE', <<OUT, "catch a SIGFPE"); newsub P0, .Exception_Handler, _handler @@ -100,6 +100,38 @@ CODE catched it ok +OUT + +output_is(<<'CODE', <<OUT, "SIGALRM - no event handler yet"); +.include "timer.pasm" +.include "interpflags.pasm" + getinterp P0 + set I0, P0[-1] # get flags + band I0, .INTERPFLAG_PARROT_JIT_FLAG + unless I0, core_ok + print "Yep. It fails with JIT.\n" + end +core_ok: + new P0, .Timer + set P0[.TIMER_NSEC], 0.2 + set P0[.TIMER_REPEAT], 1 + set P0[.TIMER_RUNNING], 1 # fires 2 times, 0.4 sec + time N1 + null I10 +loop: dec I10 + time N2 + sub N0, N2, N1 + gt N0, 0.5, ex + if I10, loop +ex: + printerr "fin\n" + end +CODE +got signal +got event +got signal +got event +fin OUT }