p2test96.c


#include "../h/const.h"
#include "../h/types.h"

/* hardware constants */
#define NOSEGS          4   /* number of segments in seg. table */
#define PRINT0ADDR      (devreg_t *)01520
                    /* address of printer0's device
                        registers  */
extern void *SSI;

/* nucleus constants the test program needs to know */
#define CLOCKINTERVAL       100000L /* interval to V clock semaphore */

/* constants to allow SYS services and SYS calls */
#define S_CREAPROC          1
#define S_TERMPROC          2
#define S_CREATHREAD        3
#define S_TERMTHREAD        4
#define S_PROGTRAPVEC       5
#define S_MMTRAPVEC         6
#define S_SYSTRAPVEC        7
#define S_WAITIO            8
#define S_WAITCLOCK         9
#define S_GETCPUTIME        10
#define S_NONEXISTENT       11

#define DO_MSGSEND          SYS1
#define DO_MSGRECV          SYS2

struct ssimsg {
    int ssiservice;
    void ssip;
};

int s_service(service,p)
void p;
{
    register r4,r3,r2;
    struct ssimsg msgtossi;
    msgtossi.ssiservice=service;
    msgtossi.ssip=p;
    r4 = SSI;
    r3 = &msgtossi;
    DO_MSGSEND();
    DO_MSGRECV();
    return(msgtossi.ssiservice);
}
    
long s_getcputime(service,p)
void p;
{
        register int r4,r3,r2;
        double_t msg;

        msg.w.whigh = S_GETCPUTIME;
        r4 = SSI;
        r3 = &(msg.w);
        DO_MSGSEND();
        DO_MSGRECV();
        return msg.l;

}
    
#define CREATENOGOOD        NULL    /* to note result of err on CREATEPROC */

/* just to be clear */

#define NOLEAVES        4   /* number of leaves of p8 process tree */


state_t      p2state, p3state,   /* initial states */
        p4state, p5state,
        p6state, p7state,
        p8rootstate, child1state,
            child2state, gchild1state,
        gchild2state, gchild3state,
        gchild4state,printstate;

state_t      pstat_n, mstat_n,   /* trap states for p5 */
        sstat_n, pstat_o,
        mstat_o, sstat_o;

int     p1p2synch=0;        /* to check on p1/p2 synchronization */

int     zero=0;         /* to check divide by 0 */
int     p8inc;          /* p8's incarnation number */

int     p4inc=1;        /* p4 incarnation number */

devreg_t    *p_devrg=PRINT0ADDR;    /* address of printer0's device
                        registers */

char        iong[12] = "i/o no good";

int     p2(),p3(),p4(),p5(),p5a(),p6(),p7(),p7a(),p5prog(),p5mm();
int     p5sys(),p8root(),child1(),child2(),p8leaf();
int     printthread();

void *printid,*p2id,*p4id,*p5id,*p8id;

int
strlen(string)
    register char *string;
{
    register int length=0;

    while (*string++)
        length++;
    return(length);
}

/* a procedure to print on the line printer */
print(msg)
    char *msg;          /* address of message to print */
{
    register int r4, r3, r2;    /* registers available */

    r4=printid;
    r3=msg;
    DO_MSGSEND();
    DO_MSGRECV();
}


printthread()
{   
    register int r4,r3,r2;
    char *msg;
    int sender;
    char *initmsg="printer test";

    /* set up printer's device registers */
    p_devrg->d_amnt = strlen(initmsg);
    p_devrg->d_badd = initmsg;
    p_devrg->d_op = IOWRITE;     /* start i/o    */

    s_service(S_WAITIO,p_devrg);
    
    while (1)
    {
        r4 = 0;
        DO_MSGRECV();
        msg=(char *) r3;
        sender=r4;
    
        /* set up printer's device registers */
        p_devrg->d_amnt = strlen(msg);
        p_devrg->d_badd = msg;
        p_devrg->d_op = IOWRITE;     /* start i/o    */

        r3=s_service(S_WAITIO,p_devrg);
        if (r3 != NORMAL)
        {
            p_devrg->d_amnt = strlen(iong);
            p_devrg->d_badd = iong;
            p_devrg->d_op = IOWRITE; /* print `iong' */
            s_service(S_WAITIO,p_devrg);
        }
        r4=sender;
        r3=0;
        DO_MSGSEND();
    }
}

