aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2024-02-20 18:23:50 +0000
committersotech117 <michael_foiani@brown.edu>2024-02-20 18:23:50 +0000
commitd2b13e08f8d6111b7f7e79a47a124fc47dd9433c (patch)
treeec46a99622c40dae1d45ff516699f949193275a2
parent84aae99b4f2f4997db95b9ea6db2a61f582b51ea (diff)
make tests and fix bugs that the tests caught :)
-rw-r--r--kernel/proc/kthread.c2
-rw-r--r--kernel/proc/proc.c16
-rw-r--r--kernel/proc/sched.c1
-rw-r--r--kernel/test/proctest.c237
4 files changed, 247 insertions, 9 deletions
diff --git a/kernel/proc/kthread.c b/kernel/proc/kthread.c
index 42beb77..46dd627 100644
--- a/kernel/proc/kthread.c
+++ b/kernel/proc/kthread.c
@@ -99,7 +99,7 @@ kthread_t *kthread_create(proc_t *proc, kthread_func_t func, long arg1,
list_init(&new_thread->kt_mutexes);
new_thread->kt_recent_core = 0;
- dbg(DBG_THR, "SUCCESFULLY created a new thread with proc name=%s, id=%d\n", proc->p_name, proc->p_pid);
+ dbg(DBG_THR, "SUCCESFULLY created a new THREAD with proc name=%s, id=%d\n", proc->p_name, proc->p_pid);
return new_thread;
}
diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c
index 2a7cdba..d0566ec 100644
--- a/kernel/proc/proc.c
+++ b/kernel/proc/proc.c
@@ -181,8 +181,6 @@ proc_t *proc_create(const char *name)
return NULL;
}
- dbg(DBG_PROC, "creating process name=%s & pid =%d\n", name, proc_pid);
-
proc_t *proc = (proc_t *)slab_obj_alloc(proc_allocator);
if (proc == NULL)
{
@@ -219,6 +217,8 @@ proc_t *proc_create(const char *name)
list_insert_tail(&curproc->p_children, &proc->p_child_link);
list_insert_tail(&proc_list, &proc->p_list_link);
+ dbg(DBG_PROC, "SUCESSFULLY created PROCESS name=%s & pid =%d\n", name, proc_pid);
+
return proc;
}
@@ -325,12 +325,11 @@ void proc_kill_all()
{
// NOT_YET_IMPLEMENTED("PROCS: proc_kill_all");
- // TODO: consider children on children
- list_iterate(&proc_initproc->p_children, thr, kthread_t, kt_plink)
+ list_iterate(&proc_list, p, proc_t, p_list_link)
{
- if((proc_t *) &thr->kt_proc != curproc)
+ if (p->p_pid != curproc->p_pid && p->p_pid != PID_IDLE)
{
- kthread_cancel(thr, 0);
+ proc_kill(p, 0);
}
}
@@ -435,8 +434,10 @@ pid_t do_waitpid(pid_t pid, int *status, int options)
if (status != NULL)
{
+ dbg(DBG_PROC, "setting status to %d\n", child->p_status);
*status = child->p_status;
}
+ list_remove(&child->p_child_link);
proc_destroy(child);
dbg(DBG_PROC, "exited child pid=%d\n", child->p_pid);
@@ -459,6 +460,7 @@ pid_t do_waitpid(pid_t pid, int *status, int options)
dbg(DBG_PROC, "found a dead thread with pid=%d\n", child->p_pid);
if (status != NULL)
{
+ dbg(DBG_PROC, "setting status to %d\n", child->p_status);
*status = child->p_status;
}
int child_pid = child->p_pid;
@@ -487,7 +489,7 @@ void do_exit(long status)
{
// NOT_YET_IMPLEMENTED("PROCS: do_exit");
- dbg(DBG_PROC, "proc exiting with pid=%d", curproc->p_pid);
+ dbg(DBG_PROC, "proc exiting with pid=%d and status=%ld\n", curproc->p_pid, status);
kthread_exit((void *)status);
}
diff --git a/kernel/proc/sched.c b/kernel/proc/sched.c
index 0461279..cd8e438 100644
--- a/kernel/proc/sched.c
+++ b/kernel/proc/sched.c
@@ -243,7 +243,6 @@ void sched_switch(ktqueue_t *queue)
intr_enable();
intr_setipl(oldIPL);
- // TODO: ask about why we need the old thread context
}
/*
diff --git a/kernel/test/proctest.c b/kernel/test/proctest.c
index eb70c81..9ab4c65 100644
--- a/kernel/test/proctest.c
+++ b/kernel/test/proctest.c
@@ -45,6 +45,235 @@ void test_termination()
"Expected: %d, Actual: %d number of processes have been cleaned up\n", num_procs_created, count);
}
+/*
+ Tests the edge cases of do_waitpid.
+ 1. No child processes to wait for
+ 2. Waiting on a specific process id
+ 3. Waiting any child process (-1)
+*/
+void test_do_waitpid()
+{
+ int status;
+ int ret = do_waitpid(-1, &status, 0);
+ test_assert(ret == -ECHILD, "No child processes to wait for");
+
+ proc_t *new_proc1 = proc_create("proc test 1");
+ kthread_t *new_kthread1 = kthread_create(new_proc1, test_func, new_proc1->p_pid, new_proc1);
+ sched_make_runnable(new_kthread1);
+
+ proc_t *new_proc2 = proc_create("proc test 2");
+ kthread_t *new_kthread2 = kthread_create(new_proc2, test_func, new_proc2->p_pid, new_proc2);
+ sched_make_runnable(new_kthread2);
+
+ proc_t *new_proc3 = proc_create("proc test 3");
+ kthread_t *new_kthread3 = kthread_create(new_proc3, test_func, new_proc3->p_pid, new_proc3);
+ sched_make_runnable(new_kthread3);
+
+ // wait for a specific process id
+ ret = do_waitpid(new_proc2->p_pid, &status, 0);
+ test_assert(ret == new_proc2->p_pid, "Waiting for a specific process id");
+
+ dbg(DBG_TEST, "Successfully removed proc 2 with pid: %d\n", new_proc2->p_pid);
+
+ // wait for any child process
+ ret = do_waitpid(-1, &status, 0);
+ test_assert(ret == new_proc1->p_pid, "Waiting for any child process");
+ dbg(DBG_TEST, "Successfully removed proc 1 with pid: %d\n", new_proc1->p_pid);
+ ret = do_waitpid(-1, &status, 0);
+ test_assert(ret == new_proc3->p_pid, "Waiting for any child process");
+ dbg(DBG_TEST, "Successfully removed proc 3 with pid: %d\n", new_proc3->p_pid);
+
+ ret = do_waitpid(-1, &status, 0);
+ test_assert(ret == -ECHILD, "No child processes to wait for");
+}
+
+/*
+ Tests proc_kill_all on a single process.
+*/
+void *test_func_kill(long arg1, void *arg2)
+{
+ // function to be called by the process
+ proc_t *proc_as_arg = (proc_t *)arg2;
+ test_assert(arg1 == proc_as_arg->p_pid, "Arguments are not set up correctly");
+ test_assert(proc_as_arg->p_state == PROC_RUNNING, "Process state is not running");
+ test_assert(list_empty(&proc_as_arg->p_children), "There should be no child processes");
+ dbg(DBG_TEST, "Process with pid=%d is running and calling proc_kill_all\n", proc_as_arg->p_pid);
+ proc_kill_all();
+ return NULL;
+}
+void test_proc_kill_all()
+{
+ proc_t *new_proc_kill = proc_create("proc test kill");
+ kthread_t *new_kthread_kill = kthread_create(new_proc_kill, test_func_kill, new_proc_kill->p_pid, new_proc_kill);
+ sched_make_runnable(new_kthread_kill);
+
+ proc_t *new_proc1 = proc_create("proc test 1");
+ kthread_t *new_kthread1 = kthread_create(new_proc1, test_func, new_proc1->p_pid, new_proc1);
+ sched_make_runnable(new_kthread1);
+
+ proc_t *new_proc2 = proc_create("proc test 2");
+ kthread_t *new_kthread2 = kthread_create(new_proc2, test_func, new_proc2->p_pid, new_proc2);
+ sched_make_runnable(new_kthread2);
+
+ // wait on the process that calls proc_kill_all
+ int status;
+ int ret = do_waitpid(new_proc_kill->p_pid, &status, 0);
+ test_assert(ret == new_proc_kill->p_pid, "Waiting for a specific process id");
+ dbg(DBG_TEST, "Successfully removed proc_kill with pid: %d\n", new_proc_kill->p_pid);
+
+ // wait for all the threads to finish
+ int count = 0;
+ while (do_waitpid(-1, &status, 0) != -ECHILD)
+ {
+ dbg(DBG_TEST, "Waiting for child process to terminate\n");
+ test_assert(status == 0, "Returned status not set correctly");
+ count++;
+ }
+ test_assert(count == 2,
+ "Expected: %d, Actual: %d number of processes have been cleaned up\n", 2, count);
+
+}
+
+/*
+ Test to run several threads and processes concurrently.
+*/
+void test_multiple()
+{
+ int num_procs_created = 0;
+ proc_t *new_proc1 = proc_create("proc test 1");
+ kthread_t *new_kthread1 = kthread_create(new_proc1, test_func, new_proc1->p_pid, new_proc1);
+ num_procs_created++;
+ sched_make_runnable(new_kthread1);
+
+ proc_t *new_proc2 = proc_create("proc test 2");
+ kthread_t *new_kthread2 = kthread_create(new_proc2, test_func, new_proc2->p_pid, new_proc2);
+ num_procs_created++;
+ sched_make_runnable(new_kthread2);
+
+ proc_t *new_proc3 = proc_create("proc test 3");
+ kthread_t *new_kthread3 = kthread_create(new_proc3, test_func, new_proc3->p_pid, new_proc3);
+ num_procs_created++;
+ sched_make_runnable(new_kthread3);
+
+ // print all of the threads in the system
+ list_iterate(&curproc->p_threads, thread, kthread_t, kt_plink)
+ {
+ dbg(DBG_THR, "Thread: %s\n", thread->kt_proc->p_name);
+ }
+
+ // wait for all the threads to finish
+ int count = 0;
+ int status;
+ while (do_waitpid(-1, &status, 0) != -ECHILD)
+ {
+ dbg(DBG_TEST, "Waiting for child process to terminate\n");
+ test_assert(status == 0, "Returned status not set correctly");
+ count++;
+ }
+ test_assert(count == num_procs_created,
+ "Expected: %d, Actual: %d number of processes have been cleaned up\n", num_procs_created, count);
+}
+
+/*
+ Test that creates several child processes and forces them to terminate out of order.
+ Then it checks to see if the processes are cleaned up correctly.
+*/
+void *func_forever_yielding(long arg1, void *arg2)
+{
+ // function that always just yields
+ // goal is that it is cleaned up by a different process
+ while (1)
+ {
+ // have a way to stop the thread
+ int *to_stop = (int *)arg2;
+ if (*to_stop)
+ {
+ dbg(DBG_TEST, "Thread with pid=%d is stopping yield loop\n", curproc->p_pid);
+ do_exit(1); // return different status code
+ break;
+ }
+ // wait a bit
+ for (int i = 0; i < 1000000; i++)
+ {
+ ;
+ }
+ dbg(DBG_TEST, "Thread with pid=%d is yielding on it's parent\n", curproc->p_pid);
+ sched_yield();
+ }
+ return NULL;
+}
+void test_out_of_order_termination()
+{
+ // create a yielding proc that will last for a long time
+ proc_t *new_proc1 = proc_create("yieling proc 1");
+ int stop_func_1 = 0;
+ kthread_t *new_kthread1 = kthread_create(new_proc1, func_forever_yielding, new_proc1->p_pid, &stop_func_1);
+ sched_make_runnable(new_kthread1);
+
+ proc_t *new_proc2 = proc_create("yielding proc 2");
+ int stop_func_2 = 0;
+ kthread_t *new_kthread2 = kthread_create(new_proc2, func_forever_yielding, new_proc2->p_pid, &stop_func_2);
+ sched_make_runnable(new_kthread2);
+
+ proc_t *new_proc3 = proc_create("proc test 3");
+ kthread_t *new_kthread3 = kthread_create(new_proc3, test_func, new_proc3->p_pid, new_proc3);
+ sched_make_runnable(new_kthread3);
+
+ proc_t *new_proc4 = proc_create("proc test 4");
+ kthread_t *new_kthread4 = kthread_create(new_proc4, test_func, new_proc4->p_pid, new_proc4);
+ sched_make_runnable(new_kthread4);
+
+ // let to first and second procs go and yield
+ sched_yield();
+
+ // the first and second proc should yield to the third proc and fourth proc
+ // which will return here to the init proc
+ test_assert(curproc->p_pid == PID_INIT, "Should have returned to init proc");
+ test_assert(new_proc3->p_state == PROC_DEAD, "Third proc should be dead");
+ test_assert(new_proc4->p_state == PROC_DEAD, "Fourth proc should be dead");
+
+ // destroy procs 3 and 4
+
+ // terminate the second proc
+ stop_func_2 = 1;
+ sched_yield();
+
+ // we should return back to the init proc
+ test_assert(curproc->p_pid == PID_INIT, "Should have returned to init proc");
+ test_assert(new_proc2->p_state == PROC_DEAD, "Second proc should be dead");
+
+ // terminate the first proc
+ stop_func_1 = 1;
+ sched_yield();
+
+ // we should return back to the init proc
+ test_assert(curproc->p_pid == PID_INIT, "Should have returned to init proc");
+ test_assert(new_proc1->p_state == PROC_DEAD, "First proc should be dead");
+
+ // clean up proc 2 using do_waitpid, with specific status 1
+ int status;
+ int ret = do_waitpid(new_proc2->p_pid, &status, 0);
+ test_assert(ret == new_proc2->p_pid, "wrong specific process id");
+ test_assert(status == 1, "Returned status not set correctly");
+ test_assert(new_proc2->p_status == 1, "Status not set correctly");
+
+ // clean up the rest of the dead procs using do_waitpid
+ int count = 0;
+ while ((ret = do_waitpid(-1, &status, 0)) != -ECHILD)
+ {
+ dbg(DBG_TEST, "found child with pid=%d that needs to be cleaned up\n", ret);
+ if (ret == new_proc1->p_pid) {
+ test_assert(status == 1, "Returned status not set correctly for proc 1 with pid=%d", new_proc1->p_pid);
+ } else {
+ test_assert(status == 0, "Returned status not set correctly");
+ }
+ count++;
+ }
+ test_assert(count == 3,
+ "Expected: %d, Actual: %d number of processes have been cleaned up\n", 3, count);
+}
+
+
long proctest_main(long arg1, void *arg2)
{
dbg(DBG_TEST, "\nStarting Procs tests\n");
@@ -53,6 +282,14 @@ long proctest_main(long arg1, void *arg2)
// Add more tests here!
// We highly recommend looking at section 3.8 on the handout for help!
+ dbg(DBG_TEST, "\nStarting test_multiple\n");
+ test_multiple();
+ dbg(DBG_TEST, "\nStarting test_do_waitpid\n");
+ test_do_waitpid();
+ dbg(DBG_TEST, "\nStarting test_proc_kill_all\n");
+ test_proc_kill_all();
+ dbg(DBG_TEST, "\nStarting test_out_of_order_termination\n");
+ test_out_of_order_termination();
test_fini();
return 0;