No need for a special out of memory function -- it's just a kind of
fatal error. Also make fatal_error() call dump_memory_layout() for
easier debugging.
save_image() shouldn't throw exceptions because if the 'then_die'
argument is t it would leave factor in an inconsistent state. So
therefore move_file() should be fixed and raw_fclose() called instead of
safe_fclose().
In vm/compaction.cpp I rescoped some variables to lower the stack usage
from 592 to 560 bytes. I wasn't very successful with this. The stack
usage is larger than it looks because methods on the structures used
take an implicit this pointer and a reference to the data (so the data
has to live out it's full scope and can't be put in a register).
In vm/debug.cpp I made a large (1024 bytes) stack allocated buffer
simply dynamically allocated.
In vm/os-unix.cpp I rescoped signal handling structures to not coincide
with each other and reduced a very large (1024 bytes) amount of stack
usage to less than 500 bytes.
clang-format doesn't recognize casts to non-pointer/non-template types
so it winds up adding a space between the right paren and the expression
and then failing to recognize prefix operators in the process
(e.g. foo = (cell) & bar; should be foo = (cell)&bar;). This commit
manually fixes up the major cases (fixnum, cell, all types ending in _t).
Factor is finally a real C++ project and has a custom assert macro. Assertion failures were still getting caught as exceptions and causing failure loops. Write our own macro that calls factor::abort on failure.
* Clear faulting_p from a safepoint rather than inside general_error, because jumping into unwind-native-frames could blow up.
* Handle multiple faults from fatal_error by breakpointing. Is there anything else we can safely do at that point?
* Verify memory protection faults in the top half of the signal handlers because signal dispatch could fault. Treat memory faults during gc or fep as fatal errors.
* Add a function factor_vm::abort() that restores the default SIGABRT handler and ::abort()s. Use it from fatal_error() so we get useful context from gdb and so the user gets feedback from the system crash reporter that Factor blew up and didn't just disappear.
* In factorbug(), don't proceed with .s .r .c if it would be unsafe to do so.
* Don't pile on signals if we've already called fatal_error().
This gives us an escape hatch for when things go way south and ^C can't be handled. Also unmask SIGQUIT and SIGTERM from the stdin_loop thread so the thread doesn't keep the process alive after those signals.
The stdin_loop thread will keep trying to consume input unless we stop it by sending it a signal. Use SIGUSR2 to stop the read syscall and a mutex to hold up the loop while the fep is active.
Although SIGINT still can't interrupt the current Factor thread in a sane way, this will at least wake up the run loop when waiting for input and fix#348 when implemented at the application level.