/*********************************P1TEST.C*******************************
*
* Test program for the modules ASL and pcbQueues (phase 1).
*
* Produces progress messages on terminal 0 in addition
* to the array ``okbuf[]''
* Error messages will also appear on terminal 0 in
* addition to the array ``errbuf[]''.
*
* Aborts as soon as an error is detected.
*
* Modified by Michael Goldweber on May 2020
*/
#include "../h/pandos_const.h"
#include "../h/pandos_types.h"
#include "/usr/include/umps3/umps/libumps.h"
#include "../h/pcb.h"
#include "../h/asl.h"
#define MAXPROC 20
#define MAXSEM MAXPROC
char okbuf[2048]; /* sequence of progress messages */
char errbuf[128]; /* contains reason for failing */
char msgbuf[128]; /* nonrecoverable error message before shut down */
int sem[MAXSEM];
int onesem;
pcb_t *procp[MAXPROC], *p, *qa, *q, *firstproc, *lastproc, *midproc;
char *mp = okbuf;
#define TRANSMITTED 5
#define ACK 1
#define PRINTCHR 2
#define CHAROFFSET 8
#define STATUSMASK 0xFF
#define TERM0ADDR 0x10000254
typedef unsigned int devreg;
/* This function returns the terminal transmitter status value given its address */
devreg termstat(memaddr * stataddr) {
return((*stataddr) & STATUSMASK);
}
/* This function prints a string on specified terminal and returns TRUE if
* print was successful, FALSE if not */
unsigned int termprint(char * str, unsigned int term) {
memaddr * statusp;
memaddr * commandp;
devreg stat;
devreg cmd;
unsigned int error = FALSE;
if (term < DEVPERINT) {
/* terminal is correct */
/* compute device register field addresses */
statusp = (devreg *) (TERM0ADDR + (term * DEVREGSIZE) + (TRANSTATUS * DEVREGLEN));
commandp = (devreg *) (TERM0ADDR + (term * DEVREGSIZE) + (TRANCOMMAND * DEVREGLEN));
/* test device status */
stat = termstat(statusp);
if (stat == READY || stat == TRANSMITTED) {
/* device is available */
/* print cycle */
while (*str != EOS && !error) {
cmd = (*str << CHAROFFSET) | PRINTCHR;
*commandp = cmd;
/* busy waiting */
stat = termstat(statusp);
while (stat == BUSY)
stat = termstat(statusp);
/* end of wait */
if (stat != TRANSMITTED)
error = TRUE;
else
/* move to next char */
str++;
}
}
else
/* device is not available */
error = TRUE;
}
else
/* wrong terminal device number */
error = TRUE;
return (!error);
}
/* This function placess the specified character string in okbuf and
* causes the string to be written out to terminal0 */
void addokbuf(char *strp) {
char *tstrp = strp;
while ((*mp++ = *strp++) != '\0')
;
mp--;
termprint(tstrp, 0);
}
/* This function placess the specified character string in errbuf and
* causes the string to be written out to terminal0. After this is done
* the system shuts down with a panic message */
void adderrbuf(char *strp) {
char *ep = errbuf;
char *tstrp = strp;
while ((*ep++ = *strp++) != '\0');
termprint(tstrp, 0);
PANIC();
}
void main() {
int i;
initPcbs();
addokbuf("Initialized process control blocks \n");
/* Check allocProc */
for (i = 0; i < MAXPROC; i++) {
if ((procp[i] = allocPcb()) == NULL)
adderrbuf("allocPcb: unexpected NULL ");
}
if (allocPcb() != NULL) {
adderrbuf("allocPcb: allocated more than MAXPROC entries ");
}
addokbuf("allocPcb ok \n");
/* return the last 10 entries back to free list */
for (i = 10; i < MAXPROC; i++)
freePcb(procp[i]);
addokbuf("freed 10 entries \n");
/* create a 10-element process queue */
qa = NULL;
if (!emptyProcQ(qa)) adderrbuf("emptyProcQ: unexpected FALSE ");
addokbuf("Inserting... \n");
for (i = 0; i < 10; i++) {
if ((q = allocPcb()) == NULL)
adderrbuf("allocPcb: unexpected NULL while insert ");
switch (i) {
case 0:
firstproc = q;
break;
case 5:
midproc = q;
break;
case 9:
lastproc = q;
break;
default:
break;
}
insertProcQ(&qa, q);
}
addokbuf("inserted 10 elements \n");
if (emptyProcQ(qa)) adderrbuf("emptyProcQ: unexpected TRUE" );
/* Check outProc and headProc */
if (headProcQ(qa) != firstproc)
adderrbuf("headProcQ failed ");
q = outProcQ(&qa, firstproc);
if (q == NULL || q != firstproc)
adderrbuf("outProcQ failed on first entry ");
freePcb(q);
q = outProcQ(&qa, midproc);
if (q == NULL || q != midproc)
adderrbuf("outProcQ failed on middle entry ");
freePcb(q);
if (outProcQ(&qa, procp[0]) != NULL)
adderrbuf("outProcQ failed on nonexistent entry ");
addokbuf("outProcQ ok \n");
/* Check if removeProc and insertProc remove in the correct order */
addokbuf("Removing... \n");
for (i = 0; i < 8; i++) {
if ((q = removeProcQ(&qa)) == NULL)
adderrbuf("removeProcQ: unexpected NULL ");
freePcb(q);
}
if (q != lastproc)
adderrbuf("removeProcQ: failed on last entry ");
if (removeProcQ(&qa) != NULL)
adderrbuf("removeProcQ: removes too many entries ");
if (!emptyProcQ(qa))
adderrbuf("emptyProcQ: unexpected FALSE ");
addokbuf("insertProcQ, removeProcQ and emptyProcQ ok \n");
addokbuf("process queues module ok \n");
addokbuf("checking process trees...\n");
if (!emptyChild(procp[2]))
adderrbuf("emptyChild: unexpected FALSE ");
/* make procp[1] through procp[9] children of procp[0] */
addokbuf("Inserting... \n");
for (i = 1; i < 10; i++) {
insertChild(procp[0], procp[i]);
}
addokbuf("Inserted 9 children \n");
if (emptyChild(procp[0]))
adderrbuf("emptyChild: unexpected TRUE ");
/* Check outChild */
q = outChild(procp[1]);
if (q == NULL || q != procp[1])
adderrbuf("outChild failed on first child ");
q = outChild(procp[4]);
if (q == NULL || q != procp[4])
adderrbuf("outChild failed on middle child ");
if (outChild(procp[0]) != NULL)
adderrbuf("outChild failed on nonexistent child ");
addokbuf("outChild ok \n");
/* Check removeChild */
addokbuf("Removing... \n");
for (i = 0; i < 7; i++) {
if ((q = removeChild(procp[0])) == NULL)
adderrbuf("removeChild: unexpected NULL ");
}
if (removeChild(procp[0]) != NULL)
adderrbuf("removeChild: removes too many children ");
if (!emptyChild(procp[0]))
adderrbuf("emptyChild: unexpected FALSE ");
addokbuf("insertChild, removeChild and emptyChild ok \n");
addokbuf("process tree module ok \n");
for (i = 0; i < 10; i++)
freePcb(procp[i]);
/* check ASL */
initASL();
addokbuf("Initialized active semaphore list \n");
/* check removeBlocked and insertBlocked */
addokbuf("insertBlocked test #1 started \n");
for (i = 10; i < MAXPROC; i++) {
procp[i] = allocPcb();
if (insertBlocked(&sem[i], procp[i]))
adderrbuf("insertBlocked(1): unexpected TRUE ");
}
addokbuf("insertBlocked test #2 started \n");
for (i = 0; i < 10; i++) {
procp[i] = allocPcb();
if (insertBlocked(&sem[i], procp[i]))
adderrbuf("insertBlocked(2): unexpected TRUE ");
}
/* check if semaphore descriptors are returned to free list */
p = removeBlocked(&sem[11]);
if (insertBlocked(&sem[11],p))
adderrbuf("removeBlocked: fails to return to free list ");
if (insertBlocked(&onesem, procp[9]) == FALSE)
adderrbuf("insertBlocked: inserted more than MAXPROC ");
addokbuf("removeBlocked test started \n");
for (i = 10; i< MAXPROC; i++) {
q = removeBlocked(&sem[i]);
if (q == NULL)
adderrbuf("removeBlocked: wouldn't remove ");
if (q != procp[i])
adderrbuf("removeBlocked: removed wrong element ");
if (insertBlocked(&sem[i-10], q))
adderrbuf("insertBlocked(3): unexpected TRUE ");
}
if (removeBlocked(&sem[11]) != NULL)
adderrbuf("removeBlocked: removed nonexistent blocked proc ");
addokbuf("insertBlocked and removeBlocked ok \n");
if (headBlocked(&sem[11]) != NULL)
adderrbuf("headBlocked: nonNULL for a nonexistent queue ");
if ((q = headBlocked(&sem[9])) == NULL)
adderrbuf("headBlocked(1): NULL for an existent queue ");
if (q != procp[9])
adderrbuf("headBlocked(1): wrong process returned ");
p = outBlocked(q);
if (p != q)
adderrbuf("outBlocked(1): couldn't remove from valid queue ");
q = headBlocked(&sem[9]);
if (q == NULL)
adderrbuf("headBlocked(2): NULL for an existent queue ");
if (q != procp[19])
adderrbuf("headBlocked(2): wrong process returned ");
p = outBlocked(q);
if (p != q)
adderrbuf("outBlocked(2): couldn't remove from valid queue ");
p = outBlocked(q);
if (p != NULL)
adderrbuf("outBlocked: removed same process twice.");
if (headBlocked(&sem[9]) != NULL)
adderrbuf("out/headBlocked: unexpected nonempty queue ");
addokbuf("headBlocked and outBlocked ok \n");
addokbuf("ASL module ok \n");
addokbuf("So Long and Thanks for All the Fish\n");
}