Improved signal handling.

This commit is contained in:
C. Guy Yarvin 2014-10-04 14:57:40 -07:00
parent 57d9c2ca26
commit 27c67acca4
8 changed files with 251 additions and 66 deletions

295
g/m.c
View File

@ -6,9 +6,222 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <ctype.h>
#include <sigsegv.h>
#include "all.h"
static jmp_buf Signal_u;
static c3_l Signal_l;
#ifndef SIGSTKSZ
# define SIGSTKSZ 16384
#endif
static uint8_t Sigstk[SIGSTKSZ];
void u3_unix_ef_hold(void); // suspend system signal regime
void u3_unix_ef_move(void); // restore system signal regime
extern void
u3_lo_sway(c3_l tab_l, u3_noun tax);
#if 1
/* _cm_punt(): crudely print trace.
*/
static void
_cm_punt(u3_noun tax)
{
u3_noun xat;
for ( xat = tax; xat; xat = u3t(xat) ) {
u3_cm_p("&", u3h(xat));
}
}
#endif
/* _cm_emergency(): write emergency text to stderr, never failing.
*/
static void
_cm_emergency(c3_c* cap_c, c3_l sig_l)
{
write(2, "\r\n", 2);
write(2, cap_c, strlen(cap_c));
if ( sig_l ) {
write(2, ": ", 2);
write(2, &sig_l, 4);
}
write(2, "\r\n", 2);
}
static void _cm_overflow_over(void *arg1, void *arg2, void *arg3)
{
(void)(arg1);
(void)(arg2);
(void)(arg3);
siglongjmp(Signal_u, c3__over);
}
static void _cm_overflow_dire(void *arg1, void *arg2, void *arg3)
{
(void)(arg1);
(void)(arg2);
(void)(arg3);
siglongjmp(Signal_u, c3__dire);
}
/* _cm_signal_handle(): handle a signal in general.
*/
static void
_cm_signal_handle(c3_l sig_l)
{
c3_l org_l = sig_l;
_cm_emergency("signal", sig_l);
if ( Signal_l || (u3R == &u3H->rod_u) ) {
_cm_emergency("signal overlap: old", Signal_l);
_cm_emergency("signal overlap: new", sig_l);
if ( c3__prof == sig_l ) {
// Ignore strange profiling event.
//
return;
}
sig_l = c3__dire;
}
Signal_l = sig_l;
if ( c3__over == org_l ) {
if ( c3__dire == sig_l ) {
sigsegv_leave_handler(_cm_overflow_dire, NULL, NULL, NULL);
}
else {
sigsegv_leave_handler(_cm_overflow_over, NULL, NULL, NULL);
}
}
else {
siglongjmp(Signal_u, sig_l);
}
}
static void
_cm_signal_handle_over(int emergency, stackoverflow_context_t scp)
{
_cm_signal_handle(c3__over);
}
static void
_cm_signal_handle_term(int x)
{
_cm_signal_handle(c3__term);
}
static void
_cm_signal_handle_intr(int x)
{
_cm_signal_handle(c3__intr);
}
static void
_cm_signal_handle_alrm(int x)
{
_cm_signal_handle(c3__alrm);
}
/* _cm_signal_reset(): reset top road after signal longjmp.
*/
static void
_cm_signal_reset(void)
{
u3R = &u3H->rod_u;
u3R->cap_w = u3R->mat_w;
u3R->kid_u = 0;
}
/* _cm_signal_recover(): recover from a deep signal, after longjmp.
*/
static u3_noun
_cm_signal_recover(void)
{
_cm_emergency("recover", Signal_l);
if ( c3__dire == Signal_l ) {
Signal_l = 0;
_cm_signal_reset();
return u3nt(3, c3__dire, 0);
}
else {
u3_noun tax = u3_nul;
u3_noun pro;
// Descend to the road that caused the problem - in almost all
// cases the innermost road, except for a
//
{
u3_cs_road* rod_u;
u3R = &(u3H->rod_u);
rod_u = u3R;
while ( rod_u->kid_u ) {
tax = u3_ckb_weld(u3_ca_take(rod_u->kid_u->bug.tax), tax);
rod_u = rod_u->kid_u;
}
}
_cm_signal_reset();
pro = u3nt(3, Signal_l, tax);
_cm_punt(tax);
u3_lo_sway(2, u3k(tax));
Signal_l = 0;
return pro;
}
}
/* _cm_signal_deep(): start deep processing; set timer for sec_w or 0.
*/
static void
_cm_signal_deep(c3_w sec_w)
{
u3_unix_ef_hold();
stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ);
signal(SIGINT, _cm_signal_handle_intr);
signal(SIGTERM, _cm_signal_handle_term);
if ( sec_w ) {
struct itimerval itm_u;
timerclear(&itm_u.it_interval);
itm_u.it_value.tv_sec = sec_w;
itm_u.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &itm_u, 0);
signal(SIGVTALRM, _cm_signal_handle_alrm);
}
}
/* _cm_signal_done():
*/
static void
_cm_signal_done()
{
// signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGVTALRM, SIG_IGN);
stackoverflow_deinstall_handler();
{
struct itimerval itm_u;
timerclear(&itm_u.it_interval);
timerclear(&itm_u.it_value);
setitimer(ITIMER_VIRTUAL, &itm_u, 0);
}
u3_unix_ef_move();
}
/* u3_cm_file(): load file, as atom, or bail.
*/
u3_noun
@ -178,23 +391,6 @@ u3_cm_dump(void)
}
}
#if 0
/* _cm_punt(): crudely print trace.
*/
static void
_cm_punt(void)
{
u3_noun xat;
for ( xat = u3R->bug.tax; xat; xat = u3t(xat) ) {
u3_cm_p("&", u3h(xat));
}
}
#endif
extern void
u3_lo_sway(c3_l tab_l, u3_noun tax);
/* u3_cm_bail(): bail out. Does not return.
**
** Bail motes:
@ -204,6 +400,7 @@ u3_lo_sway(c3_l tab_l, u3_noun tax);
** %oops :: assertion failure
** %intr :: interrupt
** %fail :: computability failure
** %over :: stack overflow (a kind of %fail)
** %need :: namespace block
** %meme :: out of memory
**
@ -240,7 +437,7 @@ u3_cm_bail(u3_noun how)
}
// _cm_punt();
// u3_lo_sway(2, u3k(u3R->bug.tax));
// abort();
abort();
/* Reconstruct a correct error ball.
*/
@ -426,21 +623,24 @@ u3_cm_water(c3_w* low_w, c3_w* hig_w)
/* u3_cm_soft_top(): top-level safety wrapper.
*/
u3_noun
u3_cm_soft_top(c3_w pad_w,
u3_cm_soft_top(c3_w sec_w, // timer seconds
c3_w pad_w, // base memory pad
u3_funk fun_f,
u3_noun arg)
{
u3_noun why, don, flu, tax, pro;
u3_noun why, pro;
c3_w gof_w;
/* Record all stacks; clear the trace.
/* Enter internal signal regime.
*/
{
don = u3R->pro.don;
flu = u3R->ski.flu;
tax = u3R->bug.tax;
_cm_signal_deep(0);
u3R->bug.tax = 0;
if ( 0 != sigsetjmp(Signal_u, 1) ) {
// return to blank state
//
_cm_signal_done();
return _cm_signal_recover();
}
/* Record the cap, and leap.
@ -449,23 +649,15 @@ u3_cm_soft_top(c3_w pad_w,
gof_w = u3_cm_golf();
u3_cm_leap(pad_w);
}
/* Trap for exceptions.
/* Trap for ordinary nock exceptions.
*/
if ( 0 == (why = u3_cm_trap()) ) {
pro = fun_f(arg);
u3_cm_wash(pro);
/* Test stack correctness assertions, and restore.
/* Revert to external signal regime.
*/
{
c3_assert(0 == u3R->bug.tax); // trace is clean
c3_assert(flu == u3R->ski.flu); // namespaces are clean
c3_assert(don == u3R->pro.don); // profile is clean
u3R->bug.tax = tax; // restore trace
}
_cm_signal_done();
/* Fall back to the old road, leaving temporary memory intact.
*/
@ -476,27 +668,23 @@ u3_cm_soft_top(c3_w pad_w,
pro = u3nc(0, u3_ca_take(pro));
}
else {
/* Test stack correctness assertions, and restore.
*/
{
c3_assert(flu == u3R->ski.flu); // namespaces are clean
u3R->pro.don = don; // restore profile
u3R->bug.tax = tax; // restore trace
}
/* Fall back to the old road, leaving temporary memory intact.
*/
u3_cm_fall();
/* Produce the error result.
/* Overload the error result.
*/
pro = u3_ca_take(why);
}
/* Clean up temporary memory.
*/
u3_cm_flog(gof_w);
/* Revert to external signal regime.
*/
_cm_signal_done();
/* Return the product.
*/
return pro;
@ -513,8 +701,6 @@ u3_cm_soft_run(u3_noun fly,
u3_noun why, pro;
c3_w gof_w;
printf("run: fly: %x\r\n", u3_cr_mug(fly));
u3_cm_wash(aga);
u3_cm_wash(agb);
@ -615,10 +801,6 @@ u3_cm_soft_esc(u3_noun sam)
{
c3_assert(0 != u3R->ski.flu);
fly = u3h(u3R->ski.flu);
u3_cm_p("esc: sam", sam);
printf("esc: fly: %x\r\n", u3_cr_mug(fly));
// u3_cm_p("esc: fly", fly);
}
/* Record the cap, and leap.
@ -641,9 +823,6 @@ u3_cm_soft_esc(u3_noun sam)
if ( 0 == (why = u3_cm_trap()) ) {
pro = u3_cn_slam_on(fly, sam);
u3_cm_p("esc: pro", pro);
abort();
/* Fall back to the old road, leaving temporary memory intact.
*/
u3_cm_fall();
@ -683,7 +862,7 @@ u3_cm_soft(c3_w sec_w,
u3_funk fun_f,
u3_noun arg)
{
u3_noun why = u3_cm_soft_top((1 << 17), fun_f, arg);
u3_noun why = u3_cm_soft_top(sec_w, (1 << 17), fun_f, arg); // 512K pad
u3_noun pro;
switch ( u3h(why) ) {

View File

@ -11,6 +11,7 @@
# define c3__actd c3_s4('a','c','t','d')
# define c3__add c3_s3('a','d','d')
# define c3__all c3_s3('a','l','l')
# define c3__alrm c3_s4('a','l','r','m')
# define c3__amat c3_s4('a','m','a','t')
# define c3__ames c3_s4('a','m','e','s')
# define c3__and c3_s3('a','n','d')
@ -288,6 +289,7 @@
# define c3__dice c3_s4('d','i','c','e')
# define c3__die c3_s3('d','i','e')
# define c3__dill c3_s4('d','i','l','l')
# define c3__dire c3_s4('d','i','r','e')
# define c3__dis c3_s3('d','i','s')
# define c3__dish c3_s4('d','i','s','h')
# define c3__disk c3_s4('d','i','s','k')
@ -811,6 +813,7 @@
# define c3__pril c3_s4('p','r','i','l')
# define c3__pro c3_s3('p','r','o')
# define c3__prod c3_s4('p','r','o','d')
# define c3__prof c3_s4('p','r','o','f')
# define c3__prox c3_s4('p','r','o','x')
# define c3__psdg c3_s4('p','s','d','g')
# define c3__puck c3_s4('p','u','c','k')

View File

@ -109,7 +109,8 @@
/* u3_cm_soft_top(): top-level safety wrapper.
*/
u3_noun
u3_cm_soft_top(c3_w pad_w,
u3_cm_soft_top(c3_w sec_w, // timer seconds
c3_w pad_w, // base memory pad
u3_funk fun_f,
u3_noun arg);
@ -121,7 +122,7 @@
u3_noun aga,
u3_noun agb);
/* u3_cm_soft_esc(): namespace lookup. Produces direct result.
/* u3_cm_soft_esc(): namespace lookup to (unit ,*).
*/
u3_noun
u3_cm_soft_esc(u3_noun sam);

View File

@ -145,7 +145,9 @@
} all;
struct { // pseudo-interrupt
c3_l sig_l; // "signal" (%intr / %prof / %time)
c3_l zap_l; // double signal, very bad
c3_l sig_l; // interrupt; written by signal
c3_l cry_l; // critical region, or 0
} coy;
struct { // jet dashboard

View File

@ -33,9 +33,6 @@
u3_noun fin = u3t(hoq);
if ( u3_nul == fin ) {
u3_cm_p("cog", cog);
u3_cm_p("typ", u3h(sut));
abort();
return u3_cm_error("find-none");
}
else {

View File

@ -338,6 +338,7 @@
u3_noun ref,
u3_noun gil)
{
if ( (u3_yes == u3_cr_sing(sut, ref)) ) {
return u3_yes;
}

View File

@ -24,7 +24,6 @@
#include "all.h"
#include "v/vere.h"
#if 0
static jmp_buf Signal_buf;
#ifndef SIGSTKSZ

View File

@ -1430,7 +1430,10 @@ _unix_sign_cb(uv_signal_t* sil_u, c3_i num_i)
fprintf(stderr, "\r\ncaught signal %d\r\n", num_i);
u3_Host.liv = u3_no;
break;
case SIGINT: u3_term_ef_ctlc(); break;
case SIGINT:
fprintf(stderr, "\r\ninterrupt\r\n");
u3_term_ef_ctlc();
break;
case SIGWINCH: u3_term_ef_winc(); break;
// case SIGCHLD: u3_save_ef_chld(); break;
}