# include	"ctlmod.h"
# include	"pipes.h"
# include	<sccs.h>

SCCSID(@(#)proc_err.c	8.1	12/31/84)

int  proc_err();
extern int pb_prime();
extern int pb_flush();
extern int pb_dump();
extern int send_off();
extern int resetp();

extern char		*Proc_name;
extern pb_t		*MonPpb;


/*
**  PROC_ERR -- Process error message
**
**	This routine processes an error.  It searches back through
**	the chain of contexts until it finds one that is willing to
**	process this error, or it finds that it must transfer the
**	error to another process to handle it.
**
**	It also unwinds the tree of
**	activations.  It leaves us in the context that processes
**	the error, or the state that should be reading the
**	input pipe.
**
**	The local error handling function returns zero if the
**	error should be ignored, anything else otherwise.
**
**	Parameters:
**		pc -- error parameter count.
**		pv -- error parameter vector.
**		ppb -- a pointer to a pipe block to use in
**			sending this error.
**
**	Returns:
**		none.
**
**	Side Effects:
**		Unwinds the list of activations.
**		The input pipe can be changed under certain
**			circumstances.
**
**	Trace Flags:
**		6.8 - 6.15
*/

int
proc_err(ppb, pc, pv)
pb_t	*ppb;
int	pc;
PARM	pv[];
{
	register struct fn_def	*f;
	register int		i;
	register ctx_t		*ctx;

# ifdef xCTR2
	if (tTf(6, 8))
		lprintf("proc_err: new = %d\n", Ctx.ctx_new);
# endif
	pb_prime(ppb, PB_ERR);

	/*
	**  Scan back on the list of context dependencies.
	**	If we come to someone who can process this message,
	**	we go ahead and do it.  We also take this
	**	opportunity to unwind the context list & call the
	**	cleanup functions.
	*/

	for (ctx = &Ctx; ctx != NULL; ctx = ctx->ctx_link)
	{
		Proc_name = ctx->ctx_name;
		f = ctx->ctx_fn;
# ifdef xCTR2
		if (tTf(6, 9))
			lprintf("proc_err: unwinding %s: errfn=%x, ppb=%x, link=%x, resp=%d, fn=%x\n",
			    Proc_name, ctx->ctx_errfn, ctx->ctx_ppb,
			    ctx->ctx_link, ctx->ctx_resp, f);
# endif

		/*  Do the actual error processing. */
		ppb->pb_proc = ctx->ctx_resp;
		if (ctx->ctx_errfn != NULL)
			i = (*ctx->ctx_errfn)(pc, pv);
		else
			i = -1;

# ifdef xCTR2
		if (tTf(6, 11))
			lprintf("proc_err: errcode %d\n", i);
# endif
		if (i == 0)
			break;
		else if (i > 0)
		{
			/* turn into nonfatal error */
			ppb->pb_stat |= PB_INFO;
			ppb->pb_proc = PB_FRONT;
		}
		else
		{
			/* call the cleanup function */
			if (f != NULL && f->fn_active > 0)
				(*f->fn_cleanup)(1);
		}

		/* arrange to leave if parent not in this process */
		if (ppb->pb_proc != Cm.cm_myproc)
		{
			send_off(ppb, pc, pv);
			pb_flush(ppb);

			/* throw away dead contexts and exit */
			break;
		}
	}
	if (ctx == NULL)
		syserr("proc_err: no parent");

# ifdef xCTR3
	if (tTf(6, 12))
	{
		lprintf("proc_err: cleanup: ctx=%x, ->_link=%x, MonPpb = ", ctx, ctx->ctx_link);
		pb_dump(MonPpb, TRUE);
	}
# endif
	/* pop contexts down to ctx and exit */
	ctx = ctx->ctx_link;
	while (Ctx.ctx_link != ctx)
	{
		if (Ctx.ctx_link == NULL)
			syserr("proc_err: underflow");
		Ctx.ctx_new = TRUE;
		resetp();
	}

	/*
	**  Flush input pipe.
	**	THIS CODE IS ONLY NEEDED TO MAKE READMON WORK, AND
	**	SHOULD BE REMOVED WHEN READMON GOES AWAY!!
	*/

	if (ctx == NULL)
	{
		Cm.cm_input = Cm.cm_rinput;
		while (!bitset(PB_EOF, MonPpb->pb_stat))
			pb_read(MonPpb);
		MonPpb->pb_st = PB_UNKNOWN;
	}

	longjmp(Ctx.ctx_jbuf, 1);
}