/*                                                                   */
/*                 p1 -- the root process                            */
/*                                                                   */
test()
{   
    register int    r4, r3, r2; /* registers available       */

    STST(&printstate);          
    printstate.s_sp = printstate.s_stl; 
    printstate.s_stl -= PAGESIZE/2;  
    printstate.s_pc = (int)printthread;

    printid=s_service(S_CREATHREAD,&printstate);
    

    /* set up states of the other processes */

    /* set up p2's state */
    STST(&p2state);         /* create a state area             */
    p2state.s_sp = printstate.s_stl;/* stack of p2 should sit above    */
    p2state.s_stl=p2state.s_sp- PAGESIZE/2;    /* current stack and be 1/2 a page */
    p2state.s_pc = (int)p2;     /* p2 starts executing function p2 */

    STST(&p3state);
    p3state.s_sp = p2state.s_stl;
    p3state.s_stl = p3state.s_sp - PAGESIZE/2;
    p3state.s_pc = (int)p3;

    STST(&p4state);
    p4state.s_sp = p3state.s_stl;
    p4state.s_stl = p4state.s_sp - PAGESIZE/2;
    p4state.s_pc = (int)p4;
    
    STST(&p5state);
    p5state.s_sp = p4state.s_stl - PAGESIZE/2;  /* because there will */
    p5state.s_stl = p5state.s_sp - PAGESIZE/2;  /* be two p4's        */
    p5state.s_pc = (int)p5;

    STST(&p6state);
    p6state.s_sp = p5state.s_stl;
    p6state.s_stl = p6state.s_sp - PAGESIZE/2;
    p6state.s_pc = (int)p6;

    STST(&p7state);
    p7state.s_sp = p6state.s_stl;
    p7state.s_stl = p7state.s_sp - PAGESIZE/2;
    p7state.s_pc = (int)p7;

    STST(&p8rootstate);
    p8rootstate.s_sp = p7state.s_stl;
    p8rootstate.s_stl = p8rootstate.s_sp - PAGESIZE/2;
    p8rootstate.s_pc = (int)p8root;

    STST(&child1state);
    child1state.s_sp = p8rootstate.s_stl;
    child1state.s_stl = child1state.s_sp - PAGESIZE/2;
    child1state.s_pc = (int)child1;

    STST(&child2state);
    child2state.s_sp = child1state.s_stl;
    child2state.s_stl = child2state.s_sp - PAGESIZE/2;
    child2state.s_pc = (int)child2;

    STST(&gchild1state);
    gchild1state.s_sp = child2state.s_stl;
    gchild1state.s_stl = gchild1state.s_sp - PAGESIZE/2;
    gchild1state.s_pc = (int)p8leaf;

    STST(&gchild2state);
    gchild2state.s_sp = gchild1state.s_stl;
    gchild2state.s_stl = gchild2state.s_sp - PAGESIZE/2;
    gchild2state.s_pc = (int)p8leaf;

    STST(&gchild3state);
    gchild3state.s_sp = gchild2state.s_stl;
    gchild3state.s_stl = gchild3state.s_sp - PAGESIZE/2;
    gchild3state.s_pc = (int)p8leaf;

    STST(&gchild4state);
    gchild4state.s_sp = gchild3state.s_stl;
    gchild4state.s_stl = gchild4state.s_sp - PAGESIZE/2;
    gchild4state.s_pc = (int)p8leaf;

    /* create process p2 */
    p2id=s_service(S_CREAPROC,&p2state); /* start p2     */

    print("p2 was started");
    
    r4=(int) p2id;
    r3 = 2;
    DO_MSGSEND();   

    DO_MSGRECV();   
    /* make sure we really blocked */
    if (p1p2synch == 0)
        print("p1/p2 synchronization bad");

    r4 = s_service(S_CREAPROC,&p3state);
    DO_MSGSEND();
    print("p3 is started");
    DO_MSGRECV();
    
    p4id=r4= s_service(S_CREAPROC,&p4state);
    DO_MSGSEND();   /* start p4     */
    DO_MSGRECV();
    DO_MSGSEND();
    
    p5id=r4= s_service(S_CREAPROC,&p5state);
    DO_MSGSEND();               /* start p5     */
    r4=p5id;
    DO_MSGSEND();
    
    r4= s_service(S_CREAPROC,&p6state);
    DO_MSGSEND();               /* start p6 */

    r4= s_service(S_CREAPROC,&p7state);
    DO_MSGSEND();               /* start p7 */

    p8id=r4= s_service(S_CREAPROC,&p8rootstate);
    DO_MSGSEND();
    
    r4=p5id;
    DO_MSGRECV();                   /* P(endp5)     */

    print("p1 knows p5 ended");

    r4 = p4id;
    DO_MSGRECV();                   /* P(blkp4)     */

#ifdef NOTDEF
    /* now for a more rigorous check of process termination */
    for (p8inc=0; p8inc<4; p8inc++) {
        r4 = (int)&p8rootstate;
        DO_CREATEPROC();

        if (r2 == CREATENOGOOD) {
            print("error in process termination");
            HALT();
        }

        r4 = p8id;
        DO_MSGRECV();                   /* P(blkp4)     */
    }
#endif

    print("p1 finishes OK");
    r4 = r4/0;              /* terminate p1 */

    /* should not reach this point, since p1 just got a program trap */
    print("p1 still alive after progtrap & no trap vector");
    HALT();                 /* HALT !!!     */
}


