Index: libcfa/src/interpose.cfa
===================================================================
--- libcfa/src/interpose.cfa	(revision 1469a8aabaefc9cc2ab5e6284f5782dfe30243f5)
+++ libcfa/src/interpose.cfa	(revision 6f302cd8bcf81367949579614c9b3601de0c59d3)
@@ -10,6 +10,6 @@
 // Created On       : Wed Mar 29 16:10:31 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 13:45:21 2019
-// Update Count     : 121
+// Last Modified On : Thu Jan 30 17:47:32 2020
+// Update Count     : 156
 //
 
@@ -95,5 +95,5 @@
 	void __cfaabi_interpose_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));
 	void __cfaabi_interpose_startup( void ) {
-		const char *version = NULL;
+		const char *version = 0p;
 
 		preload_libgcc();
@@ -105,12 +105,30 @@
 #pragma GCC diagnostic pop
 
+		// As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
+		// task stacks might be very small (4K) and the signal delivery corrupts memory to the point that a clean
+		// shutdown is impossible. Also, when a stack overflow encounters the non-accessible sentinel page (debug only)
+		// and generates a segment fault, the signal cannot be delivered on the sentinel page. Finally, calls to abort
+		// print a stack trace that uses substantial stack space.
+
+		#define MINSTKSZ SIGSTKSZ * 8
+		static char stack[MINSTKSZ] __attribute__(( aligned (16) ));
+		static stack_t ss;
+
+		ss.ss_sp = stack;
+		ss.ss_size = MINSTKSZ;
+		ss.ss_flags = 0;
+		if ( sigaltstack( &ss, 0p ) == -1 ) {
+			abort( "__cfaabi_interpose_startup : internal error, sigaltstack error(%d) %s.", errno, strerror( errno ) );
+		} // if
+
 		// Failure handler
-		__cfaabi_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO );
-		__cfaabi_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO );
-		__cfaabi_sigaction( SIGILL , sigHandler_ill  , SA_SIGINFO );
-		__cfaabi_sigaction( SIGFPE , sigHandler_fpe  , SA_SIGINFO );
-		__cfaabi_sigaction( SIGABRT, sigHandler_abrt, SA_SIGINFO | SA_RESETHAND);
-		__cfaabi_sigaction( SIGTERM, sigHandler_term , SA_SIGINFO );
-		__cfaabi_sigaction( SIGINT , sigHandler_term , SA_SIGINFO );
+		__cfaabi_sigaction( SIGSEGV, sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
+		__cfaabi_sigaction( SIGBUS , sigHandler_segv, SA_SIGINFO | SA_ONSTACK );
+		__cfaabi_sigaction( SIGILL , sigHandler_ill , SA_SIGINFO | SA_ONSTACK );
+		__cfaabi_sigaction( SIGFPE , sigHandler_fpe , SA_SIGINFO | SA_ONSTACK );
+		__cfaabi_sigaction( SIGTERM, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // one shot handler, return to default
+		__cfaabi_sigaction( SIGINT , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
+		__cfaabi_sigaction( SIGABRT, sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND );
+		__cfaabi_sigaction( SIGHUP , sigHandler_term, SA_SIGINFO | SA_ONSTACK | SA_RESETHAND ); // terminal hangup
 	}
 }
@@ -123,8 +141,9 @@
 void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
 void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
+void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
 
 extern "C" {
 	void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {
-		abort( NULL );
+		abort( false, NULL ); // FIX ME: 0p does not work
 	}
 
@@ -132,5 +151,5 @@
 		va_list argp;
 		va_start( argp, fmt );
-		abort( fmt, argp );
+		abort( false, fmt, argp );
 		va_end( argp );
 	}
@@ -141,50 +160,17 @@
 }
 
-void * kernel_abort    ( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return NULL; }
-void   kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
+void * kernel_abort( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 0p; }
+void kernel_abort_msg( void * data, char * buffer, int size ) __attribute__(( __nothrow__, __leaf__, __weak__ )) {}
+// See concurrency/kernel.cfa for strong definition used in multi-processor mode.
 int kernel_abort_lastframe( void ) __attribute__(( __nothrow__, __leaf__, __weak__ )) { return 4; }
 
 enum { abort_text_size = 1024 };
 static char abort_text[ abort_text_size ];
