/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1997 The Ohio State University
 *	NJN
 *
 *	$Id: lamsig.c,v 1.6 1999/08/27 22:34:25 jsquyres Exp $
 *
 *	Function:	- exception signal catching
 */

#include <sys/types.h>
#include <sys/signal.h>
#include <stdio.h>
#include <unistd.h>

#include <app_mgmt.h>
#include <blktype.h>
#include <mpi.h>
#include <mpisys.h>
#include <rpisys.h>
#include <portable.h>
#include <preq.h>
#include <priority.h>
#if LAM_WANT_IMPI
#include <impi.h>
#endif

typedef void 		(*sighandler_t)(int);

/*
 * public functions
 */
int			lam_mpi_set_sighandlers();
void			lam_mpi_reset_sighandlers();
void                    lam_printfunc(void);

/*
 * private functions
 */
static void		lam_mpi_sig_handler();

/*
 * external functions
 */
extern void		(*(_lam_signal()))();

/*
 * private variables
 */
static sighandler_t	old_segv_handler;
static sighandler_t	old_bus_handler;
static sighandler_t	old_fpe_handler;
static sighandler_t	old_ill_handler;


/*
 *	lam_mpi_set_sighandlers
 *
 *	Function:	- 
 *	Accepts:	-
 *	Returns:	- 
 */
int
lam_mpi_set_sighandlers()

{
	old_segv_handler = _lam_signal(SIGSEGV, lam_mpi_sig_handler);
	if (old_segv_handler == SIG_ERR) return(LAMERROR);

	old_bus_handler = _lam_signal(SIGBUS, lam_mpi_sig_handler);
	if (old_bus_handler == SIG_ERR) return(LAMERROR);

	old_fpe_handler = _lam_signal(SIGFPE, lam_mpi_sig_handler);
	if (old_fpe_handler == SIG_ERR) return(LAMERROR);

	old_ill_handler = _lam_signal(SIGILL, lam_mpi_sig_handler);
	if (old_ill_handler == SIG_ERR) return(LAMERROR);

	return(0);
}


/*
 *	lam_mpi_set_sighandlers
 *
 *	Function:	- 
 *	Accepts:	-
 *	Returns:	- 
 */
void
lam_mpi_reset_sighandlers()

{
	_lam_signal(SIGSEGV, old_segv_handler);
	_lam_signal(SIGBUS, old_bus_handler);
	_lam_signal(SIGFPE, old_fpe_handler);
	_lam_signal(SIGILL, old_ill_handler);
}

/*
 *	lam_mpi_sig_handler
 *
 *	Function:	- handler for exceptions
 *	Accepts:	- signal number
 */
static void
lam_mpi_sig_handler(sig)

int 			sig;

{
	struct _proc	**p;
	sighandler_t	old_handler;
	CONST char	*err;
	int		mpifn;
	int		i;
	char            prefix[512];
	char            extra[512];

	switch (sig) {

	case SIGSEGV:
		old_handler = old_segv_handler;
		err = "a SIGSEGV";
		break;
	case SIGBUS:
		old_handler = old_bus_handler;
		err = "a SIGBUS"; 
		break;
	case SIGFPE:
		old_handler = old_fpe_handler;
		err = "a SIGFPE";
		break;
	case SIGILL:
		old_handler = old_ill_handler;
		err = "a SIGILL";
		break;
	default:
	        old_handler = SIG_DFL;
	        sprintf(extra, "signal %d", sig);
		err = extra;
		break;
	}

	if (old_handler == SIG_IGN) return;

#if LAM_WANT_IMPI
	if (LAM_GPSCMP(&lam_myproc->p_gps, &gimpid) == 0) {
	  strcpy(prefix, "LAM IMPI client daemon");
	} else
#endif
	sprintf(prefix, "MPI process rank %d", lam_myproc->p_gps.gps_grank);

	if ((mpifn = lam_getfunc_m())) {
		fprintf(stderr,
			"%s (n%d, p%d) caught %s in %s.\n",
			prefix,
			lam_myproc->p_gps.gps_node,
			lam_myproc->p_gps.gps_pid, err, blktype(mpifn));
	} else {
		fprintf(stderr,
			"%s (n%d, p%d) caught %s.\n",
			prefix,
			lam_myproc->p_gps.gps_node,
			lam_myproc->p_gps.gps_pid, err);
	}
	fflush(stderr);
/*
 * Print the call stack
 */
	lam_printfunc();

	if (((_kio.ki_rtf & RTF_MPIRUN) || (_kio.ki_parent > 0)) &&
#if LAM_WANT_IMPI
	    LAM_GPSCMP(&lam_myproc->p_gps, &gimpid) != 0 &&
#endif
	    MPI_COMM_WORLD != 0 && MPI_COMM_WORLD->c_group) {

		if (fork() == 0) {
			if (kinit(PRCMD)) {
				exit(errno);
			}

			p = MPI_COMM_WORLD->c_group->g_procs;
			for (i = 0; i < MPI_COMM_WORLD->c_group->g_nprocs;
					++i, ++p) {

				rpdoom((*p)->p_gps.gps_node, SELECT_PID,
						(*p)->p_gps.gps_pid, SIGUDIE);
			}

			kexit(0);
		}
	}

	kexit(1);
}
