X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Ftest.c;h=627bba5fc2e5109dff8a44b6e1fa99d92e5126fb;hb=0102529af97ccc9e91b7da188c0b23b5cb388bec;hp=6f7d10ec6b4c77b51ed33899d71e9784454c1268;hpb=9eb8439ff5957091606e0ca9dc184a333d748274;p=pintos-anon diff --git a/src/threads/test.c b/src/threads/test.c index 6f7d10e..627bba5 100644 --- a/src/threads/test.c +++ b/src/threads/test.c @@ -1,85 +1,159 @@ +/* Problem 1-1: Alarm Clock tests. + + Creates N threads, each of which sleeps a different, fixed + duration, M times. Records the wake-up order and verifies + that it is valid. */ + #include "threads/test.h" #include +#include "threads/malloc.h" #include "threads/synch.h" #include "threads/thread.h" #include "devices/timer.h" -static void test_sleep_once (void); +#ifdef MLFQS +#error This test not applicable with MLFQS enabled. +#endif + +static void test_sleep (int thread_cnt, int iterations); void test (void) { - test_sleep_once (); -// test_sleep_multiple (); + /* Easy test: 5 threads sleep once each. */ + test_sleep (5, 1); + + /* Somewhat harder test: 5 threads sleep 7 times each. */ + test_sleep (5, 7); } -struct sleep_once_data +/* Information about the test. */ +struct sleep_test + { + int64_t start; /* Current time at start of test. */ + int iterations; /* Number of iterations per thread. */ + + /* Output. */ + struct lock output_lock; /* Lock protecting output buffer. */ + int *output_pos; /* Current position in output buffer. */ + }; + +/* Information about an individual thread in the test. */ +struct sleep_thread { + struct sleep_test *test; /* Info shared between all threads. */ + int id; /* Sleeper ID. */ int duration; /* Number of ticks to sleep. */ - volatile int *counter; /* Counter to check. */ - struct semaphore done; /* Completion semaphore. */ - struct thread *thread; /* Thread. */ + int iterations; /* Iterations counted so far. */ }; -static void sleep_once (void *); +static void sleeper (void *); +/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ static void -test_sleep_once (void) +test_sleep (int thread_cnt, int iterations) { - struct sleep_once_data t[5]; - const int t_cnt = sizeof t / sizeof *t; - volatile int counter; + struct sleep_test test; + struct sleep_thread *threads; + int *output, *op; + int product; int i; - printf ("\nTesting one sleep per thread...\n"); + printf ("\n" + "Creating %d threads to sleep %d times each.\n" + "Thread 0 sleeps 10 ticks each time,\n" + "thread 1 sleeps 20 ticks each time, and so on.\n" + "If successful, product of iteration count and\n" + "sleep duration will appear in nondescending order.\n\n" + "Running test... ", + thread_cnt, iterations); - /* Start all the threads. */ - counter = 0; - for (i = 0; i < t_cnt; i++) + /* Allocate memory. */ + threads = malloc (sizeof *threads * thread_cnt); + output = malloc (sizeof *output * iterations * thread_cnt * 2); + if (threads == NULL || output == NULL) + PANIC ("couldn't allocate memory for test"); + + /* Initialize test. */ + test.start = timer_ticks () + 100; + test.iterations = iterations; + lock_init (&test.output_lock, "output"); + test.output_pos = output; + + /* Start threads. */ + ASSERT (output != NULL); + for (i = 0; i < thread_cnt; i++) { + struct sleep_thread *t = threads + i; char name[16]; - snprintf (name, sizeof name, "once %d", i); + + t->test = &test; + t->id = i; + t->duration = (i + 1) * 10; + t->iterations = 0; - t[i].duration = i * 10; - t[i].counter = &counter; - sema_init (&t[i].done, 0, name); - t[i].thread = thread_create (name, sleep_once, &t[i]); + snprintf (name, sizeof name, "thread %d", i); + thread_create (name, PRI_DEFAULT, sleeper, t); } - /* Wait for all the threads to finish. */ - for (i = 0; i < t_cnt; i++) + /* Wait long enough for all the threads to finish. */ + timer_sleep (100 + thread_cnt * iterations * 10 + 100); + printf ("done\n\n"); + + /* Acquire the output lock in case some rogue thread is still + running. */ + lock_acquire (&test.output_lock); + + /* Print completion order. */ + product = 0; + for (op = output; op < test.output_pos; op++) { -#ifdef THREAD_JOIN_IMPLEMENTED - thread_join (t[i].thread); -#else - sema_down (&t[i].done); -#endif + struct sleep_thread *t; + int new_prod; + + ASSERT (*op >= 0 && *op < thread_cnt); + t = threads + *op; + + new_prod = ++t->iterations * t->duration; + + printf ("thread %d: duration=%d, iteration=%d, product=%d\n", + t->id, t->duration, t->iterations, new_prod); + + if (new_prod >= product) + product = new_prod; + else + printf ("FAIL: thread %d woke up out of order (%d > %d)!\n", + t->id, product, new_prod); } - printf ("...done\n"); + /* Verify that we had the proper number of wakeups. */ + for (i = 0; i < thread_cnt; i++) + if (threads[i].iterations != iterations) + printf ("FAIL: thread %d woke up %d times instead of %d\n", + i, threads[i].iterations, iterations); + + printf ("Test complete.\n"); + + lock_release (&test.output_lock); + free (output); + free (threads); } +/* Sleeper thread. */ static void -sleep_once (void *t_) +sleeper (void *t_) { - struct sleep_once_data *t = t_; - - /* Sleep. */ - timer_sleep (t->duration); + struct sleep_thread *t = t_; + struct sleep_test *test = t->test; + int i; - /* Check ordering. */ - if (*t->counter > t->duration) - printf ("%s: Out of order sleep completion (%d > %d)!\n", - thread_name (thread_current ()), - *t->counter, t->duration); - else + for (i = 1; i <= test->iterations; i++) { - *t->counter = t->duration; - printf ("%s: Sleep %d complete\n", - thread_name (thread_current ()), t->duration); - } + int64_t sleep_until = test->start + i * t->duration; + timer_sleep (sleep_until - timer_ticks ()); - /* Signal completion. */ - sema_up (&t->done); + lock_acquire (&test->output_lock); + *test->output_pos++ = t->id; + lock_release (&test->output_lock); + } } -