/* p2 -- synch and cputime-SYS test process */
p2()
{
    register int    r4, r3, r2;     /* registers available */
    int     i,j;            /* just to waste time  */
    long        now1,now2;      /* times of day        */
    double_t    cpu_t1,cpu_t2;      /* cpu time used       */
    void parent;

    r4=0;
    r3=0;
    DO_MSGRECV();
    if (r3 != 2)
        print("p2 received a wrong message");
    parent=r4;
    
    print("p2 starts");

    /* test of SYS6 */

    STCK(&now1);                /* time of day   */
    cpu_t1.l = s_getcputime();      /* CPU time used */

    /* delay for several milliseconds */
    for (i=1; i<=1500; i++)
        j = i;

    cpu_t2.l = s_getcputime();      /* CPU time used */
    STCK(&now2);                /* time of day  */

    if (((now2 - now1) >= (cpu_t2.l - cpu_t1.l)) &&
            ((cpu_t2.l - cpu_t1.l) >= 5000))
        print("p2 is OK");
    else  {
        if ((now2 - now1) < (cpu_t2.l - cpu_t1.l))
            print ("more cpu time than real time");
        if ((cpu_t2.l - cpu_t1.l) < 5000)
            print ("not enough cpu time went by");
        print("p2 blew it!");
    }

    p1p2synch = 1;              /* p1 will check this */

    r4 = parent;
    r3=0;
    DO_MSGSEND();               /* notify end of job     */

    s_service(S_TERMPROC,0);            /* terminate p2 */

    /* just did a SYS2, so should not get to this point */
    print("p2 didn't terminate");
    HALT();                 /* HALT!           */
}


/* p3 -- pseudoclock test process */
p3()
{
    register int    r4, r3, r2;     /* registers available */
    long        time1, time2;
    double_t    cpu_t1,cpu_t2;      /* cpu time used       */
    int     i;
    void parent;

    r4=0;
    r3=0;
    DO_MSGRECV();
    parent=r4;

    time1 = 0;
    time2 = 0;

    /* loop until we are delayed at least half of clock V interval */
    while (time2-time1 < (CLOCKINTERVAL >> 1))  {
        STCK(&time1);           /* time of day     */
        s_service(S_WAITCLOCK,0);
        STCK(&time2);           /* new time of day */
    }

    print("p3 - WAITCLOCK OK");

    /* now let's check to see if we're really charge for CPU
       time correctly */
    cpu_t1.l = s_getcputime();

    for (i=0; i<500; i++)
        s_service(S_WAITCLOCK,0);
        
    cpu_t2.l = s_getcputime();
    
    if (cpu_t2.l - cpu_t1.l < 1000)
        print("p3 - CPU time incorrectly maintained");
    else
        print("p3 - CPU time correctly maintained");


    r4 = parent;
    r3=0;
    DO_MSGSEND();               /* notify enf of job     */

    s_service(S_TERMPROC,0);            /* terminate p3 */

    /* just did a SYS2, so should not get to this point */
    print("p3 didn't terminate");
    HALT();                 /* HALT            */
}

int p4ok=0;
state_t *p42state;

