/* * Run multiple pairs of threads, each running make_dir_thread or rm_dir_thread * with a different parameter. One will be creating a directory full of files, * and the other will be deleting them. They do not move in lock step, so for * a few threads, say 4 or 5, the system is likely to run out of i-nodes. * * The calling format (from the kshell) is * directory_test <num>, where num is an integer. The number is parsed into an * int and pairs of threads with parameter 0..num are created. This code then * waits for them and prints each exit value. */ int faber_directory_test(kshell_t *ksh, int argc, char **argv) { KASSERT(NULL != ksh); proc_t *p = NULL; /* A process to run in */ kthread_t *thr = NULL; /* A thread to run in it */ char tname[TESTBUFLEN]; /* A thread name */ int pid = 0; /* Process ID from do_waitpid (who exited?) */ int lim = 1; /* Number of processes to run */ int rv = 0; /* Return values */ int i = 0; /* Scratch */ KASSERT(NULL != ksh); if ( argc > 1) { /* Oh, barf */ if ( sscanf(argv[1], "%d", &lim) != 1) lim = 1; /* A little bounds checking */ if ( lim < 1 || lim > 255 ) lim = 1; } /* Start pairs of processes */ for ( i = 0; i< lim; i++) { /* The maker process */ snprintf(tname, TESTBUFLEN, "thread%03d", i); p = proc_create(tname); KASSERT(NULL != p); thr = kthread_create(p, make_dir_thread, i, NULL); KASSERT(NULL != thr); sched_make_runnable(thr); /* The deleter process */ snprintf(tname, TESTBUFLEN, "rmthread%03d", i); p = proc_create(tname); KASSERT(NULL != p); thr = kthread_create(p, rm_dir_thread, i, NULL); KASSERT(NULL != thr); sched_make_runnable(thr); } /* Wait for children and report their error codes */ while ( ( pid = do_waitpid(-1, 0 , &rv) ) != -ECHILD) if ( rv < 0 ) kprintf(ksh, "Child %d: %d %s\n", pid, rv, strerror(-rv)); else kprintf(ksh, "Child %d: %d\n", pid, rv); return rv; }
void * sunghan_test(int arg1, void *arg2) { int status; int proc_count = 0; pid_t proc_pid[3]; int i; dbg(DBG_TEST, ">>> Start running sunghan_test()...\n"); mynode.length = 0; kmutex_init(&mynode.my_mutex); sched_queue_init(&mynode.my_queue); proc_t *p1 = proc_create("add_node"); KASSERT(NULL != p1); kthread_t *thr1 = kthread_create(p1, add_my_node, 0, NULL); KASSERT(NULL != thr1); sched_make_runnable(thr1); proc_pid[proc_count++] = p1->p_pid; proc_t *p2 = proc_create("remove_node"); KASSERT(NULL != p2); kthread_t *thr2 = kthread_create(p2, remove_my_node, 0, NULL); KASSERT(NULL != thr2); sched_make_runnable(thr2); proc_pid[proc_count++] = p2->p_pid; proc_t *p3 = proc_create("watch_dog"); KASSERT(NULL != p3); kthread_t *thr3 = kthread_create(p3, watch_dog, 0, NULL); KASSERT(NULL != thr3); sched_make_runnable(thr3); proc_pid[proc_count++] = p3->p_pid; for (i=0; i<2; ++i) { do_waitpid(proc_pid[i], 0, &status); } sched_broadcast_on(&mynode.my_queue); do_waitpid(proc_pid[2], 0, &status); while (!do_waitpid(p2->p_pid, 0, &status)); dbg(DBG_TEST, "sunghan_test() terminated\n"); return NULL; }
static void test_locking_and_cancelling(){ dbg(DBG_TEST, "testing kmutex behavior with cancellation\n"); kmutex_t m; kmutex_init(&m); proc_t *kmutex_proc = proc_create("kmutex_sleep_test_proc"); kthread_t *kmutex_thread = kthread_create(kmutex_proc, cancellable_lock_kmutex, NULL, (void *) &m); sched_make_runnable(kmutex_thread); kmutex_lock(&m); /* let kmutex_proc attempt to lock the mutex */ yield(); kthread_cancel(kmutex_thread, 0); kmutex_unlock(&m); int status; do_waitpid(kmutex_proc->p_pid, 0, &status); dbg(DBG_TESTPASS, "kmutex cancellation tests passed!\n"); }
/* * Should be called from the init proc */ static void test_proc_create(){ dbg(DBG_TEST, "testing proc_create\n"); proc_t *myproc = proc_create("myproc"); KASSERT(list_empty(&myproc->p_threads)); KASSERT(list_empty(&myproc->p_children)); KASSERT(sched_queue_empty(&myproc->p_wait)); KASSERT(myproc->p_pproc->p_pid == 1 && "created proc's parent isn't the init proc\n"); KASSERT(myproc->p_state == PROC_RUNNING); /* make sure it's in the proc list */ KASSERT(proc_lookup(myproc->p_pid) == myproc && "created proc not in proc list\n"); /* make sure it's in it's parent's child list */ KASSERT(in_child_list(myproc)); /* clean everything up */ kthread_t *mythread = kthread_create(myproc, simple_function, NULL, NULL); sched_make_runnable(mythread); int status; do_waitpid(myproc->p_pid, 0, &status); dbg(DBG_TESTPASS, "all proc_create tests passed!\n"); }
static void test_normal_locking(){ dbg(DBG_TEST, "testing normal mutex behavior\n"); kmutex_t m; kmutex_init(&m); proc_t *kmutex_proc = proc_create("kmutex_test_proc"); kthread_t *kmutex_thread = kthread_create(kmutex_proc, lock_kmutex_func, NULL, (void *) &m); sched_make_runnable(kmutex_thread); kmutex_lock(&m); /* let kmutex_proc attempt to lock the mutex */ yield(); kmutex_unlock(&m); /* lock and unlock the mutex with nobody on it's wait queue */ kmutex_lock(&m); kmutex_unlock(&m); int status; do_waitpid(kmutex_proc->p_pid, 0, &status); dbg(DBG_TESTPASS, "normal kmutex tests passed!\n"); }
static void test_proc_kill_all(){ dbg(DBG_TEST, "testing proc_kill_all when called from init proc\n"); test_proc_kill_all_func(NULL, NULL); dbg(DBG_TEST, "testing proc_kill_all when called from a different proc\n"); proc_t *test_proc = proc_create("proc_kill_all_func caller"); kthread_t *test_thread = kthread_create(test_proc, test_proc_kill_all_func, NULL, NULL); sched_make_runnable(test_thread); int status; pid_t retpid = do_waitpid(test_proc->p_pid, 0, &status); KASSERT(retpid == test_proc->p_pid); int i; for (i = 0; i < NUM_PROCS; i++){ pid_t retval = do_waitpid(-1, 0, &status); /* make sure we actually were able to wait on this pid, * meaning that it was properly killed in proc_kill_all */ KASSERT(retval > 0); } dbg(DBG_TESTPASS, "all proc_kill_all tests passed!\n"); }
static void simple_read(rw_args_t read_args){ proc_t *rp = proc_create("ata_read_proc"); kthread_t *rt = kthread_create(rp, read_func, 0, (void *) &read_args); sched_make_runnable(rt); int status2; do_waitpid(rp->p_pid, 0, &status2); }
static void simple_write(rw_args_t write_args){ proc_t *wp = proc_create("ata_write_proc"); kthread_t *wt = kthread_create(wp, write_func, 0, (void *) &write_args); sched_make_runnable(wt); int status; do_waitpid(wp->p_pid, 0, &status); }
void *init_child9(int arg1,void *arg2) { if(curtest == TEST_3){ while(curthr->kt_cancelled != 1){ sched_make_runnable(curthr); sched_switch(); }} return NULL; }
/* * A Thread function that exhibits a race condition on the race global. It * loads increments and stores race, context switching between each line of C. */ void *racer_test(int arg1, void *arg2) { int local; sched_make_runnable(curthr); sched_switch(); local = race; sched_make_runnable(curthr); sched_switch(); local++; sched_make_runnable(curthr); sched_switch(); race = local; sched_make_runnable(curthr); sched_switch(); do_exit(race); return NULL; }
/** * Once we're inside of idleproc_run(), we are executing in the context of the * first process-- a real context, so we can finally begin running * meaningful code. * * This is the body of process 0. It should initialize all that we didn't * already initialize in kmain(), launch the init process (initproc_run), * wait for the init process to exit, then halt the machine. * * @param arg1 the first argument (unused) * @param arg2 the second argument (unused) */ static void * idleproc_run(int arg1, void *arg2) { int status; pid_t child; dbg_print("Made it to idleproc_run\n"); /* create init proc */ kthread_t *initthr = initproc_create(); init_call_all(); GDB_CALL_HOOK(initialized); /* Create other kernel threads (in order) */ #ifdef __VFS__ /* Once you have VFS remember to set the current working directory * of the idle and init processes */ /* Here you need to make the null, zero, and tty devices using mknod */ /* You can't do this until you have VFS, check the include/drivers/dev.h * file for macros with the device ID's you will need to pass to mknod */ #endif /* Finally, enable interrupts (we want to make sure interrupts * are enabled AFTER all drivers are initialized) */ intr_enable(); /* Run initproc */ sched_make_runnable(initthr); /* Now wait for it */ child = do_waitpid(-1, 0, &status); KASSERT(PID_INIT == child); #ifdef __MTP__ kthread_reapd_shutdown(); #endif #ifdef __VFS__ /* Shutdown the vfs: */ dbg_print("weenix: vfs shutdown...\n"); vput(curproc->p_cwd); if (vfs_shutdown()) panic("vfs shutdown FAILED!!\n"); #endif /* Shutdown the pframe system */ #ifdef __S5FS__ pframe_shutdown(); #endif dbg_print("\nweenix: halted cleanly!\n"); GDB_CALL_HOOK(shutdown); hard_shutdown(); return NULL; }
kthread_t * sched_wakeup_on(ktqueue_t *q) { kthread_t *t = NULL; t = ktqueue_dequeue(q); sched_make_runnable(t); return t; }
void sched_broadcast_on(ktqueue_t *q) { //NOT_YET_IMPLEMENTED("PROCS: sched_broadcast_on"); while (!sched_queue_empty(q)) { kthread_t *thr = ktqueue_dequeue(q); sched_make_runnable(thr); } }
void sched_broadcast_on(ktqueue_t *q) { kthread_t *t; while (!sched_queue_empty(q)) { t = ktqueue_dequeue(q); sched_make_runnable(t); } }
/* * Create a process and a thread with the given name and calling teh given * function. Arg1 is passed to the function (arg2 is always NULL). The thread * is immediately placed on the run queue. A proc_thread_t is returned, giving * the caller a pointer to the new process and thread to coordinate tests. NB, * the proc_thread_t is returned by value, so there are no stack problems. */ static proc_thread_t start_proc(char *name, kthread_func_t f, int arg1) { proc_thread_t pt; pt.p = proc_create(name); pt.t = kthread_create(pt.p, f, arg1, NULL); KASSERT(pt.p && pt.t && "Cannot create thread or process"); sched_make_runnable(pt.t); return pt; }
/* * A Thread function that exhibits a race condition on the race global being * removed by a mutex. It loads increments and stores race, context switching * between each line of C after acquiring mutex. The mutex acquire cannot * be cancelled. */ void *mutex_uncancellable_test(int arg1, void *arg2) { int local; kmutex_lock(&mutex); sched_make_runnable(curthr); sched_switch(); local = race; sched_make_runnable(curthr); sched_switch(); local++; sched_make_runnable(curthr); sched_switch(); race = local; sched_make_runnable(curthr); sched_switch(); kmutex_unlock(&mutex); do_exit(race); return NULL; }
/* * If the thread's sleep is cancellable, we set the kt_cancelled * flag and remove it from the queue. Otherwise, we just set the * kt_cancelled flag and leave the thread on the queue. * * Remember, unless the thread is in the KT_NO_STATE or KT_EXITED * state, it should be on some queue. Otherwise, it will never be run * again. */ void sched_cancel(struct kthread *kthr) { //NOT_YET_IMPLEMENTED("PROCS: sched_cancel"); kthr->kt_cancelled = 1; if (kthr->kt_state == KT_SLEEP_CANCELLABLE) { ktqueue_remove(kthr->kt_wchan, kthr); sched_make_runnable(kthr); } }
int selftest(kshell_t *kshell, int argc, char **argv) { proc_t* selftest_proc = proc_create("self_test"); kthread_t *thread = kthread_create(selftest_proc,selftest_proc_run, 0, NULL); sched_make_runnable(thread); KASSERT(kshell != NULL); dbg(DBG_PRINT, "(GRADING2C)(kmain.c)(self_test_proc) self_test_proc() is invoked"); return 0; }
/* * Create a process and a thread with the given name and calling teh given * function. Arg1 is passed to the function (arg2 is always NULL). The thread * is immediately placed on the run queue. A proc_thread_t is returned, giving * the caller a pointer to the new process and thread to coordinate tests. NB, * the proc_thread_t is returned by value, so there are no stack problems. */ static void start_proc(proc_thread_t *ppt, char *name, kthread_func_t f, int arg1) { proc_thread_t pt; pt.p = proc_create(name); pt.t = kthread_create(pt.p, f, arg1, NULL); KASSERT(pt.p && pt.t && "Cannot create thread or process"); sched_make_runnable(pt.t); if (ppt != NULL) { memcpy(ppt, &pt, sizeof(proc_thread_t)); } }
kthread_t * sched_wakeup_on(ktqueue_t *q) { //NOT_YET_IMPLEMENTED("PROCS: sched_wakeup_on"); if (sched_queue_empty(q)) { return NULL; } kthread_t *thr = ktqueue_dequeue(q); sched_make_runnable(thr); return thr; }
int faber(kshell_t *kshell, int argc,char **argv) { int status; proc_t *faberproc = proc_create("faber"); kthread_t *faberthread = kthread_create(faberproc,faber_thread_test,0,NULL); sched_make_runnable(faberthread); KASSERT(kshell != NULL); dbg(DBG_INIT,"(GRADING1C: Faber test is invoked)\n"); while(do_waitpid(-1,0,&status)!=-ECHILD); return 0; }
int sunghan_deadlock(kshell_t *kshell, int argc,char **argv) { int status; proc_t *sunghan_deadlock_testproc = proc_create("sunghan_deadlock"); kthread_t *sunghan_deadlock_testthread = kthread_create(sunghan_deadlock_testproc,sunghan_deadlock_test,0,NULL); sched_make_runnable(sunghan_deadlock_testthread); KASSERT(kshell != NULL); dbg(DBG_INIT,"(GRADING1D)\n"); while(do_waitpid(-1,0,&status)!=-ECHILD); return 0; }
void sched_broadcast_on(ktqueue_t *q) { /* Dequeue all from wait queue and make runnable */ while (!sched_queue_empty(q)) { kthread_t *wake_thr = ktqueue_dequeue(q); wake_thr->kt_wchan = NULL; sched_make_runnable(wake_thr); } /* NOT_YET_IMPLEMENTED("PROCS: sched_broadcast_on"); */ }
/* * A Thread function that exhibits a race condition on the race global being * removed by a mutex. It loads increments and stores race, context switching * between each line of C after acquiring mutex. The mutex acquire can * be cancelled, but will print an error message if the mutex acquire succeeds * - it expects to be cancelled. */ void *mutex_test_cancelme(int arg1, void *arg2) { int local; if ( kmutex_lock_cancellable(&mutex) ) do_exit(0); dbg_print("Mutex not cancelled? %d", curproc->p_pid); sched_make_runnable(curthr); sched_switch(); local = race; sched_make_runnable(curthr); sched_switch(); local++; sched_make_runnable(curthr); sched_switch(); race = local; sched_make_runnable(curthr); sched_switch(); kmutex_unlock(&mutex); do_exit(race); return NULL; }
int sunghandeadlocktest(kshell_t *kshell, int argc, char **argv) { int status; proc_t *temp_proc; kthread_t *temp_thread; temp_proc = proc_create("sunghan deadlock test"); dbg(DBG_PRINT, "(GRADING1D 2): sunghan_deadlock_test() is invoked\n"); temp_thread = kthread_create(temp_proc,sunghan_deadlock_test,0,NULL); sched_make_runnable(temp_thread); /*Make the thread runnable*/ do_waitpid(temp_proc->p_pid,0,&status); /*waiting for the test to end*/ return 0; }
int do_deadlock(kshell_t *kshell, int argc, char **argv) { KASSERT(kshell != NULL); dbg(DBG_PRINT, "sunghan_deadlock_test() is invoked.\n"); /* * Shouldn't call a test function directly. * It's best to invoke it in a separate kernel process. */ proc_t *newproc = proc_create("deadlock test"); kthread_t *newthr = kthread_create(newproc, sunghan_deadlock_test, 0, NULL); sched_make_runnable(newthr); return 0; }
void * sunghan_deadlock_test(int arg1, void *arg2) { int status; int proc_count = 0; pid_t proc_pid[3]; int i; dbg(DBG_TEST, ">>> Start running sunghan_deadlock_test()...\n"); mynode.length = 0; kmutex_init(&mynode.my_mutex); sched_queue_init(&mynode.my_queue); proc_t *p1 = proc_create("add_node"); KASSERT(NULL != p1); kthread_t *thr1 = kthread_create(p1, add_my_node, 0, NULL); KASSERT(NULL != thr1); sched_make_runnable(thr1); proc_pid[proc_count++] = p1->p_pid; proc_t *p2 = proc_create("remove_node"); KASSERT(NULL != p2); kthread_t *thr2 = kthread_create(p2, remove_my_node, 0, NULL); KASSERT(NULL != thr2); sched_make_runnable(thr2); proc_pid[proc_count++] = p2->p_pid; for (i=0; i<2; ++i) { do_waitpid(proc_pid[i], 0, &status); } sched_broadcast_on(&mynode.my_queue); dbg(DBG_TEST, "Shouldn't have gotten here in sunghan_deadlock_test(). Did NOT deadlock.\n"); return NULL; }
/* * If the thread's sleep is cancellable, we set the kt_cancelled * flag and remove it from the queue. Otherwise, we just set the * kt_cancelled flag and leave the thread on the queue. * * Remember, unless the thread is in the KT_NO_STATE or KT_EXITED * state, it should be on some queue. Otherwise, it will never be run * again. */ void sched_cancel(struct kthread *kthr) { kthr->kt_cancelled = 1; /* If cancellable sleep, wake from queue it's waiting on */ if (kthr->kt_state == KT_SLEEP_CANCELLABLE) { ktqueue_remove(kthr->kt_wchan, kthr); kthr->kt_wchan = NULL; sched_make_runnable(kthr); } /* NOT_YET_IMPLEMENTED("PROCS: sched_cancel"); */ }
static void test_do_waitpid(waitpid_type_t type){ proc_t *test_procs[NUM_PROCS]; kthread_t *test_threads[NUM_PROCS]; int i; for (i = 0; i < NUM_PROCS; i++){ test_procs[i] = proc_create("test proc"); test_threads[i] = kthread_create(test_procs[i], simple_function, i, NULL); sched_make_runnable(test_threads[i]); } int j; for (j = 0; j < NUM_PROCS; j++){ if (type == ANY){ int status; do_waitpid(-1, 0, &status); } else { int status; pid_t proc_pid = test_procs[j]->p_pid; pid_t waitpid_pid = do_waitpid(proc_pid, 0, &status); KASSERT(waitpid_pid == proc_pid); } } int k; for (k = 0; k < NUM_PROCS; k++){ proc_t *p = test_procs[k]; KASSERT(proc_lookup(p->p_pid) == NULL); /* make sure all children have been reparented */ KASSERT(list_empty(&p->p_children)); /* make sure that it is no longer in it's parent's * child list */ KASSERT(!in_child_list(p)); /* make sure it exited with the correct status */ KASSERT(p->p_status == 0); KASSERT(p->p_state == PROC_DEAD); KASSERT(sched_queue_empty(&p->p_wait)); } }
kthread_t * sched_wakeup_on(ktqueue_t *q) { /*----Kernel1:PROCS:sched_wakeup_on:Begins---*/ KASSERT(q != NULL); kthread_t *thr = ktqueue_dequeue(q); if (thr != NULL) { KASSERT((thr->kt_state == KT_SLEEP) || (thr->kt_state == KT_SLEEP_CANCELLABLE)); sched_make_runnable(thr); } return thr; /*----Ends----*/ }