/* at_kill.c */
/*************************************************************************
 ***                    AskTask Kill Process Module                    ***
 *** Date begun: 2/4/89.                                               ***
 *** Last modified: 2/4/89.                                            ***
 *************************************************************************/
/*** The idea is to reset the task's PC to the address of the code     ***
 *** array, which calls the DOS function Exit(). This works! It should ***
 *** not be used while the task owns say, the blitter. Also, using the ***
 *** abort signal is better if the task cares about such things (say a ***
 *** Lattice C program during level 2(?) IO). It works best on pure    ***
 *** processing tasks, for example during an infinite loop that does   ***
 *** not do drawing or IO.                                             ***
 *** Cut rmv(), changepri() & setsignal() into this module.            ***
 *************************************************************************/

#include "asktask.h"

extern struct Window    *Window;
extern int          ct;
extern struct Task  *task[NUM_TASKS];
extern char         *notaskerror;
extern char         mypri;
extern struct Task  *me;

extern void putmessage(char *,int);
extern int  yesno();
extern void gettasks();
extern void puttasks();
extern void puttaskdata();
extern unsigned long    bitsput(char *);
extern void putbits(char *,unsigned long);
extern char getchfromw();

static UWORD   code[6] = {
    0x721e,                 /* moveq    #30,d1          */
    0x2c7c,0x0000,0x0000,   /* movea.l  #00000000,a6    */
    0x4eee,0xff70           /* jmp      $ff70(a6)       */
        /* I would like to know how Exit() finds out which process this
         * task belongs to. */
};

void    rmv();          /* Remove current task with RemTask() */
void    kill();         /* Remove a task with Exit() function */
void    setsignal();    /* Alter signal values for current task */
void    changepri();    /* Change task's priority */

void    rmv() /*=========================================================*/
{
    if (ct < 0) {
        putmessage(notaskerror,3);
        return;
    }
    putmessage("Are you sure you want to RemTask() the current task (y/n)?",3);
    if (!yesno()) {
        putmessage("",1);
        return;
    }
    RemTask(task[ct]);
    gettasks();
    puttasks();
    puttaskdata();
    putmessage("RemTask() completed.",1);
}

void    setsignal() /*===================================================*/
{
unsigned long   *l,lv;
int     loop;
char    ch,buf[40];
    putmessage("",1);
    if (ct < 0) {
        putmessage(notaskerror,3);
        return;
    }
    putmessage("Which signal (Alloc/Wait/Recvd/Except/None) ?",3);
    loop = 1;
    while (loop) {
        ch = getchfromw();
        switch (ch) {
            case (0x20): l = &(task[ct]->tc_SigAlloc);  loop = 0; break;
            case (0x11): l = &(task[ct]->tc_SigWait);   loop = 0; break;
            case (0x13): l = &(task[ct]->tc_SigRecvd);  loop = 0; break;
            case (0x12): l = &(task[ct]->tc_SigExcept); loop = 0; break;
            case (0x45):
            case (0x36): putmessage("",1); return;    /* n */
        }
    }
    putbits(&buf[0],*l);
    putmessage("Enter the signal bit values:",1);
    input(Window,buf,buf,"01",236,135,32,1,0);
    lv = bitsput(buf);
    *l = lv;
    puttaskdata();
}

void    changepri() /*===================================================*/
{
int     pri,newpri;
char    buf[11];
    putmessage("",1);
    if (ct < 0) {
        putmessage(notaskerror,3);
        return;
    }
    pri = (int)task[ct]->tc_Node.ln_Pri;
    newpri = pri;
    sprintf(buf,"%d",pri);
    putmessage("Change priority to :",1);
    input(Window,buf,buf,"0123456789-+",172,135,4,1,0);
    putmessage("",1);
    if (!buf[0]) return;
    sscanf(buf,"%d",&newpri);
    if (newpri == pri) return;
    if (newpri < -128) newpri = -128;
    else if (newpri > 122) newpri = 122;
    if (newpri > mypri) {
        mypri = newpri + 5; /* Don't block myself with task's priority. */
        SetTaskPri(me,mypri);
    }
    SetTaskPri(task[ct],(char)newpri);
    puttaskdata();
}

void    kill() /*========================================================*/
{
unsigned long   *lp;
ULONG   *stk;
    if (ct < 0) {
        putmessage(notaskerror,3);
        return;}
    putmessage("Are you sure you want to try Exit()ing this process (y/n)?",3);
    if (!yesno()) {
        putmessage("",1);
        return;}
    lp = (unsigned long *)&code[2];     /* Set up code for dosbase value */
    *lp = (unsigned long)DOSBase;

    Disable();                          /* Now get at task's pc          */
    stk = (ULONG *)task[ct]->tc_SPReg;  /* Have stack pointer...         */
    stk[0] = (ULONG)&code[0];           /* ...will travel. Here I go.... */
    Enable();
    putmessage("",1);
}

/******************** CONTEXT SWITCH STACK CONTENTS **********************
 *** As far as I can tell, the data on the stack is:                   ***
 ***        0 = (long) pc                                              ***
 ***        1 = (word) status reg                                      ***
 ***        2... = other registers.                                    ***
 *************************************************************************/