/* p4 -- termination test process */
p4()
{
    register int    r4, r3, r2;     /* registers available  */
    void parent;

    r4=0;
    r3=0;
    DO_MSGRECV();
    parent=r4;

    switch (p4inc) {
        case 1:
            print("first incarnation of p4 starts");
            p4inc++;
            break;
        case 2:
            print("second incarnation of p4 starts");
            p4ok=1;
            break;
    }

    r4=parent;
    r3=0;
    DO_MSGSEND();
    DO_MSGRECV();
    
    if(p4inc==2)
        p4ok=0;
        
    /* start another incarnation of p4 running, and wait for  */
    /* a V(synp4). the new process will block at the P(blkp4),*/
    /* and eventually, the parent p4 will terminate, killing  */
    /* off both p4's.                                         */

    p4state.s_sp -= PAGESIZE/2;     /* give another page  */
    p4state.s_stl -= PAGESIZE/2;        /* to the new process */

    r4 = s_service(S_CREAPROC,&p4state);
    DO_MSGSEND();           /* start a new p4    */
    DO_MSGRECV();           /* wait for it       */

    print("p4 is OK");

    r4 = parent;
    r3=0;
    DO_MSGSEND();               /* endp4         */

    r4 = s_service(S_TERMPROC,0);           /* terminate p4      */

    /* just did a termproc, so should not get to this point */
    print("p4 didn't terminate");
    HALT();                 /* HALT            */
}

void p5parent;
/* p5 -- passup test process */
p5()
{
    register int    r4, r3, r2; /* registers available         */
    state_t      tstate;     /* a state with translation on */
    sd_t        seg_tab[NOSEGS];/* bad segment table           */
    int     x;      /* divided by 0 to test prog traps */
    int     seg_no;     /* to set up segment table     */
    

    r4=0;
    r3=0;
    DO_MSGRECV();
    p5parent=r4;
    
    print("p5 starts");

    /* set up higher level TRAP handlers (new areas) */
    STST(&pstat_n);
    pstat_n.s_sp = pstat_n.s_stl + PAGESIZE/4;
    pstat_n.s_pc = (int)p5prog;
    STST(&mstat_n);
    mstat_n.s_sp = mstat_n.s_stl + PAGESIZE/4;
    mstat_n.s_pc = (int)p5mm;
    STST(&sstat_n);
    sstat_n.s_sp = sstat_n.s_stl + PAGESIZE/4;
    sstat_n.s_pc = (int)p5sys;

    r4=s_service(S_CREATHREAD,&pstat_n);
    s_service(S_PROGTRAPVEC,r4);
    /* specify trap vectors */
    r4=s_service(S_CREATHREAD,&mstat_n);
    s_service(S_MMTRAPVEC,r4);
    r4=s_service(S_CREATHREAD,&sstat_n);
    s_service(S_SYSTRAPVEC,r4);

    x = x/zero;         /* should cause a program trap      */

    STST(&tstate);          /* cause a memory management trap   */
    tstate.s_sta = seg_tab;     /* by loading a state with trans-   */
    tstate.s_ps1.ps_m = TRUE;   /* lation on with all segments      */
                                        /* invalid                          */
    for (seg_no=0; seg_no < NOSEGS; seg_no++)
        seg_tab[seg_no].sd_p = FALSE;
    LDST(&tstate);
}

/* second part of p5 - should be entered in user mode */
p5a()
{
    register int    r4, r3, r2; /* registers available              */
    long        time1, time2;
    double_t    cpu_t2;     /* cpu time used       */

    SYS9();             /* should be passed up */

    /* the first time through, we are in user mode */
    /* and the call should generate a program trap */
    cpu_t2.l = s_getcputime();


    /* if p4 and offspring are really dead, this will increment blkp4 */
    r4 = (int)p5parent;
    DO_MSGRECV();           /* P(blkp4) */

    /* do some delay to be reasonably sure p4 and its offspring are dead */
    time1 = 0;
    time2 = 0;
    while (time2-time1 < (CLOCKINTERVAL >> 1))  {
        STCK(&time1);
        s_service(S_WAITCLOCK,0);
        STCK(&time2);
    }

    r4 = p5parent;
    r3=0;
    DO_MSGSEND();               /* endp4         */

    r4 = s_service(S_TERMPROC,0);           /* terminate p5      */
    /* should have terminated, so should not get to this point */
    
    print("p5 didn't terminate");
    HALT();             /* HALT            */
}

