Commit 2c04e70d authored by Camil Staps's avatar Camil Staps 🍃

Merge branch 'fix-segfault-recovery' into 'master'

Fix deadlock in signal handler for segmentation fault recovery (includes cleanup)

See merge request !105
parents b456c0b8 cbac1b4e
Pipeline #23182 passed with stages
in 12 minutes and 59 seconds
......@@ -80,9 +80,6 @@ interworking-GraphCopy:
- cd test
- make -B test-GraphTest
- CFLAGS='-DCOMPUTED_GOTOS -Ofast -fno-unsafe-math-optimizations' make -B test-GraphTest
# For some reason, this test can get stuck during running. I cannot reproduce this locally.
retry:
max: 2
interworking-GraphCopy-clang:
extends: .base
......@@ -92,9 +89,6 @@ interworking-GraphCopy-clang:
- cd test
- make -B test-GraphTest
- CFLAGS='-DCOMPUTED_GOTOS -Ofast -fno-unsafe-math-optimizations' make -B test-GraphTest
# For some reason, this test can get stuck during running. I cannot reproduce this locally.
retry:
max: 2
examples:
extends: .base
......
......@@ -85,6 +85,8 @@ deserialize_strict dsets graph thisexe w = case deserialize` True dsets graph th
deserialize` :: !Bool !DeserializationSettings !SerializedGraph !String !*World -> *(Maybe a, !*World)
deserialize` strict dsets {graph,descinfo,modules,bytecode} thisexe w
| not ensure_interpreter_init = abort "internal error in deserialize`\n"
# (host_syms,w) = accFiles (read_symbols thisexe) w
# pgm = parse host_syms bytecode
......@@ -163,6 +165,7 @@ where
get_start_rule_as_expression :: !DeserializationSettings !String !String !*World -> *(Maybe a, !*World)
get_start_rule_as_expression dsets filename prog w
| not ensure_interpreter_init = abort "internal error in get_start_rule_as_expression\n"
# (syms,w) = accFiles (read_symbols prog) w
# (bc,w) = readFile filename w
| isNothing bc = (Nothing, w)
......
......@@ -9,6 +9,7 @@ from _SystemArray import class Array
from StdMaybe import :: Maybe
from symbols_in_program import :: Symbol
ensure_interpreter_init :: Bool
parse :: !{#Symbol} !String -> Maybe Int
new_parser :: !{#Symbol} -> Int
new_string_char_provider :: !String -> Int
......
......@@ -27,6 +27,11 @@ import code from library "ucrtbase_library"
OFFSET_PARSER_PROGRAM :== IF_INT_64_OR_32 8 4 // Offset to the program field in the parser struct (parse.h)
ensure_interpreter_init :: Bool
ensure_interpreter_init = code {
ccall ensure_interpreter_init ":I"
}
parse :: !{#Symbol} !String -> Maybe Int
parse syms s
#! cp = new_string_char_provider s
......
......@@ -72,7 +72,6 @@ struct interpretation_environment *build_interpretation_environment(
#if DEBUG_CLEAN_LINKS > 0
EPRINTF("Building interpretation_environment %p\n",ie);
#endif
install_interpreter_segv_handler();
return ie;
}
......
......@@ -79,7 +79,7 @@ BC_WORD static_characters[512];
#endif
BC_WORD static_booleans[4];
void prepare_static_nodes(void) {
static void prepare_static_nodes(void) {
static_booleans[2]=static_booleans[0]=(BC_WORD)&BOOL+2;
static_booleans[1]=0;
static_booleans[3]=1;
......@@ -100,10 +100,10 @@ void prepare_static_nodes(void) {
# include "copy_host_to_interpreter.h"
void **HOST_NODES[32] = {NULL};
BC_WORD HOST_NODE_DESCRIPTORS[1216];
BC_WORD ADD_ARG[33];
static BC_WORD ADD_ARG[33];
BC_WORD HOST_NODE_INSTRUCTIONS[32*6];
void build_host_nodes(void) {
static void build_host_nodes(void) {
if (HOST_NODES[0] != NULL)
return;
int i = 0;
......@@ -229,10 +229,6 @@ BC_WORD Fjmp_ap[32] =
, Cjmp_ap32
};
BC_WORD *g_asp, *g_bsp, *g_hp;
BC_WORD_S g_heap_free;
int trap_needs_gc = 0;
void* __interpreter_cycle_in_spine[2] = {
(void*) 0,
(void*) Chalt
......@@ -312,7 +308,7 @@ void install_interpreter_segv_handler(void) {
struct sigaction segv_handler;
segv_handler.sa_sigaction=handle_segv;
sigemptyset(&segv_handler.sa_mask);
segv_handler.sa_flags=SA_ONSTACK | SA_SIGINFO;
segv_handler.sa_flags=SA_ONSTACK | SA_SIGINFO | SA_RESTART;
if (sigaction(SIGSEGV, &segv_handler,
# ifdef LINK_CLEAN_RUNTIME
&old_segv_handler
......@@ -332,6 +328,50 @@ void install_interpreter_segv_handler(void) {
void *instruction_labels[CMAX]={NULL};
#endif
static int interpreter_initialized=0;
int ensure_interpreter_init(void) {
if (interpreter_initialized)
return 1;
install_interpreter_segv_handler();
prepare_static_nodes();
#ifdef LINK_CLEAN_RUNTIME
build_host_nodes();
#endif
#ifdef COMPUTED_GOTOS
/* Fetch label addresses */
if (instruction_labels[0]==NULL) {
interpret(NULL,
# ifdef LINK_CLEAN_RUNTIME
0,
# endif
NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
for (int i=0; i<32; i++)
Fjmp_ap[i]=(BC_WORD)instruction_labels[Fjmp_ap[i]];
__interpreter_cycle_in_spine[1]=(void*)instruction_labels[(BC_WORD)__interpreter_cycle_in_spine[1]];
__interpreter_indirection[0]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[0]];
__interpreter_indirection[1]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[1]];
__interpreter_indirection[2]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[2]];
__interpreter_indirection[3]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[3]];
__interpreter_indirection[5]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[5]];
__interpreter_indirection[7]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[7]];
__interpreter_indirection[8]=(void*)instruction_labels[(BC_WORD)__interpreter_indirection[8]];
# ifdef LINK_CLEAN_RUNTIME
for (int i = 0; i < 32; i++)
HOST_NODES[i][1]=instruction_labels[Cjsr_eval_host_node+i];
# endif
}
#endif
interpreter_initialized=1;
return 1;
}
int interpret(
#ifdef LINK_CLEAN_RUNTIME
struct interpretation_environment *ie,
......@@ -344,9 +384,18 @@ int interpret(
BC_WORD *_asp, BC_WORD *_bsp, BC_WORD *_csp, BC_WORD *_hp,
BC_WORD *_pc) {
#ifdef COMPUTED_GOTOS
if (stack == NULL) { /* See rationale in interpret.h */
if (instruction_labels[0] != NULL)
return 0;
/* When compiled with COMPUTED_GOTOS defined and stack=NULL, this function does
* not interpret at all but instead copy an array with label addresses to the
* instruction_labels array defined above. If anybody other than John (who,
* we're sure, will immediately understand) ever reads this, here is the
* rationale: with computed gotos, we want to store pointers to the label
* addresses in interpret_instructions.h instead of the bytecode values of the
* instructions themselves. However, compilers won't allow you to get a label
* address from outside a function (which is kind of silly). So, we call
* interpret(.., NULL, ..) from the parser to get an array with all the
* addresses needed.
*/
if (stack == NULL) {
# define _COMPUTED_GOTO_LABELS
# include "abc_instructions.h"
memcpy(instruction_labels, _instruction_labels, sizeof(BC_WORD) * CMAX);
......@@ -393,14 +442,14 @@ int interpret(
}
#endif
BC_WORD ret;
if (_pc != NULL) {
BC_WORD *ret=safe_malloc(sizeof(BC_WORD));
#ifdef COMPUTED_GOTOS
*ret=(BC_WORD)&&eval_to_hnf_return;
ret=(BC_WORD)&&eval_to_hnf_return;
#else
*ret=EVAL_TO_HNF_LABEL;
ret=EVAL_TO_HNF_LABEL;
#endif
*++csp=(BC_WORD)ret;
*++csp=(BC_WORD)&ret;
pc=_pc;
if (0) {
......@@ -563,6 +612,8 @@ int main(int argc, char **argv) {
}
}
ensure_interpreter_init();
struct char_provider cp;
new_file_char_provider(&cp, input);
int res = parse_program(&state, &cp);
......@@ -592,8 +643,6 @@ int main(int argc, char **argv) {
BC_WORD *bsp = &stack[stack_size];
BC_WORD *csp = &stack[stack_size >> 1];
install_interpreter_segv_handler();
#ifdef DEBUG_CURSES
init_debugger(state.program, stack, asp, bsp, csp, heap, heap_size);
#endif
......
......@@ -71,20 +71,14 @@ extern void* REAL[];
extern BC_WORD small_integers[];
extern BC_WORD static_characters[];
extern BC_WORD static_booleans[];
void prepare_static_nodes(void);
#ifdef LINK_CLEAN_RUNTIME
#include "copy_interpreter_to_host.h"
void build_host_nodes(void);
extern void **HOST_NODES[32];
extern BC_WORD HOST_NODE_DESCRIPTORS[1216];
extern BC_WORD HOST_NODE_INSTRUCTIONS[32*6];
#endif
extern BC_WORD *g_asp, *g_bsp, *g_hp;
extern BC_WORD_S g_heap_free;
extern int trap_needs_gc;
extern BC_WORD Fjmp_ap[32];
extern void* __interpreter_cycle_in_spine[2];
......@@ -92,8 +86,6 @@ extern void* __interpreter_indirection[9];
#define A_STACK_CANARY 0x87654321 /* random value to check whether the A-stack overflew */
void install_interpreter_segv_handler(void);
#ifdef COMPUTED_GOTOS
# include "abc_instructions.h"
extern void *instruction_labels[CMAX];
......@@ -112,21 +104,6 @@ extern void *instruction_labels[CMAX];
* node:
* - Pointer to a node to evaluate to HNF;
* - NULL if we should just start running at code[0].
*
* HOWEVER, when compiled with COMPUTED_GOTOS defined and stack=NULL, do not
* interpret at all but instead copy an array with label addresses to the
* instruction_labels array defined above. If anybody other than John (who,
* we're sure, will immediately understand) ever reads this, here is the
* rationale: with computed gotos, we want to store pointers to the label
* addresses in interpret_instructions.h instead of the bytecode values of the
* instructions themselves. However, compilers won't allow you to get a label
* address from outside a function (which is kind of silly). So, we call
* interpret(.., NULL, ..) from the parser to get an array with all the
* addresses needed. Why not just with an extra NULLable argument? Well, this
* function is called from Clean, which doesn't have a preprocessor so that the
* function signature has to be the same, whether we compile with or without
* computed gotos. Also, this implementation is faster, which is important for
* efficient lazy interpretation.
*/
int interpret(
#ifdef LINK_CLEAN_RUNTIME
......
......@@ -193,40 +193,6 @@ int parse_program(struct parser *state, struct char_provider *cp) {
int32_t elem32;
int64_t elem64;
#ifdef INTERPRETER
prepare_static_nodes();
#endif
#ifdef LINK_CLEAN_RUNTIME
build_host_nodes();
#endif
#ifdef COMPUTED_GOTOS
/* See rationale in interpret.h */
if (instruction_labels[0]==NULL) {
interpret(NULL,
#ifdef LINK_CLEAN_RUNTIME
0,
#endif
NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
for (int i=0; i<32; i++)
Fjmp_ap[i]=(BC_WORD)instruction_labels[Fjmp_ap[i]];
__interpreter_cycle_in_spine[1] = (void*) instruction_labels[(BC_WORD)__interpreter_cycle_in_spine[1]];
__interpreter_indirection[0] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[0]];
__interpreter_indirection[1] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[1]];
__interpreter_indirection[2] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[2]];
__interpreter_indirection[3] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[3]];
__interpreter_indirection[5] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[5]];
__interpreter_indirection[7] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[7]];
__interpreter_indirection[8] = (void*) instruction_labels[(BC_WORD)__interpreter_indirection[8]];
# ifdef LINK_CLEAN_RUNTIME
for (int i = 0; i < 32; i++)
HOST_NODES[i][1] = instruction_labels[Cjsr_eval_host_node+i];
# endif
}
#endif
while (state->state != PS_end) {
switch (state->state) {
case PS_init:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment