// Tests creation, yielding, destruction, and yielding to a nonexistent thread // arg is the string to print within the method. void funkyTown(char* arg) { printf("%s",arg); Tid weave = ULT_CreateThread((void (*)(void *))doALittleDance, "Make a little love\n"); Tid ret = ULT_Yield(weave); assert(ret == weave); Tid ret2 = ULT_DestroyThread(weave); assert(ret2 == weave); Tid ret3 = ULT_Yield(ret2); assert(ret3 = ULT_INVALID); }
static void finale() { int ret; printf("Finale running\n"); ret = ULT_Yield(ULT_ANY); assert(ret == ULT_NONE); ret = ULT_Yield(ULT_ANY); assert(ret == ULT_NONE); printf("Done.\n"); /* * Stub should exit cleanly if there are no threads left to run. */ return; }
static void mbWorker0(Mailbox *mb) { ULT_CreateThread((void (*)(void *))mbWorker1, mb); int myPart = MAXMAIL/2; int ii; for(ii = 0; ii < myPart; ii++){ mb_increment(mb, 0); ULT_Yield(ULT_ANY); ULT_Yield(ULT_ANY); } return; }
static void doPotato(int mySlot)//You will want to create data structures like a ready list (for TCBs that are { int ret; int moved; int passes = 0; printf("Made it to doPotato %d\n", mySlot); while(1){ assert(alarmIsEnabled()); moved = tryMovePotato(mySlot); if(moved){ passes++; printf("%d passes potato for %d-st/nd/rd time \n", mySlot, passes); } /* * Add some yields by some threads to scramble the list */ if(mySlot > 4){ int ii; for(ii = 0; ii < mySlot - 4; ii++){ ret = ULT_Yield(ULT_ANY); assert(ULT_isOKRet(ret)); } } } }
static void doPotato(int mySlot) { int ret; int moved; int passes = 0; printf("Made it to doPotato %d\n", mySlot); while(1){ assert(alarmIsEnabled()); moved = tryMovePotato(mySlot); if(moved){ passes++; printf("%d passes potato for %d-st/nd/rd time \n", mySlot, passes); } /* * Add some yields by some threads to scramble the list */ if(mySlot > 4){ int ii; for(ii = 0; ii < mySlot - 4; ii++){ ret = ULT_Yield(ULT_ANY); assert(tidValid(ret)); } } } }
// Tests that arg was passed correctly and yields to another thread on the readyQueue. // arg is the string to compare. void doALittleDance(char* arg) { assert(strcmp(arg, "Make a little love\n") == 0); while(1) { ULT_Yield(ULT_ANY); } }
static void hello(char *msg) { Tid ret; printf("Made it to hello() in called thread\n"); printf("Message: %s\n", msg); ret = ULT_Yield(ULT_SELF); assert(ULT_isOKRet(ret)); printf("Thread returns from first yield\n"); ret = ULT_Yield(ULT_SELF); assert(ULT_isOKRet(ret)); printf("Thread returns from second yield\n"); while(1){ ULT_Yield(ULT_ANY); } }
static void mbWorker1(Mailbox *mb) { int myPart = MAXMAIL - MAXMAIL/2; int ii; for(ii = 0; ii < myPart; ii++){ mb_increment(mb, 1); ULT_Yield(ULT_ANY); } return; }
int main(int argc, char **argv) { printf("Starting our tests....\n"); Tid IAmNotValid = 5; Tid linen; Tid cotton; Tid silk; // Get it? Because they are threads... printf("Testing destruction of a nonexistent thread.\n"); IAmNotValid = ULT_DestroyThread(IAmNotValid); assert(IAmNotValid == ULT_INVALID); printf("Testing creation of a thread and yielding to it.\n"); linen = ULT_CreateThread((void (*)(void *))doALittleDance, "Make a little love\n"); cotton = ULT_Yield(linen); assert(cotton == linen); printf("Testing destruction of a thread.\n"); Tid ret = ULT_DestroyThread(linen); assert(ret == linen); printf("Testing creation of a thread with a more complex root function, and then yielding to it.\n"); silk = ULT_CreateThread((void (*)(void *))funkyTown, "In the funkyTown method and the arg was passed just fine. Woohoo.\n"); Tid cloth = ULT_Yield(silk); assert(cloth == silk); printf("Testing destruction of a thread that has already terminated naturally.\n"); Tid deleteAttempt = ULT_DestroyThread(silk); assert(deleteAttempt == ULT_INVALID); printf("You have passed all your tests! Nice dude!\n"); return 1; }
//destroys the thread whose identifier is tid //caller continues to execute and receives the result Tid ULT_DestroyThread(Tid tid) { ULT_Maintainence(); if(tid == ULT_ANY) { //destroy any thread except the caller //if there are no more other threads available to destroy, return ULT_NONE if (alive->head->next == NULL) return ULT_NONE; if (alive->head == NULL) return ULT_NONE; Thread* target; do { target = ThreadListRemoveEnd(alive); if (!target) return ULT_NONE; ThreadListAddToHead(alive, target); } while(target->id == runningThread->id); ThreadListRemove(alive, target->id); ThreadListAddToHead(zombie, target); numberOfThreads--; //printf("Thead[%d] zombified\n", target->id); return target->id; } else if(tid == ULT_SELF) { //destroy the caller, function does not return //schedule another to run ThreadListRemove(alive, runningThread->id); ThreadListAddToHead(zombie, runningThread); numberOfThreads--; //printf("Thead[%d] zombified\n", runningThread->id); ULT_Yield(ULT_ANY); return ULT_NONE; //return runningThread->id; } else if(tid > 0) { //destroy the thread with id tid Thread* target = ThreadListFind(alive, tid); if (!target) return ULT_INVALID; ThreadListRemove(alive, target->id); ThreadListAddToHead(zombie, target); numberOfThreads--; //printf("Thead[%d] zombified\n", target->id); return target->id; } else return ULT_FAILED; }
static void pcTestConsumer(PCTestArgs *args) { int ii, jj; for(ii = 0; ii < args->count; ii++){ if(vverbose){ printf("consumer getting color %d\n", args->color); } PC_Get(args->pc, args->color); if(vverbose){ printf("consumer done getting color %d\n", args->color); } for(jj = 0; jj < args->color + 1; jj++){ ULT_Yield(ULT_ANY); } } mb_increment(args->mb, 0); free(args); }
void basicThreadTests() { Tid ret; Tid ret2; printf("Starting tests...\n"); /* * Initial thread yields */ ret = ULT_Yield(ULT_SELF); assert(ULT_isOKRet(ret)); printf("Initial thread returns from Yield(SELF)\n"); ret = ULT_Yield(0); /* See ULT.h -- initial thread must be Tid 0 */ assert(ULT_isOKRet(ret)); printf("Initial thread returns from Yield(0)\n"); ret = ULT_Yield(ULT_ANY); assert(ret == ULT_NONE); printf("Initial thread returns from Yield(ANY)\n"); ret = ULT_Yield(0xDEADBEEF); assert(ret == ULT_INVALID); printf("Initial thread returns from Yield(INVALID)\n"); ret = ULT_Yield(16); assert(ret == ULT_INVALID); printf("Initial thread returns from Yield(INVALID2)\n"); /* * Create a thread */ ret = ULT_CreateThread((void (*)(void *))hello, "World"); assert(ULT_isOKRet(ret)); ret2 = ULT_Yield(ret); assert(ret2 == ret); /* * Create 10 threads */ int ii; static const int NTHREAD = 10; Tid children[NTHREAD]; char msg[NTHREAD][1024]; for(ii = 0; ii < NTHREAD; ii++){ ret = snprintf(msg[ii], 1023, "Hello from thread %d\n", ii); assert(ret > 0); children[ii] = ULT_CreateThread((void (*)(void *))hello, msg[ii]); assert(ULT_isOKRet(children[ii])); } for(ii = 0; ii < NTHREAD; ii++){ ret = ULT_Yield(children[ii]); assert(ret == children[ii]); } /* * Destroy 11 threads we just created */ ret = ULT_DestroyThread(ret2); assert(ret == ret2); for(ii = 0; ii < NTHREAD; ii++){ ret = ULT_DestroyThread(children[ii]); assert(ret == children[ii]); } /* * Create maxthreads-1 threads */ printf("Creating %d threads\n", ULT_MAX_THREADS-1); for(ii = 0; ii < ULT_MAX_THREADS-1; ii++){ ret = ULT_CreateThread((void (*)(void *))fact, (void *)10); assert(ULT_isOKRet(ret)); } /* * Now we're out of threads. Next create should fail. */ ret = ULT_CreateThread((void (*)(void *))fact, (void *)10); assert(ret == ULT_NOMORE); /* * Now let them all run. */ printf("Running %d threads\n", ULT_MAX_THREADS-1); for(ii = 0; ii < ULT_MAX_THREADS; ii++) { ret = ULT_Yield(ii); if(ii == 0){ /* * Guaranteed that first yield will find someone. * Later ones may or may not depending on who * stub schedules on exit. */ assert(ULT_isOKRet(ret)); } } /* * They should have cleaned themselves up when * they finished running. Create maxthreads-1 threads. */ printf("Creating %d threads\n", ULT_MAX_THREADS-1); for(ii = 0; ii < ULT_MAX_THREADS-1; ii++){ ret = ULT_CreateThread((void (*)(void *))fact, (void *)10); assert(ULT_isOKRet(ret)); } /* * Now destroy some explicitly and let the others run */ printf("Destorying %d threads, running the rest\n", ULT_MAX_THREADS/2); for(ii = 0; ii < ULT_MAX_THREADS; ii+=2){ ret = ULT_DestroyThread(ULT_ANY); assert(ULT_isOKRet(ret)); } for(ii = 0; ii < ULT_MAX_THREADS; ii++){ ret = ULT_Yield(ii); } printf("Trying some destroys even though I'm the only thread\n"); ret = ULT_DestroyThread(ULT_ANY); assert(ret == ULT_NONE); ret = ULT_DestroyThread(42); assert(ret == ULT_INVALID); ret = ULT_DestroyThread(-42); assert(ret == ULT_INVALID); ret = ULT_DestroyThread(ULT_MAX_THREADS + 1000); assert(ret == ULT_INVALID); /* * Create a thread that destroys itself. * Control should come back here after * that thread runs. */ printf("Testing destroy self\n"); int flag = setFlag(0); ret = ULT_CreateThread((void (*)(void *))suicide, NULL); assert(ULT_isOKRet(ret)); ret = ULT_Yield(ret); assert(ULT_isOKRet(ret)); flag = setFlag(0); assert(flag == 1); /* Other thread ran */ /* That thread is gone now */ ret = ULT_Yield(ret); assert(ret == ULT_INVALID); }
void lockTests() { ULT_Yield(ULT_ANY); startAlarmHelper(); interruptsQuiet(); /* * One mailbox */ Mailbox *mb = (Mailbox *)malloc(sizeof(Mailbox)); assert(mb); mb_init(mb, 2, MAXMAIL); ULT_CreateThread((void (*)(void *))mbWorker0, mb); while(!mb_checkDone(mb)){ ULT_Yield(ULT_ANY); } int jj; for(jj = 0; jj < 1000; jj++){ ULT_Yield(ULT_ANY); } assert(mb_checkDone(mb)); free(mb); printf("One mailbox, two threads OK\n"); /* * Two mailboxen */ mb = (Mailbox *)malloc(sizeof(Mailbox)); assert(mb); mb_init(mb, 2, MAXMAIL); Mailbox *mb2 = (Mailbox *)malloc(sizeof(Mailbox)); assert(mb2); mb_init(mb2, 2, MAXMAIL); ULT_CreateThread((void (*)(void *))mbWorker0, mb); ULT_CreateThread((void (*)(void *))mbWorker0, mb2); while(!mb_checkDone(mb)){ ULT_Yield(ULT_ANY); } for(jj = 0; jj < 1000; jj++){ ULT_Yield(ULT_ANY); } assert(mb_checkDone(mb)); while(!mb_checkDone(mb2)){ ULT_Yield(ULT_ANY); } for(jj = 0; jj < 1000; jj++){ ULT_Yield(ULT_ANY); } assert(mb_checkDone(mb2)); free(mb); free(mb2); printf("Two mailboxen, four threads OK\n"); printf("lockTests OK\n"); }