/* 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<_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); }
/* 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; }