/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	sigHandlers
 *
 * DESCRIPTION:	RCI assumes control of the signals SIGHUP and SIGXCPU.
 *
 *		SIGHUP is delivered to the task to indicate an abort condition
 *		(i.e., rciAbort()) was called from somewhere). When this
 *		happens, RCI internally releases all tasks, and then either
 *		prints the error information that was supplied with the abort
 *		call and exits, or calls an application-supplied abort
 *		routine. 
 *
 *		SIGXCPU is delivered by the system whenever a hardware
 *		exception occurs at the control level. When this occurs, the
 *		program simply prints whatever doagnostic information was
 *		returned with the exception (cause of the exception, 
 *		pc value, stack trace, etc.), and exits.
 * 
 *		The module contains the signal handlers that perform these
 *		tasks.
 *
 * AUTHOR/DATE:	John Lloyd, Fall 1987
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

#if !defined(SGI_CFG) && !defined(SIMONLY_CFG)
#include "crashinfo.h"
#endif

#include "../h/rciTask.h"
#include "../h/rciOptions.h"

#include "../rci/abort.h"

extern ABORT_DESC rciAbortDesc;
extern ABORT_DESC rciFatalDesc;

char obuf[256];
#define ONUNIX		1

static int printFatal();
static doInit();

onXcpu()
{
#if !defined(SGI_CFG) && !defined(SIMONLY_CFG) && !defined(LINUX_CFG)

	/* Signal handler for SIGXCPU (control level program crash) */

	CRASHINFO crashInfo;
	int cpu;
	int fdp;
	int detect;

	if ((detect = auxCrashInfo (&crashInfo, &cpu)) < 0)
	 { printf ("\nRCI FATAL ERROR trying to examine crash information\n");
	   printErrors();
	   exit (-1);
	 }
	else if (detect)
	 { crashMessage (obuf, &crashInfo, 0);
	   printf ("\nProgram Crash on CPU %d\n%s\n", cpu, obuf);
	   crashStackDump (&crashInfo);
	   exit (-1);
	 }
	else if ((detect=rciCrashInfo (&crashInfo, &fdp)) < 0)
	 { printf ("\nRCI FATAL ERROR trying to examine crash information\n");
	   printErrors();
	   exit (-1);
	 }
	else if (detect)
	 { crashMessage (obuf, &crashInfo, 0);
	   if (fdp)
	    { printf ("\nProgram Crash on arbiter, interrupt device %d\n%s\n",
		      fdp, obuf);
	    }
	   else
	    { printf ("\nProgram Crash on arbiter, generic RCI device\n%s\n",
		      obuf);
	    }
	   crashStackDump (&crashInfo);
	   exit (-1);
	 }
	else
	 { printf ("\nonXcpu() -- spurious crash signal detected\n");
	 }
#endif
#if defined(SGI_CFG) || defined(LINUX_CFG)
	printf ("Program crash in RCI control level. Check core file.\n");
	exit (-1);
#endif
#if defined(SIMONLY_CFG)
	printf ("Program received SIGXCPU\n");
	exit (-1);
#endif
}

extern int rciAbortFlag;
extern int rciFatalFlag;
extern int rciNumTasks;
extern RCI_DESC rciTaskTable[];

#define MONITOR_TIMEOUT	100000

static (*abortHandler)() = NULLF;
static initDone = 0;
#define INIT_CHECK()	if (!initDone) doInit();
static doInit()
{
	initDone = 1;
	abortHandler = NULLF;
	requestFlagInit(&initDone);
}	

int (*rciAbortHandler(fxn))()
int (*fxn)();
{
	/* Routine to set up application supplied handler for rciAbort() */

	char *fxnName = "rciAbortHandler()";
	int (*old)();

	INIT_CHECK();

	if (!planningLevelCheck(fxnName))
	 { return(NULLF);
	 }
	old = abortHandler;
	abortHandler = fxn;
	return (old);	
}

onHup()
{
	/* handler for SIGHUP (delivered when rciAbort() is called) */

	RCI_DESC *td;
	int code;
	char *msg;

	INIT_CHECK();

	if (rciFatalFlag)
	 { printFatal();
	   exit(-1);
	 }
	if (!rciAbortFlag)
	 { printf ("\nonHup() -- spurious hangup signal detected\n");
	   exit (-1);
	 }
	td = &rciTaskTable[rciAbortDesc.taskId];
	msg = rciAbortDesc.buf;
	code = rciAbortDesc.code;

	if (abortRelease() < 0)
	 { printf ("\nRCI FATAL ERROR on release:\n");
	   printErrors();
	   exit (-1);
	 }
	if (rciFatalFlag)
	 { printFatal();
	   exit (-1);
	 }

	rciClearAbort();

	if (abortHandler)
	 { (*abortHandler)(code, msg, td);
	 }
	else
	 { rciPrintAbort (code, msg, td);
	   exit (-1);
	 }
}

static printFatal()
{
	printf ("\nRCI FATAL ERROR: task '%s' on cpu %d\n%s\n", 
		rciTaskName(&rciTaskTable[rciFatalDesc.taskId]),
		rciFatalDesc.cpu,
		rciFatalDesc.buf);
}

rciPrintAbort(code, msg, td)
int code;
char *msg;
RCI_DESC *td;
{
	/* Routine to print the information supplied by an RCI
	   abort condition.
	 */

	if (td->tcb)
	 { printf ("\nRCI ABORT: task '%s' on cpu %d, cycle %d\n%s\n", 
		   rciTaskName(td), td->cpu, td->tcb->cycleCount, msg);
	 }
	else
	 { printf ("\nRCI ABORT: task '%s' on cpu %d\n%s\n", 
		   rciTaskName(td), td->cpu, msg);
	 }
}