/* p5's program trap handler */
p5prog()
{
    register int r4,r3,r2;
    state_t *stat;
    
    while (1)
    {
        r4 = 0;
        DO_MSGRECV();
        stat=(state_t *) r3;

        switch(stat->s_ps2.p2_pr.pr_typ) {
        case ZERODIV:
            print("divide by zero");
            zero = 1;       /* will not happen next time */
            break;
        case PRIVINSTR:
            print("privileged instruction");
            /* return to kernel mode */
            stat->s_ps1.ps_ku = 1;
            stat->s_pc = (int)p5a;   /* retry in kernel mode */
            break;
        default:
            print("other program trap");
        }
        r3=0;
        DO_MSGSEND();
    }
}

/* p5's memory management trap handler */
p5mm()
{
    register int r4,r3,r2;
    state_t *stat;
    
    while (1)
    {
        r4 = 0;
        DO_MSGRECV();
        stat=(state_t *) r3;

        print("memory management trap");
        stat->s_ps1.ps_m = 0;        /* no more address translation  */
        stat->s_ps1.ps_ku = 0;   /* but put us in user mode when */
                    /* we return                    */
        stat->s_pc = (int)p5a;   /* return to p5a                */
        r3=0;
        DO_MSGSEND();
    }
}

/* p5's SYS trap handler */
p5sys()
{
    register int r4,r3,r2;
    state_t *stat;
    
    while (1)
    {
        r4 = 0;
        DO_MSGRECV();
        stat=(state_t *) r3;


        switch (stat->s_ps1.ps_ku) {
        case 0:
            print("high level SYS call from user mode process");
            break;
        case 1:
            print("high level SYS call from kernel mode process");
            break;
        }
        r3=0;
        DO_MSGSEND();
    }
}   

/*p6 -- high level syscall without initializing trap vector*/
p6()
{
    print("p6 starts");

    SYS9();     /* should cause termination because p6 has no 
              trap vector */

    print("p6 still alive after SYS9() without specifying trap vector");

    HALT();
}

/*p7 -- program trap without initializing passup vector*/
p7()
{
    int x;      /* to test divide by 0 */
    
    print("p7 starts");

    x = x/0;
    
    print("p7 still alive after program trap with no trap vector");
    HALT();
}


/* p8root -- test of termination of subtree of processes              */
/* create a subtree of processes, wait for the leaves to block, signal*/
/* the root process, and then terminate                               */
p8root()
{
    register int    r4,r3,r2;
    int     grandchild;
    void parent;

    r4=0;
    r3=0;
    DO_MSGRECV();
    parent=r4;

    r3=0;
    print("p8root starts");
    r4=s_service(S_CREAPROC,&child1state);
    DO_MSGSEND();
    r4=s_service(S_CREAPROC,&child2state);
    DO_MSGSEND();

    for (grandchild=0; grandchild<NOLEAVES; grandchild++) {
        r4=0;
        r3=0;
        DO_MSGRECV();
    }
    r4 = parent;
    r3=0;
    DO_MSGSEND();               /* endp8         */

    r4 = s_service(S_TERMPROC,0);           /* terminate p8      */

    /* just did a termproc, so should not get to this point */
    print("p8 didn't terminate");
    HALT();                 /* HALT            */
}

/*child1 & child2 -- create two sub-processes each*/

child1()
{
    register int    r4,r3,r2;
    r4=0;
    r3=0;
    DO_MSGRECV();
    r3=r4; /* set the message as the parent's id */
    print("child1 starts");
    r4=s_service(S_CREAPROC,&gchild1state);
    DO_MSGSEND();
    r4=s_service(S_CREAPROC,&gchild2state);
    DO_MSGSEND();
    
    r4=0;
    r3=0;
    DO_MSGRECV();
}
child2()
{
    register int    r4,r3,r2;
    r4=0;
    r3=0;
    DO_MSGRECV();
    r3=r4; /* set the message as the parent's id */
    print("child1 starts");
    r4=s_service(S_CREAPROC,&gchild3state);
    DO_MSGSEND();
    r4=s_service(S_CREAPROC,&gchild4state);
    DO_MSGSEND();
    
    r4=0;
    r3=0;
    DO_MSGRECV();

}

/*p8leaf -- code for leaf processes*/

p8leaf()
{
    register int    r4,r3,r2;
    r4=0;
    r3=0;
    DO_MSGRECV();

    print("leaf process starts");

    r4=r3; /* put grandparent address into r4 */    
    DO_MSGSEND();
    
    r4=0;
    r3=0;
    DO_MSGRECV();
}




[INDICE CODICE]