/* * threat: beat up on minithreads. */ #include #include "minithread.h" #include "mutex.h" #include #define MAXTHREADS 20 #define MAX_SPIN_DELAY 10000 struct SlotObj { minithread_t thread; int occupied; }; struct SlotObj slots[MAXTHREADS]; mutex_t slotmu; int testing; /* 1 iff test is still in progress*/ int numThreads = 0; /* number of threads alive */ int min(i,j) int i; int j; { if (i <= j) return (i); else return (j); } void Assert(cond, msg) int cond; char *msg; { if (! cond) { fprintf(stderr,"Assertion failed: %s\n",msg); /* exit(-1);*/ } } void Spin(loops) int loops; { int i; for (i = 1; i < loops; i++) ; minithread_yield(); } void AwaitChar() { extern int select(); extern int read(); int readmask; struct timeval timeout; char c; timeout.tv_sec = 0; timeout.tv_usec = 0; for (;;) { minithread_yield(); /* mipsi hates select() */ /* readmask = 1; select(1, &readmask, 0, 0, &timeout); if (readmask) { read(0, &c, 1); return; } else { minithread_yield(); } */ } } /******************************/ /* Terminal Printout Routines */ /******************************/ extern int time(); mutex_t printmu; int tcCount = 0; int startTime; int elapsedTime; void PrintThreadCount(tc) int tc; { if (tcCount == 20) { tcCount = 0; /* Mipsi doesnt like the following */ /* elapsedTime = time(0) - startTime; printf("%d:", elapsedTime / 3600); elapsedTime %= 3600; printf("%02d:", elapsedTime / 60); elapsedTime %= 60; printf("%02d)", elapsedTime);*/ } printf("%d",tc); fflush(stdout); tcCount++; } /*****************************/ /* Random Number Generator */ /*****************************/ #define AA 38737 #define CC 131071 #define MM 43691 int seed = 23311; int Random(minval, maxval) int minval; int maxval; { int span; if (minval > maxval) return (minval); span = (maxval - minval) + 1; seed = (AA*seed + CC) % MM; return (minval + (seed % span)); } /****************/ /* Mutex Test */ /****************/ mutex_t mCountmu; mutex_t mTestmu; int mCount = 0; minithread_t holder = 0; void HitMutex() { int maxThreshold = MAXTHREADS / 4; int threshold; mutex_lock(mCountmu); mCount++; mutex_unlock(mCountmu); mutex_lock(mTestmu); holder = minithread_self(); for (;;) { Spin(MAX_SPIN_DELAY); threshold = Random(0, maxThreshold); if (threshold < mCount) break; } mutex_lock(printmu); printf( "["); PrintThreadCount(mCount); printf( "]"); fflush(stdout); mutex_unlock(printmu); mutex_unlock(mTestmu); mutex_lock(mCountmu); mCount--; mutex_unlock(mCountmu); } /*****************************/ /* Condition Variable Test */ /*****************************/ mutex_t cvmu; condition_t cv; int cvCount = 0; void BroadCastCV(); void HitCV() { int maxThreshold = MAXTHREADS / 2; int threshold; mutex_lock(cvmu); threshold = Random(0, min(maxThreshold, numThreads-1)); if (cvCount < threshold) { cvCount++; condition_wait(cvmu, cv); } else { BroadCastCV(); } mutex_unlock(cvmu); } void BroadCastCV() { condition_broadcast(cv); mutex_lock(printmu); printf( "{"); PrintThreadCount(cvCount); printf( "}"); fflush(stdout); mutex_unlock(printmu); cvCount = 0; } void PokeCV() { mutex_lock(cvmu); BroadCastCV(); mutex_unlock(cvmu); } /*********************************/ /* Spawning and Slot machinery */ /*********************************/ void Root(); void Spawn(slotNum) int slotNum; { Assert((slots[slotNum].occupied == 0), "Spawn: occupied slot"); slots[slotNum].occupied = 1; slots[slotNum].thread = minithread_fork(Root, slotNum); numThreads++; } void Die(slotNum) int slotNum; { PokeCV(); /* in case cv waiters were depending on this thread*/ slots[slotNum].occupied = 0; slots[slotNum].thread = 0; numThreads--; } int SpawnOrDie(int me) { int slotNum; int breed; char* c; mutex_lock(slotmu); mutex_lock(printmu); PrintThreadCount(numThreads); mutex_unlock(printmu); for (;;) { slotNum = Random(0, MAXTHREADS-1); if (slotNum != me) break; } breed = (testing && (! slots[slotNum].occupied)); if (breed) { Spawn(slotNum); c = "+"; } else { Die(me); c = "-"; } mutex_lock(printmu); printf("%s", c); fflush(stdout); mutex_unlock(printmu); mutex_unlock(slotmu); return (breed); } void InitSlots() { int slotNum; for (slotNum = 0; slotNum < MAXTHREADS; slotNum++) { slots[slotNum].occupied = 0; slots[slotNum].thread = 0; } } /***********************************/ /* Root procedure for all threads */ /***********************************/ void Root(int me) { int alive = 1; int action; mutex_lock(slotmu); Assert(slots[me].occupied && (slots[me].thread == minithread_self()), "Root: slot not mine"); if(!(slots[me].occupied && (slots[me].thread == minithread_self()))) { printf("failure!!! : me = %d, slots[me].occupied = %d slots[me].thread = %d minithread_self = %d\n", me,slots[me].occupied , slots[me].thread,minithread_self()); } mutex_unlock(slotmu); while (alive) { action = Random(1, 8); switch (action) { case 1: alive = SpawnOrDie(me); break; case 2: HitMutex(); break; case 3: case 4: case 5: case 6: case 7: case 8: HitCV(); break; default: ; } Spin(Random(1, MAX_SPIN_DELAY)); } } /****************/ /* Main Program */ /****************/ mainmain() { printf( "Begin minithread test. Max threads = %d\n", MAXTHREADS); printf( " [n] - n threads waiting for the mutex (incl holder)\n"); printf( " {n} - n threads waiting on the condition variable\n"); printf( " n - total number of threads\n"); printf( " + - thread spawned\n"); printf( " - - thread died\n"); printf( " (h:mm:ss) - elapsed time\n"); printf( "Press CTRL C to terminate.\n\n"); fflush(stdout); /* mipsi isn't happy with the time() sys calls */ /* startTime = time(0);*/ testing = 1; mutex_lock(slotmu); Spawn(0); mutex_unlock(slotmu); AwaitChar(); mutex_lock(printmu); printf( "\nShutting down...\n"); mutex_unlock(printmu); testing = 0; exit(0); } mutex_t new_mutex() { mutex_t mu; mu = mutex_create(); mutex_initialize(mu); return mu; } condition_t new_condition() { condition_t c; c = condition_create(); condition_initialize(c); return c; } main() { slotmu = new_mutex(); printmu = new_mutex(); mCountmu = new_mutex(); mTestmu = new_mutex(); cvmu = new_mutex(); cv = new_condition(); InitSlots(); /* don't want to call minithread_system_initialize */ minithread_fork(mainmain,0); }