From 27e2fa0176f088ee129a65130322574f3807c67c Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 31 Dec 2004 07:10:02 +0000 Subject: [PATCH] Improve basic alarm clock test. --- grading/threads/alarm-multiple.c | 150 ++++++++++++++----------- grading/threads/alarm-single.c | 150 ++++++++++++++----------- grading/threads/run-tests | 2 +- src/tests/threads/p1-1.c | 182 ++++++++++++++++++------------- src/threads/test.c | 174 ++++++++++++++++++----------- 5 files changed, 393 insertions(+), 265 deletions(-) diff --git a/grading/threads/alarm-multiple.c b/grading/threads/alarm-multiple.c index 3d30af2..aaa3cc8 100644 --- a/grading/threads/alarm-multiple.c +++ b/grading/threads/alarm-multiple.c @@ -1,9 +1,8 @@ /* Problem 1-1: Alarm Clock tests. - Based on a test originally submitted for Stanford's CS 140 in - winter 1998 by Rob Baesman , Ben - Taskar , and Toli Kuznets - . */ + 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 @@ -16,117 +15,140 @@ #error This test not applicable with MLFQS enabled. #endif -static void test_sleep (int iterations); +static void test_sleep (int thread_cnt, int iterations); void test (void) { - test_sleep (7); + test_sleep (5, 7); } + +/* 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. */ + }; -struct sleep_thread_data +/* Information about an individual thread in the test. */ +struct sleep_thread { - int64_t start; /* Start time. */ - int duration; /* Number of ticks to sleep. */ - int iterations; /* Number of iterations to run. */ - struct semaphore done; /* Completion semaphore. */ - tid_t tid; /* Thread ID. */ + struct sleep_test *test; /* Info shared between all threads. */ int id; /* Sleeper ID. */ - - struct lock *lock; /* Lock on access to `op'. */ - int **op; /* Output buffer position. */ + int duration; /* Number of ticks to sleep. */ + int iterations; /* Iterations counted so far. */ }; static void sleeper (void *); +/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ static void -test_sleep (int iterations) +test_sleep (int thread_cnt, int iterations) { - struct sleep_thread_data threads[5]; - const int thread_cnt = sizeof threads / sizeof *threads; + struct sleep_test test; + struct sleep_thread *threads; int *output, *op; - struct lock lock; - int64_t start; int product; int i; printf ("\n" - "Testing %d sleeps per thread.\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", - iterations); - - /* Start all the threads. */ - product = 0; - lock_init (&lock, "product"); - op = output = malloc (sizeof *output * iterations * thread_cnt * 2); + "sleep duration will appear in nondescending order.\n\n" + "Running test... ", + thread_cnt, iterations); + + /* 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); - start = timer_ticks (); for (i = 0; i < thread_cnt; i++) { - struct sleep_thread_data *t; + struct sleep_thread *t = threads + i; char name[16]; - snprintf (name, sizeof name, "thread %d", i); - t = threads + i; - t->start = start; - t->duration = (i + 1) * 10; - t->iterations = iterations; - sema_init (&t->done, 0, name); - t->tid = thread_create (name, PRI_DEFAULT, sleeper, t); + t->test = &test; t->id = i; + t->duration = (i + 1) * 10; + t->iterations = 0; - t->lock = &lock; - t->op = &op; + 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 < thread_cnt; i++) - { - sema_down (&threads[i].done); - threads[i].iterations = 1; - } + /* Wait long enough for all the threads to finish. */ + timer_sleep (100 + thread_cnt * iterations * 10 + 100); + printf ("done\n\n"); - /* Print output buffer. */ + /* Acquire the output lock in case some rogue thread is still + running. */ + lock_acquire (&test.output_lock); + + /* Print completion order. */ product = 0; - for (; output < op; output++) + for (op = output; op < test.output_pos; op++) { - struct sleep_thread_data *t; + struct sleep_thread *t; int new_prod; - - ASSERT (*output >= 0 && *output < thread_cnt); - t = threads + *output; - new_prod = t->iterations++ * t->duration; + 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 ("thread %d: Out of order sleep completion (%d > %d)!\n", + printf ("FAIL: thread %d woke up out of order (%d > %d)!\n", t->id, product, new_prod); } + + /* 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 ("...done\n"); + printf ("Test complete.\n"); + + free (output); + free (threads); } +/* Sleeper thread. */ static void sleeper (void *t_) { - struct sleep_thread_data *t = t_; + struct sleep_thread *t = t_; + struct sleep_test *test = t->test; int i; - for (i = 1; i <= t->iterations; i++) + for (i = 1; i <= test->iterations; i++) { - timer_sleep ((t->start + i * t->duration) - timer_ticks ()); + int64_t sleep_until = test->start + i * t->duration; + timer_sleep (sleep_until - timer_ticks ()); - lock_acquire (t->lock); - *(*t->op)++ = t->id; - lock_release (t->lock); + lock_acquire (&test->output_lock); + *test->output_pos++ = t->id; + lock_release (&test->output_lock); } - - /* Signal completion. */ - sema_up (&t->done); } diff --git a/grading/threads/alarm-single.c b/grading/threads/alarm-single.c index 8acef92..4681d89 100644 --- a/grading/threads/alarm-single.c +++ b/grading/threads/alarm-single.c @@ -1,9 +1,8 @@ /* Problem 1-1: Alarm Clock tests. - Based on a test originally submitted for Stanford's CS 140 in - winter 1998 by Rob Baesman , Ben - Taskar , and Toli Kuznets - . */ + 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 @@ -16,117 +15,140 @@ #error This test not applicable with MLFQS enabled. #endif -static void test_sleep (int iterations); +static void test_sleep (int thread_cnt, int iterations); void test (void) { - test_sleep (1); + test_sleep (5, 1); } + +/* 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. */ + }; -struct sleep_thread_data +/* Information about an individual thread in the test. */ +struct sleep_thread { - int64_t start; /* Start time. */ - int duration; /* Number of ticks to sleep. */ - int iterations; /* Number of iterations to run. */ - struct semaphore done; /* Completion semaphore. */ - tid_t tid; /* Thread ID. */ + struct sleep_test *test; /* Info shared between all threads. */ int id; /* Sleeper ID. */ - - struct lock *lock; /* Lock on access to `op'. */ - int **op; /* Output buffer position. */ + int duration; /* Number of ticks to sleep. */ + int iterations; /* Iterations counted so far. */ }; static void sleeper (void *); +/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ static void -test_sleep (int iterations) +test_sleep (int thread_cnt, int iterations) { - struct sleep_thread_data threads[5]; - const int thread_cnt = sizeof threads / sizeof *threads; + struct sleep_test test; + struct sleep_thread *threads; int *output, *op; - struct lock lock; - int64_t start; int product; int i; printf ("\n" - "Testing %d sleeps per thread.\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", - iterations); - - /* Start all the threads. */ - product = 0; - lock_init (&lock, "product"); - op = output = malloc (sizeof *output * iterations * thread_cnt * 2); + "sleep duration will appear in nondescending order.\n\n" + "Running test... ", + thread_cnt, iterations); + + /* 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); - start = timer_ticks (); for (i = 0; i < thread_cnt; i++) { - struct sleep_thread_data *t; + struct sleep_thread *t = threads + i; char name[16]; - snprintf (name, sizeof name, "thread %d", i); - t = threads + i; - t->start = start; - t->duration = (i + 1) * 10; - t->iterations = iterations; - sema_init (&t->done, 0, name); - t->tid = thread_create (name, PRI_DEFAULT, sleeper, t); + t->test = &test; t->id = i; + t->duration = (i + 1) * 10; + t->iterations = 0; - t->lock = &lock; - t->op = &op; + 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 < thread_cnt; i++) - { - sema_down (&threads[i].done); - threads[i].iterations = 1; - } + /* Wait long enough for all the threads to finish. */ + timer_sleep (100 + thread_cnt * iterations * 10 + 100); + printf ("done\n\n"); - /* Print output buffer. */ + /* Acquire the output lock in case some rogue thread is still + running. */ + lock_acquire (&test.output_lock); + + /* Print completion order. */ product = 0; - for (; output < op; output++) + for (op = output; op < test.output_pos; op++) { - struct sleep_thread_data *t; + struct sleep_thread *t; int new_prod; - - ASSERT (*output >= 0 && *output < thread_cnt); - t = threads + *output; - new_prod = t->iterations++ * t->duration; + 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 ("thread %d: Out of order sleep completion (%d > %d)!\n", + printf ("FAIL: thread %d woke up out of order (%d > %d)!\n", t->id, product, new_prod); } + + /* 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 ("...done\n"); + printf ("Test complete.\n"); + + free (output); + free (threads); } +/* Sleeper thread. */ static void sleeper (void *t_) { - struct sleep_thread_data *t = t_; + struct sleep_thread *t = t_; + struct sleep_test *test = t->test; int i; - for (i = 1; i <= t->iterations; i++) + for (i = 1; i <= test->iterations; i++) { - timer_sleep ((t->start + i * t->duration) - timer_ticks ()); + int64_t sleep_until = test->start + i * t->duration; + timer_sleep (sleep_until - timer_ticks ()); - lock_acquire (t->lock); - *(*t->op)++ = t->id; - lock_release (t->lock); + lock_acquire (&test->output_lock); + *test->output_pos++ = t->id; + lock_release (&test->output_lock); } - - /* Signal completion. */ - sema_up (&t->done); } diff --git a/grading/threads/run-tests b/grading/threads/run-tests index 37bc659..096bec0 100755 --- a/grading/threads/run-tests +++ b/grading/threads/run-tests @@ -125,7 +125,7 @@ sub verify_alarm { local ($_); foreach (@output) { - die $_ if /Out of order/; + die $_ if /out of order/i; my ($p) = /product=(\d+)$/; next if !defined $p; diff --git a/src/tests/threads/p1-1.c b/src/tests/threads/p1-1.c index 7e52866..2aeb910 100644 --- a/src/tests/threads/p1-1.c +++ b/src/tests/threads/p1-1.c @@ -1,122 +1,158 @@ /* Problem 1-1: Alarm Clock tests. - These tests will work with Pintos "out of the box" because an - implementation of timer_sleep() that "busy-waits" is - included. You need to replace that implementation with one - that doesn't busy-wait. - - Based on a test originally submitted for Stanford's CS 140 in - winter 1998 by Rob Baesman , Ben - Taskar , and Toli Kuznets - . */ - -#ifdef MLFQS -#error This test not applicable with MLFQS enabled. -#endif + 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 (int iterations); +#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 (1); - test_sleep (7); + /* Easy test: 5 threads sleep once each. */ + test_sleep (5, 1); + + /* Somewhat harder test: 5 threads sleep 7 times each. */ + test_sleep (5, 7); } + +/* 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. */ + }; -struct sleep_thread_data +/* Information about an individual thread in the test. */ +struct sleep_thread { - int64_t start; /* Start time. */ + struct sleep_test *test; /* Info shared between all threads. */ + int id; /* Sleeper ID. */ int duration; /* Number of ticks to sleep. */ - int iterations; /* Number of iterations to run. */ - int *product; /* Largest product so far. */ - struct lock *lock; /* Lock on access to `product'. */ - struct semaphore done; /* Completion semaphore. */ - tid_t tid; /* Thread ID. */ + int iterations; /* Iterations counted so far. */ }; static void sleeper (void *); +/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ static void -test_sleep (int iterations) +test_sleep (int thread_cnt, int iterations) { - struct sleep_thread_data threads[5]; - const int thread_cnt = sizeof threads / sizeof *threads; - struct lock lock; - int64_t start; + struct sleep_test test; + struct sleep_thread *threads; + int *output, *op; int product; int i; printf ("\n" - "Testing %d sleeps per thread.\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", - iterations); - - /* Start all the threads. */ - product = 0; - lock_init (&lock, "product"); - start = timer_ticks (); + "sleep duration will appear in nondescending order.\n\n" + "Running test... ", + thread_cnt, iterations); + + /* 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_data *t; + struct sleep_thread *t = threads + i; char name[16]; - snprintf (name, sizeof name, "thread %d", i); - t = threads + i; - t->start = start; + t->test = &test; + t->id = i; t->duration = (i + 1) * 10; - t->iterations = iterations; - t->product = &product; - t->lock = &lock; - sema_init (&t->done, 0, name); - t->tid = thread_create (name, PRI_DEFAULT, sleeper, t); + t->iterations = 0; + + 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 < thread_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 (threads[i].tid); -#else - sema_down (&threads[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"); + + free (output); + free (threads); } +/* Sleeper thread. */ static void sleeper (void *t_) { - struct sleep_thread_data *t = t_; + struct sleep_thread *t = t_; + struct sleep_test *test = t->test; int i; - for (i = 1; i <= t->iterations; i++) + for (i = 1; i <= test->iterations; i++) { - int old_product; - int new_product = i * t->duration; + int64_t sleep_until = test->start + i * t->duration; + timer_sleep (sleep_until - timer_ticks ()); - timer_sleep ((t->start + new_product) - timer_ticks ()); - - lock_acquire (t->lock); - old_product = *t->product; - *t->product = new_product; - lock_release (t->lock); - - printf ("%s: duration=%d, iteration=%d, product=%d\n", - thread_name (), t->duration, i, new_product); - - if (old_product > new_product) - printf ("%s: Out of order sleep completion (%d > %d)!\n", - thread_name (), old_product, new_product); + lock_acquire (&test->output_lock); + *test->output_pos++ = t->id; + lock_release (&test->output_lock); } - - /* Signal completion. */ - sema_up (&t->done); } diff --git a/src/threads/test.c b/src/threads/test.c index ae9d16d..2aeb910 100644 --- a/src/threads/test.c +++ b/src/threads/test.c @@ -1,110 +1,158 @@ +/* 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 (int iterations); +#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 (1); - test_sleep (7); + /* Easy test: 5 threads sleep once each. */ + test_sleep (5, 1); + + /* Somewhat harder test: 5 threads sleep 7 times each. */ + test_sleep (5, 7); } -/* Based on a test originally submitted for Stanford's CS 140 in - winter 1998 by Rob Baesman , Ben - Taskar , and Toli Kuznets - . */ -struct sleep_thread_data +/* Information about the test. */ +struct sleep_test { - int64_t start; /* Start time. */ + 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. */ - int iterations; /* Number of iterations to run. */ - int *product; /* Largest product so far. */ - struct lock *lock; /* Lock on access to `product'. */ - struct semaphore done; /* Completion semaphore. */ - tid_t tid; /* Thread ID. */ + int iterations; /* Iterations counted so far. */ }; static void sleeper (void *); +/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ static void -test_sleep (int iterations) +test_sleep (int thread_cnt, int iterations) { - struct sleep_thread_data threads[5]; - const int thread_cnt = sizeof threads / sizeof *threads; - struct lock lock; - int64_t start; + struct sleep_test test; + struct sleep_thread *threads; + int *output, *op; int product; int i; printf ("\n" - "Testing %d sleeps per thread.\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", - iterations); + "sleep duration will appear in nondescending order.\n\n" + "Running test... ", + thread_cnt, iterations); - /* Start all the threads. */ - product = 0; - lock_init (&lock, "product"); - start = timer_ticks (); + /* 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_data *t; + struct sleep_thread *t = threads + i; char name[16]; - snprintf (name, sizeof name, "thread %d", i); - t = threads + i; - t->start = start; + t->test = &test; + t->id = i; t->duration = (i + 1) * 10; - t->iterations = iterations; - t->product = &product; - t->lock = &lock; - sema_init (&t->done, 0, name); - t->tid = thread_create (name, PRI_DEFAULT, sleeper, t); + t->iterations = 0; + + 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 < thread_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 (threads[i].tid); -#else - sema_down (&threads[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"); + + free (output); + free (threads); } +/* Sleeper thread. */ static void sleeper (void *t_) { - struct sleep_thread_data *t = t_; + struct sleep_thread *t = t_; + struct sleep_test *test = t->test; int i; - for (i = 1; i <= t->iterations; i++) + for (i = 1; i <= test->iterations; i++) { - int old_product; - int new_product = i * t->duration; - - timer_sleep ((t->start + new_product) - timer_ticks ()); + int64_t sleep_until = test->start + i * t->duration; + timer_sleep (sleep_until - timer_ticks ()); - lock_acquire (t->lock); - old_product = *t->product; - *t->product = new_product; - lock_release (t->lock); - - printf ("%s: duration=%d, iteration=%d, product=%d\n", - thread_name (), t->duration, i, new_product); - - if (old_product > new_product) - printf ("%s: Out of order sleep completion (%d > %d)!\n", - thread_name (), old_product, new_product); + lock_acquire (&test->output_lock); + *test->output_pos++ = t->id; + lock_release (&test->output_lock); } - - /* Signal completion. */ - sema_up (&t->done); } -- 2.30.2