-static int abort_lastframe;
-
-void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )) {
-    va_list args;
-    va_start( args, fmt );
-    vfprintf( stderr, fmt, args );
-    va_end( args );
-	__cabi_libc.exit( status );
-}
-
-void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {
-	void * kernel_data = kernel_abort();			// must be done here to lock down kernel
-	int len;
-
-	abort_lastframe = kernel_abort_lastframe();
-	len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
-	__cfaabi_dbg_write( abort_text, len );
-
-	if ( fmt ) {
-		va_list args;
-		va_start( args, fmt );
-
-		len = vsnprintf( abort_text, abort_text_size, fmt, args );
-		va_end( args );
-		__cfaabi_dbg_write( abort_text, len );
-
-		if ( fmt[strlen( fmt ) - 1] != '\n' ) {		// add optional newline if missing at the end of the format text
-			__cfaabi_dbg_write( "\n", 1 );
-		}
-	}
-
-	kernel_abort_msg( kernel_data, abort_text, abort_text_size );
-	__cabi_libc.abort();
-}
-
-static void __cfaabi_backtrace() {
+
+static void __cfaabi_backtrace( int start ) {
 	enum {
 		Frames = 50,									// maximum number of stack frames
-		Start = 8,										// skip first N stack frames
 	};
+	int last = kernel_abort_lastframe();				// skip last N stack frames
 
 	void * array[Frames];
@@ -192,14 +178,12 @@
 	char ** messages = backtrace_symbols( array, size );
 
-	// find executable name
-	*index( messages[0], '(' ) = '\0';
+	*index( messages[0], '(' ) = '\0';					// find executable name
 	__cfaabi_bits_print_nolock( STDERR_FILENO, "Stack back trace for: %s\n", messages[0]);
 
-	for ( int i = Start; i < size - abort_lastframe && messages != 0p; i += 1 ) {
+	for ( unsigned int i = start; i < size - last && messages != 0p; i += 1 ) {
 		char * name = 0p, * offset_begin = 0p, * offset_end = 0p;
 
-		for ( char * p = messages[i]; *p; ++p ) {
+		for ( char * p = messages[i]; *p; ++p ) {		// find parantheses and +offset
 			//__cfaabi_bits_print_nolock( "X %s\n", p);
-			// find parantheses and +offset
 			if ( *p == '(' ) {
 				name = p;
@@ -212,9 +196,8 @@
 		}
 
-		// if line contains symbol print it
-		int frameNo = i - Start;
+		// if line contains symbol, print it
+		int frameNo = i - start;
 		if ( name && offset_begin && offset_end && name < offset_begin ) {
-			// delimit strings
-			*name++ = '\0';
+			*name++ = '\0';								// delimit strings
 			*offset_begin++ = '\0';
 			*offset_end++ = '\0';
@@ -228,9 +211,52 @@
 }
 
+void exit( int status, const char fmt[], ... ) {
+	va_list args;
+	va_start( args, fmt );
+	vfprintf( stderr, fmt, args );
+	va_end( args );
+	__cabi_libc.exit( status );
+}
+
+void abort( bool signalAbort, const char fmt[], ... ) {
+	void * kernel_data = kernel_abort();				// must be done here to lock down kernel
+	int len;
+
+	signal( SIGABRT, SIG_DFL );							// prevent final "real" abort from recursing to handler
+
+	len = snprintf( abort_text, abort_text_size, "Cforall Runtime error (UNIX pid:%ld) ", (long int)getpid() ); // use UNIX pid (versus getPid)
+	__cfaabi_bits_write( STDERR_FILENO, abort_text, len );
+
+	if ( fmt ) {
+		va_list args;
+		va_start( args, fmt );
+
+		len = vsnprintf( abort_text, abort_text_size, fmt, args );
+		va_end( args );
+		__cfaabi_bits_write( STDERR_FILENO, abort_text, len );
+
+		if ( fmt[strlen( fmt ) - 1] != '\n' ) {			// add optional newline if missing at the end of the format text
+			__cfaabi_dbg_write( "\n", 1 );
+		}
+	}
+
+	kernel_abort_msg( kernel_data, abort_text, abort_text_size );
+	__cfaabi_backtrace( signalAbort ? 4 : 3 );
+
+	__cabi_libc.abort();								// print stack trace in handler
+}
+
+void abort( const char fmt[], ... ) {
+	va_list args;
+	va_start( args, fmt );
+	abort( false, fmt, args );
+	va_end( args );
+}
+
 void sigHandler_segv( __CFA_SIGPARMS__ ) {
-		if ( sfp->si_addr == NULL ) {
-			abort( "Null pointer (0p) dereference.\n" );
+		if ( sfp->si_addr == 0p ) {
+			abort( true, "Null pointer (0p) dereference.\n" );
 		} else {
-			abort( "%s at memory location %p.\n"
+			abort( true, "%s at memory location %p.\n"
 				   "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript.\n",
 				   (sig == SIGSEGV ? "Segment fault" : "Bus error"), sfp->si_addr );
@@ -239,5 +265,5 @@
 
 void sigHandler_ill( __CFA_SIGPARMS__ ) {
-	abort( "Executing illegal instruction at location %p.\n"
+	abort( true, "Executing illegal instruction at location %p.\n"
 			"Possible cause is stack corruption.\n",
 			sfp->si_addr );
@@ -255,18 +281,9 @@
 	  default: msg = "unknown";
 	} // choose
-	abort( "Computation error %s at location %p.\n", msg, sfp->si_addr );
-}
-
-void sigHandler_abrt( __CFA_SIGPARMS__ ) {
-	__cfaabi_backtrace();
-
-	// reset default signal handler
-	__cfaabi_sigdefault( SIGABRT );
-
-	raise( SIGABRT );
+	abort( true, "Computation error %s at location %p.\n", msg, sfp->si_addr );
 }
 
 void sigHandler_term( __CFA_SIGPARMS__ ) {
-	abort( "Application stopped by %s signal.", sig == SIGINT ? "an interrupt (SIGINT)" : "a terminate (SIGTERM)" );
+	abort( true, "Application interrupted by signal: %s.\n", strsignal( sig ) );
 }
 
