Example #1
0
File: exec.c Project: geechee/iraf
/* KILLTASK -- Abort the currently executing task.  Only call this when a task
 *  is to be killed spontaneously, as from interrupt, not when it is just dying
 *   due to a "bye" or eof.
 * Close all pipes and pseudofiles, being careful not to close any that
 *   are real stdio files.
 * Note that our function is to kill an external task, not the process in which
 *   it resides.  The process is left running in the cache in case it is needed
 *   again.
 */
void
killtask (
  register struct task *tp
)
{
	char	buf[128];

	/* Print stack trace, with arguments.
	 */
	if (!(tp->t_ltp->lt_flags&LT_INVIS) && !(firstask->t_flags&T_BATCH) &&
	    !(strcmp (tp->t_ltp->lt_lname, "error") == 0))
	    printcall (currentask->t_stderr, tp);

	/* If task is running in a subprocess, interrupt it and read the ERROR
	 * message.  Not certain there isn't some case where this could cause
	 * deadlock, but it does not seem so.  Interrupts are disabled during
	 * process startup.  If task issues ERROR then it is popped before
	 * we are called, without issuing the signal.
	 */
	if (tp->t_pid != -1) {
	    fflush (tp->t_out);
	    c_prsignal (tp->t_pid, X_INT);
	    fgets (buf, 128, tp->t_in);
	}

	iofinish (tp);
}
Example #2
0
File: main.c Project: olebole/iraf
/* SHUTDOWN -- Call this to exit gracefully from the whole cl; never return.
 * Write out any remaining PF_UPDATE'd pfiles by restoring topd to just above
 *   first task unless we are in batch mode, then just flush io and die..
 * So that the restor will include the cl's pfile and any other pfiles that
 *   might have been cached or assigned into, we force its topd to be
 *   below its pfile head.  See the "pfp < topdp" loop in restor().
 * Don't bother with restor'ing if BATCH since we don't want to write out
 *   anything then anyway.
 */
static void
shutdown (void)
{
	float	cpu, clk;

	pr_dumpcache (0, YES);		/* flush process cache	*/
	clgflush();			/* flush graphics output */

	if (firstask->t_flags & T_BATCH) {
	    iofinish (currentask);
	    if (notify()) {
		cpu = (float)c_cputime(cpustart) / 1000.;
		clk = (float)c_clktime(clkstart);
		fprintf (stderr, "\n[%d] done  %.1f %.0m %d%%\n", bkgno,
		    cpu, clk/60., (int)((clk > 0 ? cpu / clk : 0.) * 100.));
	    }
	} else {
	    firstask->t_topd = dereference (firstask->t_ltp) + LTASKSIZ;
	    restor (firstask);
	}

	yy_startblock (LOG);			/* flush and close log	*/
	close_logfile (logfile());
	clexit();
}
Example #3
0
File: main.c Project: olebole/iraf
/* ARGSUSED */
void
onint (
  int	*vex,			/* virtual exception code	*/
  int	(**next_handler)(void) 	/* next handler to be called	*/
)
{
	if (firstask->t_flags & T_BATCH) {
	    /* Batch task.
	     */
	    iofinish (currentask);
	    bkg_abort();
	    clexit();

	} else if (currentask->t_flags & (T_SCRIPT|T_CL|T_BUILTIN)) {
	    /* CL task.
	     */
	    cl_error (E_UERR, "interrupt!!!");

	} else {
	    /* External task connected via IPC.  Pass the interrupt on to
	     * the child.
	     */
	    c_prsignal (currentask->t_pid, X_INT);

	    /* Cancel any output and disable i/o on the tasks pseudofiles.
	     * This is necessary to cancel any i/o still buffered in the
	     * IPC channel.  Commonly when the task is writing to STDOUT,
	     * for example, the CL will be writing the last buffer sent
	     * to the terminal, while the task waits after having already
	     * pushed the next buffer into the IPC.  When we resume reading
	     * from the task we will see this buffered output on the next
	     * read and we wish to discard it.  Leave STDERR connected to
	     * give a path to the terminal for recovery actions such as
	     * turning standout or graphics mode off.  This gives the task
	     * a chance to cleanup but does not permit full recovery.  The
	     * pseudofiles will be reconnected for the next task run.
	     */
	    c_fseti (fileno(stdout),            F_CANCEL, OK);
	    c_fseti (fileno(currentask->t_in),  F_CANCEL, OK);
	    c_fseti (fileno(currentask->t_out), F_CANCEL, OK);

	    c_prredir (currentask->t_pid, STDIN, 0);
	    c_prredir (currentask->t_pid, STDOUT, 0);

	    /* If a subprocess is repeatedly interrupted we assume that it
	     * is hung in a loop and abort, advising the user to kill the
	     * process.
	     */
	    if (++ninterrupts >= MAX_INTERRUPTS)
		cl_error (E_UERR, "subprocess is hung; should be killed");
	    else
		longjmp (intenv, 1);
	}

	*next_handler = NULL;
}
Example #4
0
File: exec.c Project: geechee/iraf
/* ONEOF -- "on eof" (not "one of"):
 * The current task has issued eof, either directly or via the "bye" command.
 *   Flush out all pending io, copy working pfile back to original if have one,
 *   pop a state back to the previous state and restore its environment.
 *   Avoid calling effecmode() if called from a builtin task since builtins
 *   do not have the "mode" parameter.
 *
 * If currentask is the first cl or we are batch, then we are truely done.
 *   Return true to the caller (EXECUTE), causing a return to the main.
 */
