MC logo

Thread Demolition Derby

^  Dr. Bennet

Tswitch

Main Page
F06 Assignment
Download Library
CCSC '07 Paper

Clients for Tswitch

Save And Restore
Restack
Multiple Stacks

Clients for the F06 Assignment

Simple
Thread Demolition Derby
Graph Search
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.

<<Simple Two-Thread Test thlibt3.c Graph Search>>
#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]);
        }
}

<<Simple Two-Thread Test Graph Search>>