Tswitch
Clients for Tswitch
Clients for the F06 Assignment
This program creates and destroys threads in a somewhat
random fashion. Threads can exit themselves or be killed
by another. Several raven
threads execute th_wait
on randomly-selected worker threads.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <thlib.h>
/*
* This program tests the thread scheduler by creating and destroying
* processes randomly.
*/
/* A collection of thread records. */
struct trec {
th_id_t id;
char name[40];
unsigned char status;
};
#define INUSE 0x1
#define DEAD 0x2
#define WAITED 0x4
#define NENT 25
int nthreads = 0;
struct trec members[NENT];
static char *name_parts[] = { "non", "gol", "wan", "weg", "ol",
"tag", "pul", "noc", "tap", "bink",
"at", "balt", "rut", "qua", "wye" };
/* Choose an entry at random. */
struct trec * randent(void)
{
return members + random() % NENT;
}
/* Bomb set. */
char bomb = 0;
/* Thread starting threshhold. */
int startthresh = (9*NENT) / 10;
/* Raven function waits on processes to try and clean them up. */
int raven(void)
{
while(1) {
/* Choose an entry at random. If it's valid, then we'll
wait on it. */
struct trec *targ = randent();
if((targ->status & (INUSE|WAITED)) == INUSE) {
/* Claim it and snooze. */
int ret;
targ->status |= WAITED;
ret = th_wait(targ->id);
/* Give status. */
--nthreads;
targ->status = 0;
if(ret == -1)
printf("%s was executed.\n", targ->name);
else if(ret == -2)
printf("%s was blown up.\n", targ->name);
else
printf("%s died at %d.\n", targ->name, ret);
} else
/* Just wait for the next opportunity. */
th_yield();
}
}
/* Initialize a table entry for a new thread. */
void trec_init(struct trec *ent)
{
strcat(strcat(strcpy(ent->name, name_parts[random() % 15]), " "),
name_parts[random() % 15]);
ent->id = th_me();
ent->status = INUSE;
printf("%s started\n", ent->name);
}
/* Generator thread. */
int gen(struct trec *ent)
{
int age = 0;
/* Choose a random name. */
trec_init(ent);
while(1) {
struct trec *targ;
th_yield();
++age;
/* See if we hit a bomb. */
if(bomb) {
bomb = 0;
printf("%s boom!\n", ent->name);
ent->status |= DEAD;
th_exit(-2);
}
/* See if we're going to set a bomb. */
if(random() % 20 == 0) {
bomb = 1;
printf("%s set bomb\n", ent->name);
continue;
}
/* See if we croak. */
if(age > 5 && random() % 15 == 0) {
printf("%s done for\n", ent->name);
ent->status |= DEAD;
th_exit(age);
}
/* Choose a random position. */
targ = randent();
if(targ->status == 0) {
/* Maybe start a new thread there? */
if(random() % 100 < startthresh) {
th_id_t k;
printf("%s starting new thread\n", ent->name);
++nthreads;
if(th_fork() == ARE_CHILD) {
trec_init(ent = targ);
age = 0;
}
//startthresh /= 2;
startthresh = 10 * startthresh / 15;
}
} else if(!(targ->status & DEAD)) {
/* Maybe kill it? */
if(random() % 10 == 0) {
printf("%s terminating %s\n", ent->name,
targ->name);
th_kill(targ->id, -1);
targ->status |= DEAD;
}
}
}
}
main()
{
int i;
th_id_t r[3];
/* Get us started. */
for(i = 0; i < NENT; ++i) members[i].status = 0;
th_init();
/* Three ravens. */
if((r[0] = th_fork()) == ARE_CHILD) raven();
if((r[1] = th_fork()) == ARE_CHILD) raven();
if((r[2] = th_fork()) == ARE_CHILD) raven();
/* First three workers. */
if(th_fork() == ARE_CHILD) gen(&members[0]);
if(th_fork() == ARE_CHILD) gen(&members[1]);
if(th_fork() == ARE_CHILD) gen(&members[2]);
nthreads = 3;
/* Let it all happen. */
while(nthreads) th_yield();
for(i = 0; i < 3; ++i) {
th_kill(r[i], 0);
th_wait(r[i]);
}
}