void
oneof (void)
{
	register struct pfile *pfp;
	register struct package *pkp;
	static	int	nerrs = 0;
	int	flags;

	if (cldebug)
	    eprintf ("received `%s' from `%s'\n", yeof ? "eof" : "bye",
		currentask == firstask ? "root" : currentask->t_ltp->lt_lname);

	if (!(firstask->t_flags & T_BATCH))
	    if (currentask == firstask && !gologout && !loggingout &&
		isatty (fileno (stdin)) && nerrs++ < 8)
		cl_error (E_UERR, "use `logout' to log out of the CL");

	flags = currentask->t_flags;

	if (!(flags & (T_BUILTIN|T_CL|T_SCRIPT|T_BATCH)))
	    fflush (currentask->t_out);
	iofinish (currentask);

	/* Copy back the main pfile and any pset-param files.  If the task
	 * which has terminated is a package script task, fix up the pfile
	 * pointer in the package descriptor to point to the updated pset.
	 */
	if (currentask->t_ltp->lt_flags & LT_PFILE) {
	    pfcopyback (pfp = currentask->t_pfp);
	    if (currentask->t_ltp->lt_flags & LT_DEFPCK)
		if ((pkp = pacfind(currentask->t_ltp->lt_lname)))
		    if (pkp->pk_pfp == pfp)
			pkp->pk_pfp = pfp->pf_oldpfp;
	    for (pfp = pfp->pf_npset;  pfp != NULL;  pfp = pfp->pf_npset)
		pfcopyback (pfp);
	}

	if (currentask == firstask)
	    alldone = 1;
	else {
	    currentask = poptask();
	    if (currentask->t_flags & T_BATCH)
		alldone = 1;
	}

	restor (currentask);		/* restore environment 		*/
}
Example #5
0
File: bkg.c Project: geechee/iraf
/* BKG_ABORT -- Called by onint() in main.c when we get interrupted while
 * running as a bkg job.  Kill any and all background CL's WE may have
 * started, flush io, close any open pipe files, remove our job seq lock
 * file, kill all tasks back to the one that started us as background and
 * write a message on stderr.
 */
void 
bkg_abort (void)
{
	register int	job;
	register struct task *tp;

	for (job=1;  job <= NBKG;  job++)
	    if (busy (job))
		bkg_kill (job);

	iofinish (currentask);
	delpipes (0);

	tp = currentask;
	while (!(tp->t_flags & T_BATCH)) {
	    killtask (tp);
	    tp = poptask();
	}

	fprintf (stderr, "\n[%d] killed\n", bkgno);
}
Example #6
0
File: errs.c Project: geechee/iraf
void
cl_error (int errtype, char *diagstr, ...)
{
	va_list	args;
	register struct task *tp;
	static	int nfatal = 0;
	static	int break_locks = 1;

	va_start (args, diagstr);

        /* (Re)-initialize the error action.
         */
        erract_init();

	/* Safety measure, in the event of error recursion.
	 */
	if (err_abort) {
	    if (nfatal)
	        clexit();

	    if (errlev++ > 2) {
	        nfatal++;
	        eprintf ("Error recursion.  Cl dies.\n");
	        clexit();
	    }
	}

	/* The first setjmp(errenv) is not done until we start the main loop.
 	 * Set validerrenv when start the first interactive cl to indicate that
	 * we may safely longjmp back to main's loop on an error.  ERRENV is
	 * not set for bkg jobs since error restart is not permitted.
	 */
	    
	if (!validerrenv && !(firstask->t_flags & T_BATCH)) {
	    nfatal++;
            u_doprnt (diagstr, &args, currentask->t_stderr);
	    if (errtype & E_P)
	        perror ("\nOS errmsg");
	    else
		eprintf ("\n");
	    eprintf ("Fatal startup error.  CL dies.\n");
	    clexit();
	}

	/* Any error occurring during logout is fatal.
	 */
	if (loggingout || gologout) {
	    nfatal++;
            u_doprnt (diagstr, &args, currentask->t_stderr);
	    if (errtype & E_P)
	        perror ("\nOS errmsg");
	    else
		eprintf ("\n");
	    eprintf ("Fatal logout error.  CL dies.\n");
	    clexit();
	}

	/* Perform any ONERROR error recovery in the vos first.  Initialize
	 * the error recovery mechanism (necessary since the iraf main is not
	 * being allowed to do error recovery).
	 */
	c_xonerr (1);
	XER_RESET();	/* TODO: move into LIBC interface */

	/* Clear terminal raw mode if still set. */
	c_fseti ((XINT)STDIN, F_RAW, NO);

	if (firstask->t_flags & T_BATCH)
	    eprintf ("\n[%d] ", bkgno);
	if (errtype & E_IERR)
	    eprintf ("INTERNAL ");
	if (errtype & E_FERR)
	    eprintf ("FATAL ");

	/* Disable error tracing if requested.
	 */
	if (err_trace == YES || (errtype & E_UERR)) {
	    if (currentask->t_flags & T_SCRIPT &&
	        currentask->t_flags & T_INTERACTIVE)
		    eprintf ("ERROR on line %d: ", errorline);
	    else
	        eprintf ("ERROR: ");

	    u_doprnt (diagstr, &args, currentask->t_stderr);
	    if (errtype & E_P)
	        perror ("\nOS errmsg");
	    else
	        eprintf ("\n");
	}

	/* Log the error message if from a script or an executable.
	 */
	if (!errlog && keeplog() && log_errors()) {
	    if (currentask->t_flags & T_SCRIPT || currentask->t_pid != -1) {
	    	PKCHAR  buf[SZ_LINE+1];
		FILE	*fp;
		int     fd;

		fd = c_stropen (buf, SZ_LINE, NEW_FILE);
		fp = fdopen (fd, "w");

		fprintf (fp, "ERROR on line %d: ", errorline);
		u_doprnt (diagstr, &args, fp);

		fclose (fp);
		c_close (fd);
	    	putlog (currentask, c_strpak (buf, (char *)buf, SZ_LINE));
	    }
	}
	errlog = 0;

	/* Initialize the current command block but do not log the command
	 * which aborted.  If we're only trapping errors and not fully 
  	 * recovering, don't reset the command block so we have the option
	 * to continue execution.
	 */
	if ((err_abort == YES && do_error == NO) || 
	    (do_error == YES || (errtype & E_UERR))) 
		yy_startblock (NOLOG);

	/* Delete all pipefiles.  Call iofinish() first as some OS's may
	 * require that the files be closed before they can be deleted.
	 */
	for (tp=currentask; !(tp->t_flags & T_INTERACTIVE); tp=next_task(tp)) {
	    iofinish (tp);
	    if (tp == firstask)
		break;
	}
	delpipes (0);

	/* Do not go on if this is a fatal error or we are unattended.
	 */
	if (errtype & E_FERR) {
	    nfatal++;
	    pr_dumpcache (0, break_locks);
	    clexit();
	} else if (firstask->t_flags & T_BATCH)
	    clshutdown();

	/* Reset state variables. */
	/* Most of these probably needn't be reset, but we'll play
	 * it safe.
	 */
	nestlevel = 0;			/* set nesting to 0 		*/
	offsetmode (0);			/* offset mode to index 	*/
	ncaseval = 0;			/* number of case values 	*/
	n_indexes = 0;
	imloopset = 0;			/* in an implicit loop 		*/
	n_oarr = 0;			/* implicit loop indicators 	*/
	i_oarr = 0;
	maybeindex = 0;			/* sexagesimal/index range	*/
	parse_state = PARSE_FREE;
	if (last_parm) {		/* have we tried to add a param	*/
	    last_parm->p_np = NULL;
	    currentask->t_pfp->pf_lastpp = last_parm;
	    last_parm = NULL;
	}


	/* Set the error flag.  */
	errcom.errflag++;
	errcom.nhandlers++;

	/* Get back to an interactive state.  We simply return if we're
	 * trapping errors except when processing a E_UERR.  These type
	 * messages come from the CL itself and require user attention to
	 * correct (e.g. task not found, parameter type/syntax errors, etc).
	 * The calling procedure is not expecting us to return, so we cannot
	 * properly trap without rewriting the calling code.
	 */
	if (cltrace) {
	    eprintf ("cl_error: abort=%d  beep=%d  trace=%d  flpr=%d\n", 
	        err_abort, err_beep, err_trace, err_flpr);
	    eprintf ("cl_error: code=%d do_err=%d errtype=%d/%d task='%s'\n", 
	        errcom.errcode, do_error, errtype, errtype&E_UERR, 
	        currentask->t_ltp->lt_lname);
	}
	if ((err_abort == YES && do_error == NO) || 
	    (do_error == YES || (errtype & E_UERR))) {
	        extern ErrCom errcom;
	        register struct param *pp;

	    	if (!errcom.errcode && (errtype & E_UERR)) {

                    errcom.errcode = errtype;
                    strcpy (errcom.errmsg, diagstr);
                    strcpy (errcom.task, currentask->t_ltp->lt_lname);

                    pp = paramfind (firstask->t_pfp, "$errno", 0, YES);
                    pp->p_val.v_i = errcom.errcode;
                    pp = paramfind (firstask->t_pfp, "$errmsg", 0, YES);
                    pp->p_val.v_s = errcom.errmsg;
                    pp = paramfind (firstask->t_pfp, "$errtask", 0, YES);
                    pp->p_val.v_s = errcom.task;
	    	}
	    	taskunwind();

	    	/* If an abort occurs while interrupts are disabled they will 
	    	 * never get reenabled unless we do so here.
	    	 */
	    	intr_reset();

	    	/* Go back to main loop in main().
	    	 */
	    	va_end (args);
	    	longjmp (errenv, 1);

	} else {
	    va_end (args);
	    return;
	}
}