summaryrefslogtreecommitdiffstats
path: root/pintos-progos/tests/threads
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/tests/threads')
-rw-r--r--pintos-progos/tests/threads/Grading11
-rw-r--r--pintos-progos/tests/threads/Make.tests56
-rw-r--r--pintos-progos/tests/threads/Rubric.alarm8
-rw-r--r--pintos-progos/tests/threads/Rubric.mlfqs14
-rw-r--r--pintos-progos/tests/threads/Rubric.priority15
-rw-r--r--pintos-progos/tests/threads/alarm-multiple.ck4
-rw-r--r--pintos-progos/tests/threads/alarm-negative.c15
-rw-r--r--pintos-progos/tests/threads/alarm-negative.ck10
-rw-r--r--pintos-progos/tests/threads/alarm-priority.c58
-rw-r--r--pintos-progos/tests/threads/alarm-priority.ck19
-rw-r--r--pintos-progos/tests/threads/alarm-simultaneous.c94
-rw-r--r--pintos-progos/tests/threads/alarm-simultaneous.ck27
-rw-r--r--pintos-progos/tests/threads/alarm-single.ck4
-rw-r--r--pintos-progos/tests/threads/alarm-wait.c152
-rw-r--r--pintos-progos/tests/threads/alarm-zero.c15
-rw-r--r--pintos-progos/tests/threads/alarm-zero.ck10
-rw-r--r--pintos-progos/tests/threads/alarm.pm32
-rw-r--r--pintos-progos/tests/threads/mlfqs-block.c64
-rw-r--r--pintos-progos/tests/threads/mlfqs-block.ck17
-rw-r--r--pintos-progos/tests/threads/mlfqs-fair-2.ck7
-rw-r--r--pintos-progos/tests/threads/mlfqs-fair-20.ck7
-rw-r--r--pintos-progos/tests/threads/mlfqs-fair.c124
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-1.c60
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-1.ck15
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-60.c155
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-60.ck36
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-avg.c167
-rw-r--r--pintos-progos/tests/threads/mlfqs-load-avg.ck36
-rw-r--r--pintos-progos/tests/threads/mlfqs-nice-10.ck7
-rw-r--r--pintos-progos/tests/threads/mlfqs-nice-2.ck7
-rw-r--r--pintos-progos/tests/threads/mlfqs-recent-1.c144
-rw-r--r--pintos-progos/tests/threads/mlfqs-recent-1.ck31
-rw-r--r--pintos-progos/tests/threads/mlfqs.pm146
-rw-r--r--pintos-progos/tests/threads/priority-change.c31
-rw-r--r--pintos-progos/tests/threads/priority-change.ck14
-rw-r--r--pintos-progos/tests/threads/priority-condvar.c53
-rw-r--r--pintos-progos/tests/threads/priority-condvar.ck39
-rw-r--r--pintos-progos/tests/threads/priority-donate-chain.c114
-rw-r--r--pintos-progos/tests/threads/priority-donate-chain.ck46
-rw-r--r--pintos-progos/tests/threads/priority-donate-lower.c51
-rw-r--r--pintos-progos/tests/threads/priority-donate-lower.ck16
-rw-r--r--pintos-progos/tests/threads/priority-donate-multiple.c77
-rw-r--r--pintos-progos/tests/threads/priority-donate-multiple.ck19
-rw-r--r--pintos-progos/tests/threads/priority-donate-multiple2.c90
-rw-r--r--pintos-progos/tests/threads/priority-donate-multiple2.ck19
-rw-r--r--pintos-progos/tests/threads/priority-donate-nest.c94
-rw-r--r--pintos-progos/tests/threads/priority-donate-nest.ck19
-rw-r--r--pintos-progos/tests/threads/priority-donate-one.c65
-rw-r--r--pintos-progos/tests/threads/priority-donate-one.ck17
-rw-r--r--pintos-progos/tests/threads/priority-donate-sema.c82
-rw-r--r--pintos-progos/tests/threads/priority-donate-sema.ck16
-rw-r--r--pintos-progos/tests/threads/priority-fifo.c99
-rw-r--r--pintos-progos/tests/threads/priority-fifo.ck63
-rw-r--r--pintos-progos/tests/threads/priority-preempt.c41
-rw-r--r--pintos-progos/tests/threads/priority-preempt.ck16
-rw-r--r--pintos-progos/tests/threads/priority-sema.c45
-rw-r--r--pintos-progos/tests/threads/priority-sema.ck29
-rw-r--r--pintos-progos/tests/threads/tests.c102
-rw-r--r--pintos-progos/tests/threads/tests.h41
59 files changed, 2865 insertions, 0 deletions
diff --git a/pintos-progos/tests/threads/Grading b/pintos-progos/tests/threads/Grading
new file mode 100644
index 0000000..cc235f2
--- /dev/null
+++ b/pintos-progos/tests/threads/Grading
@@ -0,0 +1,11 @@
1# Percentage of the testing point total designated for each set of
2# tests.
3
4# Priority Scheduling
590.0% tests/threads/Rubric.priority
6
7# Robustness
810.0% tests/threads/Rubric.alarm
9
10# Not used in SS 2012
11# XX.0% tests/threads/Rubric.mlfqs
diff --git a/pintos-progos/tests/threads/Make.tests b/pintos-progos/tests/threads/Make.tests
new file mode 100644
index 0000000..dbdfd0c
--- /dev/null
+++ b/pintos-progos/tests/threads/Make.tests
@@ -0,0 +1,56 @@
1# -*- makefile -*-
2
3# Test names.
4tests/threads_TESTS = $(addprefix tests/threads/,alarm-single \
5alarm-multiple alarm-simultaneous alarm-priority alarm-zero \
6alarm-negative priority-change priority-donate-one \
7priority-donate-multiple priority-donate-multiple2 \
8priority-donate-nest priority-donate-sema priority-donate-lower \
9priority-fifo priority-preempt priority-sema priority-condvar \
10priority-donate-chain)
11
12
13# Sources for tests.
14tests/threads_SRC = tests/threads/tests.c
15tests/threads_SRC += tests/threads/alarm-wait.c
16tests/threads_SRC += tests/threads/alarm-simultaneous.c
17tests/threads_SRC += tests/threads/alarm-priority.c
18tests/threads_SRC += tests/threads/alarm-zero.c
19tests/threads_SRC += tests/threads/alarm-negative.c
20tests/threads_SRC += tests/threads/priority-change.c
21tests/threads_SRC += tests/threads/priority-donate-one.c
22tests/threads_SRC += tests/threads/priority-donate-multiple.c
23tests/threads_SRC += tests/threads/priority-donate-multiple2.c
24tests/threads_SRC += tests/threads/priority-donate-nest.c
25tests/threads_SRC += tests/threads/priority-donate-sema.c
26tests/threads_SRC += tests/threads/priority-donate-lower.c
27tests/threads_SRC += tests/threads/priority-fifo.c
28tests/threads_SRC += tests/threads/priority-preempt.c
29tests/threads_SRC += tests/threads/priority-sema.c
30tests/threads_SRC += tests/threads/priority-condvar.c
31tests/threads_SRC += tests/threads/priority-donate-chain.c
32
33# Not used in SS 2012
34MLFQS_TESTS = mlfqs-load-1 mlfqs-load-60 mlfqs-load-avg mlfqs-recent-1 \
35mlfqs-fair-2 mlfqs-fair-20 mlfqs-nice-2 mlfqs-nice-10 mlfqs-block)
36
37tests/threads_SRC += tests/threads/mlfqs-load-1.c
38tests/threads_SRC += tests/threads/mlfqs-load-60.c
39tests/threads_SRC += tests/threads/mlfqs-load-avg.c
40tests/threads_SRC += tests/threads/mlfqs-recent-1.c
41tests/threads_SRC += tests/threads/mlfqs-fair.c
42tests/threads_SRC += tests/threads/mlfqs-block.c
43
44MLFQS_OUTPUTS = \
45tests/threads/mlfqs-load-1.output \
46tests/threads/mlfqs-load-60.output \
47tests/threads/mlfqs-load-avg.output \
48tests/threads/mlfqs-recent-1.output \
49tests/threads/mlfqs-fair-2.output \
50tests/threads/mlfqs-fair-20.output \
51tests/threads/mlfqs-nice-2.output \
52tests/threads/mlfqs-nice-10.output \
53tests/threads/mlfqs-block.output
54
55$(MLFQS_OUTPUTS): KERNELFLAGS += -mlfqs
56$(MLFQS_OUTPUTS): TIMEOUT = 480
diff --git a/pintos-progos/tests/threads/Rubric.alarm b/pintos-progos/tests/threads/Rubric.alarm
new file mode 100644
index 0000000..61abe85
--- /dev/null
+++ b/pintos-progos/tests/threads/Rubric.alarm
@@ -0,0 +1,8 @@
1Functionality and robustness of alarm clock:
24 alarm-single
34 alarm-multiple
44 alarm-simultaneous
54 alarm-priority
6
71 alarm-zero
81 alarm-negative
diff --git a/pintos-progos/tests/threads/Rubric.mlfqs b/pintos-progos/tests/threads/Rubric.mlfqs
new file mode 100644
index 0000000..f260091
--- /dev/null
+++ b/pintos-progos/tests/threads/Rubric.mlfqs
@@ -0,0 +1,14 @@
1Functionality of advanced scheduler:
25 mlfqs-load-1
35 mlfqs-load-60
43 mlfqs-load-avg
5
65 mlfqs-recent-1
7
85 mlfqs-fair-2
93 mlfqs-fair-20
10
114 mlfqs-nice-2
122 mlfqs-nice-10
13
145 mlfqs-block
diff --git a/pintos-progos/tests/threads/Rubric.priority b/pintos-progos/tests/threads/Rubric.priority
new file mode 100644
index 0000000..652bc99
--- /dev/null
+++ b/pintos-progos/tests/threads/Rubric.priority
@@ -0,0 +1,15 @@
1Functionality of priority scheduler:
23 priority-change
33 priority-preempt
4
53 priority-fifo
63 priority-sema
73 priority-condvar
8
93 priority-donate-one
103 priority-donate-multiple
113 priority-donate-multiple2
123 priority-donate-nest
135 priority-donate-chain
143 priority-donate-sema
153 priority-donate-lower
diff --git a/pintos-progos/tests/threads/alarm-multiple.ck b/pintos-progos/tests/threads/alarm-multiple.ck
new file mode 100644
index 0000000..fd83bcd
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-multiple.ck
@@ -0,0 +1,4 @@
1# -*- perl -*-
2use tests::tests;
3use tests::threads::alarm;
4check_alarm (7);
diff --git a/pintos-progos/tests/threads/alarm-negative.c b/pintos-progos/tests/threads/alarm-negative.c
new file mode 100644
index 0000000..aec52cf
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-negative.c
@@ -0,0 +1,15 @@
1/* Tests timer_sleep(-100). Only requirement is that it not crash. */
2
3#include <stdio.h>
4#include "tests/threads/tests.h"
5#include "threads/malloc.h"
6#include "threads/synch.h"
7#include "threads/thread.h"
8#include "devices/timer.h"
9
10void
11test_alarm_negative (void)
12{
13 timer_sleep (-100);
14 pass ();
15}
diff --git a/pintos-progos/tests/threads/alarm-negative.ck b/pintos-progos/tests/threads/alarm-negative.ck
new file mode 100644
index 0000000..0d2bab0
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-negative.ck
@@ -0,0 +1,10 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(alarm-negative) begin
7(alarm-negative) PASS
8(alarm-negative) end
9EOF
10pass;
diff --git a/pintos-progos/tests/threads/alarm-priority.c b/pintos-progos/tests/threads/alarm-priority.c
new file mode 100644
index 0000000..2288ff6
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-priority.c
@@ -0,0 +1,58 @@
1/* Checks that when the alarm clock wakes up threads, the
2 higher-priority threads run first. */
3
4#include <stdio.h>
5#include "tests/threads/tests.h"
6#include "threads/init.h"
7#include "threads/malloc.h"
8#include "threads/synch.h"
9#include "threads/thread.h"
10#include "devices/timer.h"
11
12static thread_func alarm_priority_thread;
13static int64_t wake_time;
14static struct semaphore wait_sema;
15
16void
17test_alarm_priority (void)
18{
19 int i;
20
21 /* This test does not work with the MLFQS. */
22 ASSERT (!thread_mlfqs);
23
24 wake_time = timer_ticks () + 5 * TIMER_FREQ;
25 sema_init (&wait_sema, 0);
26
27 for (i = 0; i < 10; i++)
28 {
29 int priority = PRI_DEFAULT - (i + 5) % 10 - 1;
30 char name[16];
31 snprintf (name, sizeof name, "priority %d", priority);
32 thread_create (name, priority, alarm_priority_thread, NULL);
33 }
34
35 thread_set_priority (PRI_MIN);
36
37 for (i = 0; i < 10; i++)
38 sema_down (&wait_sema);
39}
40
41static void
42alarm_priority_thread (void *aux UNUSED)
43{
44 /* Busy-wait until the current time changes. */
45 int64_t start_time = timer_ticks ();
46 while (timer_elapsed (start_time) == 0)
47 continue;
48
49 /* Now we know we're at the very beginning of a timer tick, so
50 we can call timer_sleep() without worrying about races
51 between checking the time and a timer interrupt. */
52 timer_sleep (wake_time - timer_ticks ());
53
54 /* Print a message on wake-up. */
55 msg ("Thread %s woke up.", thread_name ());
56
57 sema_up (&wait_sema);
58}
diff --git a/pintos-progos/tests/threads/alarm-priority.ck b/pintos-progos/tests/threads/alarm-priority.ck
new file mode 100644
index 0000000..b57c78b
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-priority.ck
@@ -0,0 +1,19 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(alarm-priority) begin
7(alarm-priority) Thread priority 30 woke up.
8(alarm-priority) Thread priority 29 woke up.
9(alarm-priority) Thread priority 28 woke up.
10(alarm-priority) Thread priority 27 woke up.
11(alarm-priority) Thread priority 26 woke up.
12(alarm-priority) Thread priority 25 woke up.
13(alarm-priority) Thread priority 24 woke up.
14(alarm-priority) Thread priority 23 woke up.
15(alarm-priority) Thread priority 22 woke up.
16(alarm-priority) Thread priority 21 woke up.
17(alarm-priority) end
18EOF
19pass;
diff --git a/pintos-progos/tests/threads/alarm-simultaneous.c b/pintos-progos/tests/threads/alarm-simultaneous.c
new file mode 100644
index 0000000..844eea4
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-simultaneous.c
@@ -0,0 +1,94 @@
1/* Creates N threads, each of which sleeps a different, fixed
2 duration, M times. Records the wake-up order and verifies
3 that it is valid. */
4
5#include <stdio.h>
6#include "tests/threads/tests.h"
7#include "threads/init.h"
8#include "threads/malloc.h"
9#include "threads/synch.h"
10#include "threads/thread.h"
11#include "devices/timer.h"
12
13static void test_sleep (int thread_cnt, int iterations);
14
15void
16test_alarm_simultaneous (void)
17{
18 test_sleep (3, 5);
19}
20
21/* Information about the test. */
22struct sleep_test
23 {
24 int64_t start; /* Current time at start of test. */
25 int iterations; /* Number of iterations per thread. */
26 int *output_pos; /* Current position in output buffer. */
27 };
28
29static void sleeper (void *);
30
31/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */
32static void
33test_sleep (int thread_cnt, int iterations)
34{
35 struct sleep_test test;
36 int *output;
37 int i;
38
39 /* This test does not work with the MLFQS. */
40 ASSERT (!thread_mlfqs);
41
42 msg ("Creating %d threads to sleep %d times each.", thread_cnt, iterations);
43 msg ("Each thread sleeps 10 ticks each time.");
44 msg ("Within an iteration, all threads should wake up on the same tick.");
45
46 /* Allocate memory. */
47 output = malloc (sizeof *output * iterations * thread_cnt * 2);
48 if (output == NULL)
49 PANIC ("couldn't allocate memory for test");
50
51 /* Initialize test. */
52 test.start = timer_ticks () + 100;
53 test.iterations = iterations;
54 test.output_pos = output;
55
56 /* Start threads. */
57 ASSERT (output != NULL);
58 for (i = 0; i < thread_cnt; i++)
59 {
60 char name[16];
61 snprintf (name, sizeof name, "thread %d", i);
62 thread_create (name, PRI_DEFAULT, sleeper, &test);
63 }
64
65 /* Wait long enough for all the threads to finish. */
66 timer_sleep (100 + iterations * 10 + 100);
67
68 /* Print completion order. */
69 msg ("iteration 0, thread 0: woke up after %d ticks", output[0]);
70 for (i = 1; i < test.output_pos - output; i++)
71 msg ("iteration %d, thread %d: woke up %d ticks later",
72 i / thread_cnt, i % thread_cnt, output[i] - output[i - 1]);
73
74 free (output);
75}
76
77/* Sleeper thread. */
78static void
79sleeper (void *test_)
80{
81 struct sleep_test *test = test_;
82 int i;
83
84 /* Make sure we're at the beginning of a timer tick. */
85 timer_sleep (1);
86
87 for (i = 1; i <= test->iterations; i++)
88 {
89 int64_t sleep_until = test->start + i * 10;
90 timer_sleep (sleep_until - timer_ticks ());
91 *test->output_pos++ = timer_ticks () - test->start;
92 thread_yield ();
93 }
94}
diff --git a/pintos-progos/tests/threads/alarm-simultaneous.ck b/pintos-progos/tests/threads/alarm-simultaneous.ck
new file mode 100644
index 0000000..406b8b0
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-simultaneous.ck
@@ -0,0 +1,27 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(alarm-simultaneous) begin
7(alarm-simultaneous) Creating 3 threads to sleep 5 times each.
8(alarm-simultaneous) Each thread sleeps 10 ticks each time.
9(alarm-simultaneous) Within an iteration, all threads should wake up on the same tick.
10(alarm-simultaneous) iteration 0, thread 0: woke up after 10 ticks
11(alarm-simultaneous) iteration 0, thread 1: woke up 0 ticks later
12(alarm-simultaneous) iteration 0, thread 2: woke up 0 ticks later
13(alarm-simultaneous) iteration 1, thread 0: woke up 10 ticks later
14(alarm-simultaneous) iteration 1, thread 1: woke up 0 ticks later
15(alarm-simultaneous) iteration 1, thread 2: woke up 0 ticks later
16(alarm-simultaneous) iteration 2, thread 0: woke up 10 ticks later
17(alarm-simultaneous) iteration 2, thread 1: woke up 0 ticks later
18(alarm-simultaneous) iteration 2, thread 2: woke up 0 ticks later
19(alarm-simultaneous) iteration 3, thread 0: woke up 10 ticks later
20(alarm-simultaneous) iteration 3, thread 1: woke up 0 ticks later
21(alarm-simultaneous) iteration 3, thread 2: woke up 0 ticks later
22(alarm-simultaneous) iteration 4, thread 0: woke up 10 ticks later
23(alarm-simultaneous) iteration 4, thread 1: woke up 0 ticks later
24(alarm-simultaneous) iteration 4, thread 2: woke up 0 ticks later
25(alarm-simultaneous) end
26EOF
27pass;
diff --git a/pintos-progos/tests/threads/alarm-single.ck b/pintos-progos/tests/threads/alarm-single.ck
new file mode 100644
index 0000000..31215df
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-single.ck
@@ -0,0 +1,4 @@
1# -*- perl -*-
2use tests::tests;
3use tests::threads::alarm;
4check_alarm (1);
diff --git a/pintos-progos/tests/threads/alarm-wait.c b/pintos-progos/tests/threads/alarm-wait.c
new file mode 100644
index 0000000..37d3afc
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-wait.c
@@ -0,0 +1,152 @@
1/* Creates N threads, each of which sleeps a different, fixed
2 duration, M times. Records the wake-up order and verifies
3 that it is valid. */
4
5#include <stdio.h>
6#include "tests/threads/tests.h"
7#include "threads/init.h"
8#include "threads/malloc.h"
9#include "threads/synch.h"
10#include "threads/thread.h"
11#include "devices/timer.h"
12
13static void test_sleep (int thread_cnt, int iterations);
14
15void
16test_alarm_single (void)
17{
18 test_sleep (5, 1);
19}
20
21void
22test_alarm_multiple (void)
23{
24 test_sleep (5, 7);
25}
26
27/* Information about the test. */
28struct sleep_test
29 {
30 int64_t start; /* Current time at start of test. */
31 int iterations; /* Number of iterations per thread. */
32
33 /* Output. */
34 struct lock output_lock; /* Lock protecting output buffer. */
35 int *output_pos; /* Current position in output buffer. */
36 };
37
38/* Information about an individual thread in the test. */
39struct sleep_thread
40 {
41 struct sleep_test *test; /* Info shared between all threads. */
42 int id; /* Sleeper ID. */
43 int duration; /* Number of ticks to sleep. */
44 int iterations; /* Iterations counted so far. */
45 };
46
47static void sleeper (void *);
48
49/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */
50static void
51test_sleep (int thread_cnt, int iterations)
52{
53 struct sleep_test test;
54 struct sleep_thread *threads;
55 int *output, *op;
56 int product;
57 int i;
58
59 /* This test does not work with the MLFQS. */
60 ASSERT (!thread_mlfqs);
61
62 msg ("Creating %d threads to sleep %d times each.", thread_cnt, iterations);
63 msg ("Thread 0 sleeps 10 ticks each time,");
64 msg ("thread 1 sleeps 20 ticks each time, and so on.");
65 msg ("If successful, product of iteration count and");
66 msg ("sleep duration will appear in nondescending order.");
67
68 /* Allocate memory. */
69 threads = malloc (sizeof *threads * thread_cnt);
70 output = malloc (sizeof *output * iterations * thread_cnt * 2);
71 if (threads == NULL || output == NULL)
72 PANIC ("couldn't allocate memory for test");
73
74 /* Initialize test. */
75 test.start = timer_ticks () + 100;
76 test.iterations = iterations;
77 lock_init (&test.output_lock);
78 test.output_pos = output;
79
80 /* Start threads. */
81 ASSERT (output != NULL);
82 for (i = 0; i < thread_cnt; i++)
83 {
84 struct sleep_thread *t = threads + i;
85 char name[16];
86
87 t->test = &test;
88 t->id = i;
89 t->duration = (i + 1) * 10;
90 t->iterations = 0;
91
92 snprintf (name, sizeof name, "thread %d", i);
93 thread_create (name, PRI_DEFAULT, sleeper, t);
94 }
95
96 /* Wait long enough for all the threads to finish. */
97 timer_sleep (100 + thread_cnt * iterations * 10 + 100);
98
99 /* Acquire the output lock in case some rogue thread is still
100 running. */
101 lock_acquire (&test.output_lock);
102
103 /* Print completion order. */
104 product = 0;
105 for (op = output; op < test.output_pos; op++)
106 {
107 struct sleep_thread *t;
108 int new_prod;
109
110 ASSERT (*op >= 0 && *op < thread_cnt);
111 t = threads + *op;
112
113 new_prod = ++t->iterations * t->duration;
114
115 msg ("thread %d: duration=%d, iteration=%d, product=%d",
116 t->id, t->duration, t->iterations, new_prod);
117
118 if (new_prod >= product)
119 product = new_prod;
120 else
121 fail ("thread %d woke up out of order (%d > %d)!",
122 t->id, product, new_prod);
123 }
124
125 /* Verify that we had the proper number of wakeups. */
126 for (i = 0; i < thread_cnt; i++)
127 if (threads[i].iterations != iterations)
128 fail ("thread %d woke up %d times instead of %d",
129 i, threads[i].iterations, iterations);
130
131 lock_release (&test.output_lock);
132 free (output);
133 free (threads);
134}
135
136/* Sleeper thread. */
137static void
138sleeper (void *t_)
139{
140 struct sleep_thread *t = t_;
141 struct sleep_test *test = t->test;
142 int i;
143
144 for (i = 1; i <= test->iterations; i++)
145 {
146 int64_t sleep_until = test->start + i * t->duration;
147 timer_sleep (sleep_until - timer_ticks ());
148 lock_acquire (&test->output_lock);
149 *test->output_pos++ = t->id;
150 lock_release (&test->output_lock);
151 }
152}
diff --git a/pintos-progos/tests/threads/alarm-zero.c b/pintos-progos/tests/threads/alarm-zero.c
new file mode 100644
index 0000000..c8a3ee2
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-zero.c
@@ -0,0 +1,15 @@
1/* Tests timer_sleep(0), which should return immediately. */
2
3#include <stdio.h>
4#include "tests/threads/tests.h"
5#include "threads/malloc.h"
6#include "threads/synch.h"
7#include "threads/thread.h"
8#include "devices/timer.h"
9
10void
11test_alarm_zero (void)
12{
13 timer_sleep (0);
14 pass ();
15}
diff --git a/pintos-progos/tests/threads/alarm-zero.ck b/pintos-progos/tests/threads/alarm-zero.ck
new file mode 100644
index 0000000..a6b1a3c
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm-zero.ck
@@ -0,0 +1,10 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(alarm-zero) begin
7(alarm-zero) PASS
8(alarm-zero) end
9EOF
10pass;
diff --git a/pintos-progos/tests/threads/alarm.pm b/pintos-progos/tests/threads/alarm.pm
new file mode 100644
index 0000000..84b3b7f
--- /dev/null
+++ b/pintos-progos/tests/threads/alarm.pm
@@ -0,0 +1,32 @@
1sub check_alarm {
2 my ($iterations) = @_;
3 our ($test);
4
5 @output = read_text_file ("$test.output");
6 common_checks ("run", @output);
7
8 my (@products);
9 for (my ($i) = 0; $i < $iterations; $i++) {
10 for (my ($t) = 0; $t < 5; $t++) {
11 push (@products, ($i + 1) * ($t + 1) * 10);
12 }
13 }
14 @products = sort {$a <=> $b} @products;
15
16 local ($_);
17 foreach (@output) {
18 fail $_ if /out of order/i;
19
20 my ($p) = /product=(\d+)$/;
21 next if !defined $p;
22
23 my ($q) = shift (@products);
24 fail "Too many wakeups.\n" if !defined $q;
25 fail "Out of order wakeups ($p vs. $q).\n" if $p != $q; # FIXME
26 }
27 fail scalar (@products) . " fewer wakeups than expected.\n"
28 if @products != 0;
29 pass;
30}
31
321;
diff --git a/pintos-progos/tests/threads/mlfqs-block.c b/pintos-progos/tests/threads/mlfqs-block.c
new file mode 100644
index 0000000..6d4992d
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-block.c
@@ -0,0 +1,64 @@
1/* Checks that recent_cpu and priorities are updated for blocked
2 threads.
3
4 The main thread sleeps for 25 seconds, spins for 5 seconds,
5 then releases a lock. The "block" thread spins for 20 seconds
6 then attempts to acquire the lock, which will block for 10
7 seconds (until the main thread releases it). If recent_cpu
8 decays properly while the "block" thread sleeps, then the
9 block thread should be immediately scheduled when the main
10 thread releases the lock. */
11
12#include <stdio.h>
13#include "tests/threads/tests.h"
14#include "threads/init.h"
15#include "threads/malloc.h"
16#include "threads/synch.h"
17#include "threads/thread.h"
18#include "devices/timer.h"
19
20static void block_thread (void *lock_);
21
22void
23test_mlfqs_block (void)
24{
25 int64_t start_time;
26 struct lock lock;
27
28 ASSERT (thread_mlfqs);
29
30 msg ("Main thread acquiring lock.");
31 lock_init (&lock);
32 lock_acquire (&lock);
33
34 msg ("Main thread creating block thread, sleeping 25 seconds...");
35 thread_create ("block", PRI_DEFAULT, block_thread, &lock);
36 timer_sleep (25 * TIMER_FREQ);
37
38 msg ("Main thread spinning for 5 seconds...");
39 start_time = timer_ticks ();
40 while (timer_elapsed (start_time) < 5 * TIMER_FREQ)
41 continue;
42
43 msg ("Main thread releasing lock.");
44 lock_release (&lock);
45
46 msg ("Block thread should have already acquired lock.");
47}
48
49static void
50block_thread (void *lock_)
51{
52 struct lock *lock = lock_;
53 int64_t start_time;
54
55 msg ("Block thread spinning for 20 seconds...");
56 start_time = timer_ticks ();
57 while (timer_elapsed (start_time) < 20 * TIMER_FREQ)
58 continue;
59
60 msg ("Block thread acquiring lock...");
61 lock_acquire (lock);
62
63 msg ("...got it.");
64}
diff --git a/pintos-progos/tests/threads/mlfqs-block.ck b/pintos-progos/tests/threads/mlfqs-block.ck
new file mode 100644
index 0000000..8833a3a
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-block.ck
@@ -0,0 +1,17 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(mlfqs-block) begin
7(mlfqs-block) Main thread acquiring lock.
8(mlfqs-block) Main thread creating block thread, sleeping 25 seconds...
9(mlfqs-block) Block thread spinning for 20 seconds...
10(mlfqs-block) Block thread acquiring lock...
11(mlfqs-block) Main thread spinning for 5 seconds...
12(mlfqs-block) Main thread releasing lock.
13(mlfqs-block) ...got it.
14(mlfqs-block) Block thread should have already acquired lock.
15(mlfqs-block) end
16EOF
17pass;
diff --git a/pintos-progos/tests/threads/mlfqs-fair-2.ck b/pintos-progos/tests/threads/mlfqs-fair-2.ck
new file mode 100644
index 0000000..5b19ff1
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-fair-2.ck
@@ -0,0 +1,7 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7check_mlfqs_fair ([0, 0], 50);
diff --git a/pintos-progos/tests/threads/mlfqs-fair-20.ck b/pintos-progos/tests/threads/mlfqs-fair-20.ck
new file mode 100644
index 0000000..bb4d051
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-fair-20.ck
@@ -0,0 +1,7 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7check_mlfqs_fair ([(0) x 20], 20);
diff --git a/pintos-progos/tests/threads/mlfqs-fair.c b/pintos-progos/tests/threads/mlfqs-fair.c
new file mode 100644
index 0000000..3b1bea5
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-fair.c
@@ -0,0 +1,124 @@
1/* Measures the correctness of the "nice" implementation.
2
3 The "fair" tests run either 2 or 20 threads all niced to 0.
4 The threads should all receive approximately the same number
5 of ticks. Each test runs for 30 seconds, so the ticks should
6 also sum to approximately 30 * 100 == 3000 ticks.
7
8 The mlfqs-nice-2 test runs 2 threads, one with nice 0, the
9 other with nice 5, which should receive 1,904 and 1,096 ticks,
10 respectively, over 30 seconds.
11
12 The mlfqs-nice-10 test runs 10 threads with nice 0 through 9.
13 They should receive 672, 588, 492, 408, 316, 232, 152, 92, 40,
14 and 8 ticks, respectively, over 30 seconds.
15
16 (The above are computed via simulation in mlfqs.pm.) */
17
18#include <stdio.h>
19#include <inttypes.h>
20#include "tests/threads/tests.h"
21#include "threads/init.h"
22#include "threads/malloc.h"
23#include "threads/palloc.h"
24#include "threads/synch.h"
25#include "threads/thread.h"
26#include "devices/timer.h"
27
28static void test_mlfqs_fair (int thread_cnt, int nice_min, int nice_step);
29
30void
31test_mlfqs_fair_2 (void)
32{
33 test_mlfqs_fair (2, 0, 0);
34}
35
36void
37test_mlfqs_fair_20 (void)
38{
39 test_mlfqs_fair (20, 0, 0);
40}
41
42void
43test_mlfqs_nice_2 (void)
44{
45 test_mlfqs_fair (2, 0, 5);
46}
47
48void
49test_mlfqs_nice_10 (void)
50{
51 test_mlfqs_fair (10, 0, 1);
52}
53
54#define MAX_THREAD_CNT 20
55
56struct thread_info
57 {
58 int64_t start_time;
59 int tick_count;
60 int nice;
61 };
62
63static void load_thread (void *aux);
64
65static void
66test_mlfqs_fair (int thread_cnt, int nice_min, int nice_step)
67{
68 struct thread_info info[MAX_THREAD_CNT];
69 int64_t start_time;
70 int nice;
71 int i;
72
73 ASSERT (thread_mlfqs);
74 ASSERT (thread_cnt <= MAX_THREAD_CNT);
75 ASSERT (nice_min >= -10);
76 ASSERT (nice_step >= 0);
77 ASSERT (nice_min + nice_step * (thread_cnt - 1) <= 20);
78
79 thread_set_nice (-20);
80
81 start_time = timer_ticks ();
82 msg ("Starting %d threads...", thread_cnt);
83 nice = nice_min;
84 for (i = 0; i < thread_cnt; i++)
85 {
86 struct thread_info *ti = &info[i];
87 char name[16];
88
89 ti->start_time = start_time;
90 ti->tick_count = 0;
91 ti->nice = nice;
92
93 snprintf(name, sizeof name, "load %d", i);
94 thread_create (name, PRI_DEFAULT, load_thread, ti);
95
96 nice += nice_step;
97 }
98 msg ("Starting threads took %"PRId64" ticks.", timer_elapsed (start_time));
99
100 msg ("Sleeping 40 seconds to let threads run, please wait...");
101 timer_sleep (40 * TIMER_FREQ);
102
103 for (i = 0; i < thread_cnt; i++)
104 msg ("Thread %d received %d ticks.", i, info[i].tick_count);
105}
106
107static void
108load_thread (void *ti_)
109{
110 struct thread_info *ti = ti_;
111 int64_t sleep_time = 5 * TIMER_FREQ;
112 int64_t spin_time = sleep_time + 30 * TIMER_FREQ;
113 int64_t last_time = 0;
114
115 thread_set_nice (ti->nice);
116 timer_sleep (sleep_time - timer_elapsed (ti->start_time));
117 while (timer_elapsed (ti->start_time) < spin_time)
118 {
119 int64_t cur_time = timer_ticks ();
120 if (cur_time != last_time)
121 ti->tick_count++;
122 last_time = cur_time;
123 }
124}
diff --git a/pintos-progos/tests/threads/mlfqs-load-1.c b/pintos-progos/tests/threads/mlfqs-load-1.c
new file mode 100644
index 0000000..a39eea2
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-1.c
@@ -0,0 +1,60 @@
1/* Verifies that a single busy thread raises the load average to
2 0.5 in 38 to 45 seconds. The expected time is 42 seconds, as
3 you can verify:
4 perl -e '$i++,$a=(59*$a+1)/60while$a<=.5;print "$i\n"'
5
6 Then, verifies that 10 seconds of inactivity drop the load
7 average back below 0.5 again. */
8
9#include <stdio.h>
10#include "tests/threads/tests.h"
11#include "threads/init.h"
12#include "threads/malloc.h"
13#include "threads/synch.h"
14#include "threads/thread.h"
15#include "devices/timer.h"
16
17void
18test_mlfqs_load_1 (void)
19{
20 int64_t start_time;
21 int elapsed;
22 int load_avg;
23
24 ASSERT (thread_mlfqs);
25
26 msg ("spinning for up to 45 seconds, please wait...");
27
28 start_time = timer_ticks ();
29 for (;;)
30 {
31 load_avg = thread_get_load_avg ();
32 ASSERT (load_avg >= 0);
33 elapsed = timer_elapsed (start_time) / TIMER_FREQ;
34 if (load_avg > 100)
35 fail ("load average is %d.%02d "
36 "but should be between 0 and 1 (after %d seconds)",
37 load_avg / 100, load_avg % 100, elapsed);
38 else if (load_avg > 50)
39 break;
40 else if (elapsed > 45)
41 fail ("load average stayed below 0.5 for more than 45 seconds");
42 }
43
44 if (elapsed < 38)
45 fail ("load average took only %d seconds to rise above 0.5", elapsed);
46 msg ("load average rose to 0.5 after %d seconds", elapsed);
47
48 msg ("sleeping for another 10 seconds, please wait...");
49 timer_sleep (TIMER_FREQ * 10);
50
51 load_avg = thread_get_load_avg ();
52 if (load_avg < 0)
53 fail ("load average fell below 0");
54 if (load_avg > 50)
55 fail ("load average stayed above 0.5 for more than 10 seconds");
56 msg ("load average fell back below 0.5 (to %d.%02d)",
57 load_avg / 100, load_avg % 100);
58
59 pass ();
60}
diff --git a/pintos-progos/tests/threads/mlfqs-load-1.ck b/pintos-progos/tests/threads/mlfqs-load-1.ck
new file mode 100644
index 0000000..faf0ffa
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-1.ck
@@ -0,0 +1,15 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5
6our ($test);
7my (@output) = read_text_file ("$test.output");
8
9common_checks ("run", @output);
10
11@output = get_core_output ("run", @output);
12fail "missing PASS in output"
13 unless grep ($_ eq '(mlfqs-load-1) PASS', @output);
14
15pass;
diff --git a/pintos-progos/tests/threads/mlfqs-load-60.c b/pintos-progos/tests/threads/mlfqs-load-60.c
new file mode 100644
index 0000000..b6a3eb6
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-60.c
@@ -0,0 +1,155 @@
1/* Starts 60 threads that each sleep for 10 seconds, then spin in
2 a tight loop for 60 seconds, and sleep for another 60 seconds.
3 Every 2 seconds after the initial sleep, the main thread
4 prints the load average.
5
6 The expected output is this (some margin of error is allowed):
7
8 After 0 seconds, load average=1.00.
9 After 2 seconds, load average=2.95.
10 After 4 seconds, load average=4.84.
11 After 6 seconds, load average=6.66.
12 After 8 seconds, load average=8.42.
13 After 10 seconds, load average=10.13.
14 After 12 seconds, load average=11.78.
15 After 14 seconds, load average=13.37.
16 After 16 seconds, load average=14.91.
17 After 18 seconds, load average=16.40.
18 After 20 seconds, load average=17.84.
19 After 22 seconds, load average=19.24.
20 After 24 seconds, load average=20.58.
21 After 26 seconds, load average=21.89.
22 After 28 seconds, load average=23.15.
23 After 30 seconds, load average=24.37.
24 After 32 seconds, load average=25.54.
25 After 34 seconds, load average=26.68.
26 After 36 seconds, load average=27.78.
27 After 38 seconds, load average=28.85.
28 After 40 seconds, load average=29.88.
29 After 42 seconds, load average=30.87.
30 After 44 seconds, load average=31.84.
31 After 46 seconds, load average=32.77.
32 After 48 seconds, load average=33.67.
33 After 50 seconds, load average=34.54.
34 After 52 seconds, load average=35.38.
35 After 54 seconds, load average=36.19.
36 After 56 seconds, load average=36.98.
37 After 58 seconds, load average=37.74.
38 After 60 seconds, load average=37.48.
39 After 62 seconds, load average=36.24.
40 After 64 seconds, load average=35.04.
41 After 66 seconds, load average=33.88.
42 After 68 seconds, load average=32.76.
43 After 70 seconds, load average=31.68.
44 After 72 seconds, load average=30.63.
45 After 74 seconds, load average=29.62.
46 After 76 seconds, load average=28.64.
47 After 78 seconds, load average=27.69.
48 After 80 seconds, load average=26.78.
49 After 82 seconds, load average=25.89.
50 After 84 seconds, load average=25.04.
51 After 86 seconds, load average=24.21.
52 After 88 seconds, load average=23.41.
53 After 90 seconds, load average=22.64.
54 After 92 seconds, load average=21.89.
55 After 94 seconds, load average=21.16.
56 After 96 seconds, load average=20.46.
57 After 98 seconds, load average=19.79.
58 After 100 seconds, load average=19.13.
59 After 102 seconds, load average=18.50.
60 After 104 seconds, load average=17.89.
61 After 106 seconds, load average=17.30.
62 After 108 seconds, load average=16.73.
63 After 110 seconds, load average=16.17.
64 After 112 seconds, load average=15.64.
65 After 114 seconds, load average=15.12.
66 After 116 seconds, load average=14.62.
67 After 118 seconds, load average=14.14.
68 After 120 seconds, load average=13.67.
69 After 122 seconds, load average=13.22.
70 After 124 seconds, load average=12.78.
71 After 126 seconds, load average=12.36.
72 After 128 seconds, load average=11.95.
73 After 130 seconds, load average=11.56.
74 After 132 seconds, load average=11.17.
75 After 134 seconds, load average=10.80.
76 After 136 seconds, load average=10.45.
77 After 138 seconds, load average=10.10.
78 After 140 seconds, load average=9.77.
79 After 142 seconds, load average=9.45.
80 After 144 seconds, load average=9.13.
81 After 146 seconds, load average=8.83.
82 After 148 seconds, load average=8.54.
83 After 150 seconds, load average=8.26.
84 After 152 seconds, load average=7.98.
85 After 154 seconds, load average=7.72.
86 After 156 seconds, load average=7.47.
87 After 158 seconds, load average=7.22.
88 After 160 seconds, load average=6.98.
89 After 162 seconds, load average=6.75.
90 After 164 seconds, load average=6.53.
91 After 166 seconds, load average=6.31.
92 After 168 seconds, load average=6.10.
93 After 170 seconds, load average=5.90.
94 After 172 seconds, load average=5.70.
95 After 174 seconds, load average=5.52.
96 After 176 seconds, load average=5.33.
97 After 178 seconds, load average=5.16.
98*/
99
100#include <stdio.h>
101#include "tests/threads/tests.h"
102#include "threads/init.h"
103#include "threads/malloc.h"
104#include "threads/synch.h"
105#include "threads/thread.h"
106#include "devices/timer.h"
107
108static int64_t start_time;
109
110static void load_thread (void *aux);
111
112#define THREAD_CNT 60
113
114void
115test_mlfqs_load_60 (void)
116{
117 int i;
118
119 ASSERT (thread_mlfqs);
120
121 start_time = timer_ticks ();
122 msg ("Starting %d niced load threads...", THREAD_CNT);
123 for (i = 0; i < THREAD_CNT; i++)
124 {
125 char name[16];
126 snprintf(name, sizeof name, "load %d", i);
127 thread_create (name, PRI_DEFAULT, load_thread, NULL);
128 }
129 msg ("Starting threads took %d seconds.",
130 timer_elapsed (start_time) / TIMER_FREQ);
131
132 for (i = 0; i < 90; i++)
133 {
134 int64_t sleep_until = start_time + TIMER_FREQ * (2 * i + 10);
135 int load_avg;
136 timer_sleep (sleep_until - timer_ticks ());
137 load_avg = thread_get_load_avg ();
138 msg ("After %d seconds, load average=%d.%02d.",
139 i * 2, load_avg / 100, load_avg % 100);
140 }
141}
142
143static void
144load_thread (void *aux UNUSED)
145{
146 int64_t sleep_time = 10 * TIMER_FREQ;
147 int64_t spin_time = sleep_time + 60 * TIMER_FREQ;
148 int64_t exit_time = spin_time + 60 * TIMER_FREQ;
149
150 thread_set_nice (20);
151 timer_sleep (sleep_time - timer_elapsed (start_time));
152 while (timer_elapsed (start_time) < spin_time)
153 continue;
154 timer_sleep (exit_time - timer_elapsed (start_time));
155}
diff --git a/pintos-progos/tests/threads/mlfqs-load-60.ck b/pintos-progos/tests/threads/mlfqs-load-60.ck
new file mode 100644
index 0000000..cb69220
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-60.ck
@@ -0,0 +1,36 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7our ($test);
8
9my (@output) = read_text_file ("$test.output");
10common_checks ("run", @output);
11@output = get_core_output ("run", @output);
12
13# Get actual values.
14local ($_);
15my (@actual);
16foreach (@output) {
17 my ($t, $load_avg) = /After (\d+) seconds, load average=(\d+\.\d+)\./
18 or next;
19 $actual[$t] = $load_avg;
20}
21
22# Calculate expected values.
23my ($load_avg) = 0;
24my ($recent) = 0;
25my (@expected);
26for (my ($t) = 0; $t < 180; $t++) {
27 my ($ready) = $t < 60 ? 60 : 0;
28 $load_avg = (59/60) * $load_avg + (1/60) * $ready;
29 $expected[$t] = $load_avg;
30}
31
32mlfqs_compare ("time", "%.2f", \@actual, \@expected, 3.5, [2, 178, 2],
33 "Some load average values were missing or "
34 . "differed from those expected "
35 . "by more than 3.5.");
36pass;
diff --git a/pintos-progos/tests/threads/mlfqs-load-avg.c b/pintos-progos/tests/threads/mlfqs-load-avg.c
new file mode 100644
index 0000000..50e83e2
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-avg.c
@@ -0,0 +1,167 @@
1/* Starts 60 threads numbered 0 through 59. Thread #i sleeps for
2 (10+i) seconds, then spins in a loop for 60 seconds, then
3 sleeps until a total of 120 seconds have passed. Every 2
4 seconds, starting 10 seconds in, the main thread prints the
5 load average.
6
7 The expected output is listed below. Some margin of error is
8 allowed.
9
10 If your implementation fails this test but passes most other
11 tests, then consider whether you are doing too much work in
12 the timer interrupt. If the timer interrupt handler takes too
13 long, then the test's main thread will not have enough time to
14 do its own work (printing a message) and go back to sleep
15 before the next tick arrives. Then the main thread will be
16 ready, instead of sleeping, when the tick arrives,
17 artificially driving up the load average.
18
19 After 0 seconds, load average=0.00.
20 After 2 seconds, load average=0.05.
21 After 4 seconds, load average=0.16.
22 After 6 seconds, load average=0.34.
23 After 8 seconds, load average=0.58.
24 After 10 seconds, load average=0.87.
25 After 12 seconds, load average=1.22.
26 After 14 seconds, load average=1.63.
27 After 16 seconds, load average=2.09.
28 After 18 seconds, load average=2.60.
29 After 20 seconds, load average=3.16.
30 After 22 seconds, load average=3.76.
31 After 24 seconds, load average=4.42.
32 After 26 seconds, load average=5.11.
33 After 28 seconds, load average=5.85.
34 After 30 seconds, load average=6.63.
35 After 32 seconds, load average=7.46.
36 After 34 seconds, load average=8.32.
37 After 36 seconds, load average=9.22.
38 After 38 seconds, load average=10.15.
39 After 40 seconds, load average=11.12.
40 After 42 seconds, load average=12.13.
41 After 44 seconds, load average=13.16.
42 After 46 seconds, load average=14.23.
43 After 48 seconds, load average=15.33.
44 After 50 seconds, load average=16.46.
45 After 52 seconds, load average=17.62.
46 After 54 seconds, load average=18.81.
47 After 56 seconds, load average=20.02.
48 After 58 seconds, load average=21.26.
49 After 60 seconds, load average=22.52.
50 After 62 seconds, load average=23.71.
51 After 64 seconds, load average=24.80.
52 After 66 seconds, load average=25.78.
53 After 68 seconds, load average=26.66.
54 After 70 seconds, load average=27.45.
55 After 72 seconds, load average=28.14.
56 After 74 seconds, load average=28.75.
57 After 76 seconds, load average=29.27.
58 After 78 seconds, load average=29.71.
59 After 80 seconds, load average=30.06.
60 After 82 seconds, load average=30.34.
61 After 84 seconds, load average=30.55.
62 After 86 seconds, load average=30.68.
63 After 88 seconds, load average=30.74.
64 After 90 seconds, load average=30.73.
65 After 92 seconds, load average=30.66.
66 After 94 seconds, load average=30.52.
67 After 96 seconds, load average=30.32.
68 After 98 seconds, load average=30.06.
69 After 100 seconds, load average=29.74.
70 After 102 seconds, load average=29.37.
71 After 104 seconds, load average=28.95.
72 After 106 seconds, load average=28.47.
73 After 108 seconds, load average=27.94.
74 After 110 seconds, load average=27.36.
75 After 112 seconds, load average=26.74.
76 After 114 seconds, load average=26.07.
77 After 116 seconds, load average=25.36.
78 After 118 seconds, load average=24.60.
79 After 120 seconds, load average=23.81.
80 After 122 seconds, load average=23.02.
81 After 124 seconds, load average=22.26.
82 After 126 seconds, load average=21.52.
83 After 128 seconds, load average=20.81.
84 After 130 seconds, load average=20.12.
85 After 132 seconds, load average=19.46.
86 After 134 seconds, load average=18.81.
87 After 136 seconds, load average=18.19.
88 After 138 seconds, load average=17.59.
89 After 140 seconds, load average=17.01.
90 After 142 seconds, load average=16.45.
91 After 144 seconds, load average=15.90.
92 After 146 seconds, load average=15.38.
93 After 148 seconds, load average=14.87.
94 After 150 seconds, load average=14.38.
95 After 152 seconds, load average=13.90.
96 After 154 seconds, load average=13.44.
97 After 156 seconds, load average=13.00.
98 After 158 seconds, load average=12.57.
99 After 160 seconds, load average=12.15.
100 After 162 seconds, load average=11.75.
101 After 164 seconds, load average=11.36.
102 After 166 seconds, load average=10.99.
103 After 168 seconds, load average=10.62.
104 After 170 seconds, load average=10.27.
105 After 172 seconds, load average=9.93.
106 After 174 seconds, load average=9.61.
107 After 176 seconds, load average=9.29.
108 After 178 seconds, load average=8.98.
109*/
110
111#include <stdio.h>
112#include "tests/threads/tests.h"
113#include "threads/init.h"
114#include "threads/malloc.h"
115#include "threads/synch.h"
116#include "threads/thread.h"
117#include "devices/timer.h"
118
119static int64_t start_time;
120
121static void load_thread (void *seq_no);
122
123#define THREAD_CNT 60
124
125void
126test_mlfqs_load_avg (void)
127{
128 int i;
129
130 ASSERT (thread_mlfqs);
131
132 start_time = timer_ticks ();
133 msg ("Starting %d load threads...", THREAD_CNT);
134 for (i = 0; i < THREAD_CNT; i++)
135 {
136 char name[16];
137 snprintf(name, sizeof name, "load %d", i);
138 thread_create (name, PRI_DEFAULT, load_thread, (void *) i);
139 }
140 msg ("Starting threads took %d seconds.",
141 timer_elapsed (start_time) / TIMER_FREQ);
142 thread_set_nice (-20);
143
144 for (i = 0; i < 90; i++)
145 {
146 int64_t sleep_until = start_time + TIMER_FREQ * (2 * i + 10);
147 int load_avg;
148 timer_sleep (sleep_until - timer_ticks ());
149 load_avg = thread_get_load_avg ();
150 msg ("After %d seconds, load average=%d.%02d.",
151 i * 2, load_avg / 100, load_avg % 100);
152 }
153}
154
155static void
156load_thread (void *seq_no_)
157{
158 int seq_no = (int) seq_no_;
159 int sleep_time = TIMER_FREQ * (10 + seq_no);
160 int spin_time = sleep_time + TIMER_FREQ * THREAD_CNT;
161 int exit_time = TIMER_FREQ * (THREAD_CNT * 2);
162
163 timer_sleep (sleep_time - timer_elapsed (start_time));
164 while (timer_elapsed (start_time) < spin_time)
165 continue;
166 timer_sleep (exit_time - timer_elapsed (start_time));
167}
diff --git a/pintos-progos/tests/threads/mlfqs-load-avg.ck b/pintos-progos/tests/threads/mlfqs-load-avg.ck
new file mode 100644
index 0000000..2254d05
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-load-avg.ck
@@ -0,0 +1,36 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7our ($test);
8my (@output) = read_text_file ("$test.output");
9
10common_checks ("run", @output);
11@output = get_core_output ("run", @output);
12
13# Get actual values.
14local ($_);
15my (@actual);
16foreach (@output) {
17 my ($t, $load_avg) = /After (\d+) seconds, load average=(\d+\.\d+)\./
18 or next;
19 $actual[$t] = $load_avg;
20}
21
22# Calculate expected values.
23my ($load_avg) = 0;
24my ($recent) = 0;
25my (@expected);
26for (my ($t) = 0; $t < 180; $t++) {
27 my ($ready) = $t < 60 ? $t : $t < 120 ? 120 - $t : 0;
28 $load_avg = (59/60) * $load_avg + (1/60) * $ready;
29 $expected[$t] = $load_avg;
30}
31
32mlfqs_compare ("time", "%.2f", \@actual, \@expected, 2.5, [2, 178, 2],
33 "Some load average values were missing or "
34 . "differed from those expected "
35 . "by more than 2.5.");
36pass;
diff --git a/pintos-progos/tests/threads/mlfqs-nice-10.ck b/pintos-progos/tests/threads/mlfqs-nice-10.ck
new file mode 100644
index 0000000..53e0abe
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-nice-10.ck
@@ -0,0 +1,7 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7check_mlfqs_fair ([0...9], 25);
diff --git a/pintos-progos/tests/threads/mlfqs-nice-2.ck b/pintos-progos/tests/threads/mlfqs-nice-2.ck
new file mode 100644
index 0000000..ada366b
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-nice-2.ck
@@ -0,0 +1,7 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7check_mlfqs_fair ([0, 5], 50);
diff --git a/pintos-progos/tests/threads/mlfqs-recent-1.c b/pintos-progos/tests/threads/mlfqs-recent-1.c
new file mode 100644
index 0000000..4258671
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-recent-1.c
@@ -0,0 +1,144 @@
1/* Checks that recent_cpu is calculated properly for the case of
2 a single ready process.
3
4 The expected output is this (some margin of error is allowed):
5
6 After 2 seconds, recent_cpu is 6.40, load_avg is 0.03.
7 After 4 seconds, recent_cpu is 12.60, load_avg is 0.07.
8 After 6 seconds, recent_cpu is 18.61, load_avg is 0.10.
9 After 8 seconds, recent_cpu is 24.44, load_avg is 0.13.
10 After 10 seconds, recent_cpu is 30.08, load_avg is 0.15.
11 After 12 seconds, recent_cpu is 35.54, load_avg is 0.18.
12 After 14 seconds, recent_cpu is 40.83, load_avg is 0.21.
13 After 16 seconds, recent_cpu is 45.96, load_avg is 0.24.
14 After 18 seconds, recent_cpu is 50.92, load_avg is 0.26.
15 After 20 seconds, recent_cpu is 55.73, load_avg is 0.29.
16 After 22 seconds, recent_cpu is 60.39, load_avg is 0.31.
17 After 24 seconds, recent_cpu is 64.90, load_avg is 0.33.
18 After 26 seconds, recent_cpu is 69.27, load_avg is 0.35.
19 After 28 seconds, recent_cpu is 73.50, load_avg is 0.38.
20 After 30 seconds, recent_cpu is 77.60, load_avg is 0.40.
21 After 32 seconds, recent_cpu is 81.56, load_avg is 0.42.
22 After 34 seconds, recent_cpu is 85.40, load_avg is 0.44.
23 After 36 seconds, recent_cpu is 89.12, load_avg is 0.45.
24 After 38 seconds, recent_cpu is 92.72, load_avg is 0.47.
25 After 40 seconds, recent_cpu is 96.20, load_avg is 0.49.
26 After 42 seconds, recent_cpu is 99.57, load_avg is 0.51.
27 After 44 seconds, recent_cpu is 102.84, load_avg is 0.52.
28 After 46 seconds, recent_cpu is 106.00, load_avg is 0.54.
29 After 48 seconds, recent_cpu is 109.06, load_avg is 0.55.
30 After 50 seconds, recent_cpu is 112.02, load_avg is 0.57.
31 After 52 seconds, recent_cpu is 114.89, load_avg is 0.58.
32 After 54 seconds, recent_cpu is 117.66, load_avg is 0.60.
33 After 56 seconds, recent_cpu is 120.34, load_avg is 0.61.
34 After 58 seconds, recent_cpu is 122.94, load_avg is 0.62.
35 After 60 seconds, recent_cpu is 125.46, load_avg is 0.64.
36 After 62 seconds, recent_cpu is 127.89, load_avg is 0.65.
37 After 64 seconds, recent_cpu is 130.25, load_avg is 0.66.
38 After 66 seconds, recent_cpu is 132.53, load_avg is 0.67.
39 After 68 seconds, recent_cpu is 134.73, load_avg is 0.68.
40 After 70 seconds, recent_cpu is 136.86, load_avg is 0.69.
41 After 72 seconds, recent_cpu is 138.93, load_avg is 0.70.
42 After 74 seconds, recent_cpu is 140.93, load_avg is 0.71.
43 After 76 seconds, recent_cpu is 142.86, load_avg is 0.72.
44 After 78 seconds, recent_cpu is 144.73, load_avg is 0.73.
45 After 80 seconds, recent_cpu is 146.54, load_avg is 0.74.
46 After 82 seconds, recent_cpu is 148.29, load_avg is 0.75.
47 After 84 seconds, recent_cpu is 149.99, load_avg is 0.76.
48 After 86 seconds, recent_cpu is 151.63, load_avg is 0.76.
49 After 88 seconds, recent_cpu is 153.21, load_avg is 0.77.
50 After 90 seconds, recent_cpu is 154.75, load_avg is 0.78.
51 After 92 seconds, recent_cpu is 156.23, load_avg is 0.79.
52 After 94 seconds, recent_cpu is 157.67, load_avg is 0.79.
53 After 96 seconds, recent_cpu is 159.06, load_avg is 0.80.
54 After 98 seconds, recent_cpu is 160.40, load_avg is 0.81.
55 After 100 seconds, recent_cpu is 161.70, load_avg is 0.81.
56 After 102 seconds, recent_cpu is 162.96, load_avg is 0.82.
57 After 104 seconds, recent_cpu is 164.18, load_avg is 0.83.
58 After 106 seconds, recent_cpu is 165.35, load_avg is 0.83.
59 After 108 seconds, recent_cpu is 166.49, load_avg is 0.84.
60 After 110 seconds, recent_cpu is 167.59, load_avg is 0.84.
61 After 112 seconds, recent_cpu is 168.66, load_avg is 0.85.
62 After 114 seconds, recent_cpu is 169.69, load_avg is 0.85.
63 After 116 seconds, recent_cpu is 170.69, load_avg is 0.86.
64 After 118 seconds, recent_cpu is 171.65, load_avg is 0.86.
65 After 120 seconds, recent_cpu is 172.58, load_avg is 0.87.
66 After 122 seconds, recent_cpu is 173.49, load_avg is 0.87.
67 After 124 seconds, recent_cpu is 174.36, load_avg is 0.88.
68 After 126 seconds, recent_cpu is 175.20, load_avg is 0.88.
69 After 128 seconds, recent_cpu is 176.02, load_avg is 0.88.
70 After 130 seconds, recent_cpu is 176.81, load_avg is 0.89.
71 After 132 seconds, recent_cpu is 177.57, load_avg is 0.89.
72 After 134 seconds, recent_cpu is 178.31, load_avg is 0.89.
73 After 136 seconds, recent_cpu is 179.02, load_avg is 0.90.
74 After 138 seconds, recent_cpu is 179.72, load_avg is 0.90.
75 After 140 seconds, recent_cpu is 180.38, load_avg is 0.90.
76 After 142 seconds, recent_cpu is 181.03, load_avg is 0.91.
77 After 144 seconds, recent_cpu is 181.65, load_avg is 0.91.
78 After 146 seconds, recent_cpu is 182.26, load_avg is 0.91.
79 After 148 seconds, recent_cpu is 182.84, load_avg is 0.92.
80 After 150 seconds, recent_cpu is 183.41, load_avg is 0.92.
81 After 152 seconds, recent_cpu is 183.96, load_avg is 0.92.
82 After 154 seconds, recent_cpu is 184.49, load_avg is 0.92.
83 After 156 seconds, recent_cpu is 185.00, load_avg is 0.93.
84 After 158 seconds, recent_cpu is 185.49, load_avg is 0.93.
85 After 160 seconds, recent_cpu is 185.97, load_avg is 0.93.
86 After 162 seconds, recent_cpu is 186.43, load_avg is 0.93.
87 After 164 seconds, recent_cpu is 186.88, load_avg is 0.94.
88 After 166 seconds, recent_cpu is 187.31, load_avg is 0.94.
89 After 168 seconds, recent_cpu is 187.73, load_avg is 0.94.
90 After 170 seconds, recent_cpu is 188.14, load_avg is 0.94.
91 After 172 seconds, recent_cpu is 188.53, load_avg is 0.94.
92 After 174 seconds, recent_cpu is 188.91, load_avg is 0.95.
93 After 176 seconds, recent_cpu is 189.27, load_avg is 0.95.
94 After 178 seconds, recent_cpu is 189.63, load_avg is 0.95.
95 After 180 seconds, recent_cpu is 189.97, load_avg is 0.95.
96*/
97
98#include <stdio.h>
99#include "tests/threads/tests.h"
100#include "threads/init.h"
101#include "threads/malloc.h"
102#include "threads/synch.h"
103#include "threads/thread.h"
104#include "devices/timer.h"
105
106/* Sensitive to assumption that recent_cpu updates happen exactly
107 when timer_ticks() % TIMER_FREQ == 0. */
108
109void
110test_mlfqs_recent_1 (void)
111{
112 int64_t start_time;
113 int last_elapsed = 0;
114
115 ASSERT (thread_mlfqs);
116
117 do
118 {
119 msg ("Sleeping 10 seconds to allow recent_cpu to decay, please wait...");
120 start_time = timer_ticks ();
121 timer_sleep (DIV_ROUND_UP (start_time, TIMER_FREQ) - start_time
122 + 10 * TIMER_FREQ);
123 }
124 while (thread_get_recent_cpu () > 700);
125
126 start_time = timer_ticks ();
127 for (;;)
128 {
129 int elapsed = timer_elapsed (start_time);
130 if (elapsed % (TIMER_FREQ * 2) == 0 && elapsed > last_elapsed)
131 {
132 int recent_cpu = thread_get_recent_cpu ();
133 int load_avg = thread_get_load_avg ();
134 int elapsed_seconds = elapsed / TIMER_FREQ;
135 msg ("After %d seconds, recent_cpu is %d.%02d, load_avg is %d.%02d.",
136 elapsed_seconds,
137 recent_cpu / 100, recent_cpu % 100,
138 load_avg / 100, load_avg % 100);
139 if (elapsed_seconds >= 180)
140 break;
141 }
142 last_elapsed = elapsed;
143 }
144}
diff --git a/pintos-progos/tests/threads/mlfqs-recent-1.ck b/pintos-progos/tests/threads/mlfqs-recent-1.ck
new file mode 100644
index 0000000..a2ba44d
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs-recent-1.ck
@@ -0,0 +1,31 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5use tests::threads::mlfqs;
6
7our ($test);
8my (@output) = read_text_file ("$test.output");
9common_checks ("run", @output);
10@output = get_core_output ("run", @output);
11
12# Get actual values.
13local ($_);
14my (@actual);
15foreach (@output) {
16 my ($t, $recent_cpu) = /After (\d+) seconds, recent_cpu is (\d+\.\d+),/
17 or next;
18 $actual[$t] = $recent_cpu;
19}
20
21# Calculate expected values.
22my ($expected_load_avg, $expected_recent_cpu)
23 = mlfqs_expected_load ([(1) x 180], [(100) x 180]);
24my (@expected) = @$expected_recent_cpu;
25
26# Compare actual and expected values.
27mlfqs_compare ("time", "%.2f", \@actual, \@expected, 2.5, [2, 178, 2],
28 "Some recent_cpu values were missing or "
29 . "differed from those expected "
30 . "by more than 2.5.");
31pass;
diff --git a/pintos-progos/tests/threads/mlfqs.pm b/pintos-progos/tests/threads/mlfqs.pm
new file mode 100644
index 0000000..184ac16
--- /dev/null
+++ b/pintos-progos/tests/threads/mlfqs.pm
@@ -0,0 +1,146 @@
1# -*- perl -*-
2use strict;
3use warnings;
4
5sub mlfqs_expected_load {
6 my ($ready, $recent_delta) = @_;
7 my (@load_avg) = 0;
8 my (@recent_cpu) = 0;
9 my ($load_avg) = 0;
10 my ($recent_cpu) = 0;
11 for my $i (0...$#$ready) {
12 $load_avg = (59/60) * $load_avg + (1/60) * $ready->[$i];
13 push (@load_avg, $load_avg);
14
15 if (defined $recent_delta->[$i]) {
16 my ($twice_load) = $load_avg * 2;
17 my ($load_factor) = $twice_load / ($twice_load + 1);
18 $recent_cpu = ($recent_cpu + $recent_delta->[$i]) * $load_factor;
19 push (@recent_cpu, $recent_cpu);
20 }
21 }
22 return (\@load_avg, \@recent_cpu);
23}
24
25sub mlfqs_expected_ticks {
26 my (@nice) = @_;
27 my ($thread_cnt) = scalar (@nice);
28 my (@recent_cpu) = (0) x $thread_cnt;
29 my (@slices) = (0) x $thread_cnt;
30 my (@fifo) = (0) x $thread_cnt;
31 my ($next_fifo) = 1;
32 my ($load_avg) = 0;
33 for my $i (1...750) {
34 if ($i % 25 == 0) {
35 # Update load average.
36 $load_avg = (59/60) * $load_avg + (1/60) * $thread_cnt;
37
38 # Update recent_cpu.
39 my ($twice_load) = $load_avg * 2;
40 my ($load_factor) = $twice_load / ($twice_load + 1);
41 $recent_cpu[$_] = $recent_cpu[$_] * $load_factor + $nice[$_]
42 foreach 0...($thread_cnt - 1);
43 }
44
45 # Update priorities.
46 my (@priority);
47 foreach my $j (0...($thread_cnt - 1)) {
48 my ($priority) = int ($recent_cpu[$j] / 4 + $nice[$j] * 2);
49 $priority = 0 if $priority < 0;
50 $priority = 63 if $priority > 63;
51 push (@priority, $priority);
52 }
53
54 # Choose thread to run.
55 my $max = 0;
56 for my $j (1...$#priority) {
57 if ($priority[$j] < $priority[$max]
58 || ($priority[$j] == $priority[$max]
59 && $fifo[$j] < $fifo[$max])) {
60 $max = $j;
61 }
62 }
63 $fifo[$max] = $next_fifo++;
64
65 # Run thread.
66 $recent_cpu[$max] += 4;
67 $slices[$max] += 4;
68 }
69 return @slices;
70}
71
72sub check_mlfqs_fair {
73 my ($nice, $maxdiff) = @_;
74 our ($test);
75 my (@output) = read_text_file ("$test.output");
76 common_checks ("run", @output);
77 @output = get_core_output ("run", @output);
78
79 my (@actual);
80 local ($_);
81 foreach (@output) {
82 my ($id, $count) = /Thread (\d+) received (\d+) ticks\./ or next;
83 $actual[$id] = $count;
84 }
85
86 my (@expected) = mlfqs_expected_ticks (@$nice);
87 mlfqs_compare ("thread", "%d",
88 \@actual, \@expected, $maxdiff, [0, $#$nice, 1],
89 "Some tick counts were missing or differed from those "
90 . "expected by more than $maxdiff.");
91 pass;
92}
93
94sub mlfqs_compare {
95 my ($indep_var, $format,
96 $actual_ref, $expected_ref, $maxdiff, $t_range, $message) = @_;
97 my ($t_min, $t_max, $t_step) = @$t_range;
98
99 my ($ok) = 1;
100 for (my ($t) = $t_min; $t <= $t_max; $t += $t_step) {
101 my ($actual) = $actual_ref->[$t];
102 my ($expected) = $expected_ref->[$t];
103 $ok = 0, last
104 if !defined ($actual) || abs ($actual - $expected) > $maxdiff + .01;
105 }
106 return if $ok;
107
108 print "$message\n";
109 mlfqs_row ($indep_var, "actual", "<->", "expected", "explanation");
110 mlfqs_row ("------", "--------", "---", "--------", '-' x 40);
111 for (my ($t) = $t_min; $t <= $t_max; $t += $t_step) {
112 my ($actual) = $actual_ref->[$t];
113 my ($expected) = $expected_ref->[$t];
114 my ($diff, $rationale);
115 if (!defined $actual) {
116 $actual = 'undef' ;
117 $diff = '';
118 $rationale = 'Missing value.';
119 } else {
120 my ($delta) = abs ($actual - $expected);
121 if ($delta > $maxdiff + .01) {
122 my ($excess) = $delta - $maxdiff;
123 if ($actual > $expected) {
124 $diff = '>>>';
125 $rationale = sprintf "Too big, by $format.", $excess;
126 } else {
127 $diff = '<<<';
128 $rationale = sprintf "Too small, by $format.", $excess;
129 }
130 } else {
131 $diff = ' = ';
132 $rationale = '';
133 }
134 $actual = sprintf ($format, $actual);
135 }
136 $expected = sprintf ($format, $expected);
137 mlfqs_row ($t, $actual, $diff, $expected, $rationale);
138 }
139 fail;
140}
141
142sub mlfqs_row {
143 printf "%6s %8s %3s %-8s %s\n", @_;
144}
145
1461;
diff --git a/pintos-progos/tests/threads/priority-change.c b/pintos-progos/tests/threads/priority-change.c
new file mode 100644
index 0000000..810b05a
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-change.c
@@ -0,0 +1,31 @@
1/* Verifies that lowering a thread's priority so that it is no
2 longer the highest-priority thread in the system causes it to
3 yield immediately. */
4
5#include <stdio.h>
6#include "tests/threads/tests.h"
7#include "threads/init.h"
8#include "threads/thread.h"
9
10static thread_func changing_thread;
11
12void
13test_priority_change (void)
14{
15 /* This test does not work with the MLFQS. */
16 ASSERT (!thread_mlfqs);
17
18 msg ("Creating a high-priority thread 2.");
19 thread_create ("thread 2", PRI_DEFAULT + 1, changing_thread, NULL);
20 msg ("Thread 2 should have just lowered its priority.");
21 thread_set_priority (PRI_DEFAULT - 2);
22 msg ("Thread 2 should have just exited.");
23}
24
25static void
26changing_thread (void *aux UNUSED)
27{
28 msg ("Thread 2 now lowering priority.");
29 thread_set_priority (PRI_DEFAULT - 1);
30 msg ("Thread 2 exiting.");
31}
diff --git a/pintos-progos/tests/threads/priority-change.ck b/pintos-progos/tests/threads/priority-change.ck
new file mode 100644
index 0000000..f4d9b2f
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-change.ck
@@ -0,0 +1,14 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-change) begin
7(priority-change) Creating a high-priority thread 2.
8(priority-change) Thread 2 now lowering priority.
9(priority-change) Thread 2 should have just lowered its priority.
10(priority-change) Thread 2 exiting.
11(priority-change) Thread 2 should have just exited.
12(priority-change) end
13EOF
14pass;
diff --git a/pintos-progos/tests/threads/priority-condvar.c b/pintos-progos/tests/threads/priority-condvar.c
new file mode 100644
index 0000000..c1efb1b
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-condvar.c
@@ -0,0 +1,53 @@
1/* Tests that cond_signal() wakes up the highest-priority thread
2 waiting in cond_wait(). */
3
4#include <stdio.h>
5#include "tests/threads/tests.h"
6#include "threads/init.h"
7#include "threads/malloc.h"
8#include "threads/synch.h"
9#include "threads/thread.h"
10#include "devices/timer.h"
11
12static thread_func priority_condvar_thread;
13static struct lock lock;
14static struct condition condition;
15
16void
17test_priority_condvar (void)
18{
19 int i;
20
21 /* This test does not work with the MLFQS. */
22 ASSERT (!thread_mlfqs);
23
24 lock_init (&lock);
25 cond_init (&condition);
26
27 thread_set_priority (PRI_MIN);
28 for (i = 0; i < 10; i++)
29 {
30 int priority = PRI_DEFAULT - (i + 7) % 10 - 1;
31 char name[16];
32 snprintf (name, sizeof name, "priority %d", priority);
33 thread_create (name, priority, priority_condvar_thread, NULL);
34 }
35
36 for (i = 0; i < 10; i++)
37 {
38 lock_acquire (&lock);
39 msg ("Signaling...");
40 cond_signal (&condition, &lock);
41 lock_release (&lock);
42 }
43}
44
45static void
46priority_condvar_thread (void *aux UNUSED)
47{
48 msg ("Thread %s starting.", thread_name ());
49 lock_acquire (&lock);
50 cond_wait (&condition, &lock);
51 msg ("Thread %s woke up.", thread_name ());
52 lock_release (&lock);
53}
diff --git a/pintos-progos/tests/threads/priority-condvar.ck b/pintos-progos/tests/threads/priority-condvar.ck
new file mode 100644
index 0000000..195c1ab
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-condvar.ck
@@ -0,0 +1,39 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-condvar) begin
7(priority-condvar) Thread priority 23 starting.
8(priority-condvar) Thread priority 22 starting.
9(priority-condvar) Thread priority 21 starting.
10(priority-condvar) Thread priority 30 starting.
11(priority-condvar) Thread priority 29 starting.
12(priority-condvar) Thread priority 28 starting.
13(priority-condvar) Thread priority 27 starting.
14(priority-condvar) Thread priority 26 starting.
15(priority-condvar) Thread priority 25 starting.
16(priority-condvar) Thread priority 24 starting.
17(priority-condvar) Signaling...
18(priority-condvar) Thread priority 30 woke up.
19(priority-condvar) Signaling...
20(priority-condvar) Thread priority 29 woke up.
21(priority-condvar) Signaling...
22(priority-condvar) Thread priority 28 woke up.
23(priority-condvar) Signaling...
24(priority-condvar) Thread priority 27 woke up.
25(priority-condvar) Signaling...
26(priority-condvar) Thread priority 26 woke up.
27(priority-condvar) Signaling...
28(priority-condvar) Thread priority 25 woke up.
29(priority-condvar) Signaling...
30(priority-condvar) Thread priority 24 woke up.
31(priority-condvar) Signaling...
32(priority-condvar) Thread priority 23 woke up.
33(priority-condvar) Signaling...
34(priority-condvar) Thread priority 22 woke up.
35(priority-condvar) Signaling...
36(priority-condvar) Thread priority 21 woke up.
37(priority-condvar) end
38EOF
39pass;
diff --git a/pintos-progos/tests/threads/priority-donate-chain.c b/pintos-progos/tests/threads/priority-donate-chain.c
new file mode 100644
index 0000000..3ffabca
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-chain.c
@@ -0,0 +1,114 @@
1/* The main thread set its priority to PRI_MIN and creates 7 threads
2 (thread 1..7) with priorities PRI_MIN + 3, 6, 9, 12, ...
3 The main thread initializes 8 locks: lock 0..7 and acquires lock 0.
4
5 When thread[i] starts, it first acquires lock[i] (unless i == 7.)
6 Subsequently, thread[i] attempts to acquire lock[i-1], which is held by
7 thread[i-1], except for lock[0], which is held by the main thread.
8 Because the lock is held, thread[i] donates its priority to thread[i-1],
9 which donates to thread[i-2], and so on until the main thread
10 receives the donation.
11
12 After threads[1..7] have been created and are blocked on locks[0..7],
13 the main thread releases lock[0], unblocking thread[1], and being
14 preempted by it.
15 Thread[1] then completes acquiring lock[0], then releases lock[0],
16 then releases lock[1], unblocking thread[2], etc.
17 Thread[7] finally acquires & releases lock[7] and exits, allowing
18 thread[6], then thread[5] etc. to run and exit until finally the
19 main thread exits.
20
21 In addition, interloper threads are created at priority levels
22 p = PRI_MIN + 2, 5, 8, 11, ... which should not be run until the
23 corresponding thread with priority p + 1 has finished.
24
25 Written by Godmar Back <gback@cs.vt.edu> */
26
27#include <stdio.h>
28#include "tests/threads/tests.h"
29#include "threads/init.h"
30#include "threads/synch.h"
31#include "threads/thread.h"
32
33#define NESTING_DEPTH 8
34
35struct lock_pair
36 {
37 struct lock *second;
38 struct lock *first;
39 };
40
41static thread_func donor_thread_func;
42static thread_func interloper_thread_func;
43
44void
45test_priority_donate_chain (void)
46{
47 int i;
48 struct lock locks[NESTING_DEPTH - 1];
49 struct lock_pair lock_pairs[NESTING_DEPTH];
50
51 /* This test does not work with the MLFQS. */
52 ASSERT (!thread_mlfqs);
53
54 thread_set_priority (PRI_MIN);
55
56 for (i = 0; i < NESTING_DEPTH - 1; i++)
57 lock_init (&locks[i]);
58
59 lock_acquire (&locks[0]);
60 msg ("%s got lock.", thread_name ());
61
62 for (i = 1; i < NESTING_DEPTH; i++)
63 {
64 char name[16];
65 int thread_priority;
66
67 snprintf (name, sizeof name, "thread %d", i);
68 thread_priority = PRI_MIN + i * 3;
69 lock_pairs[i].first = i < NESTING_DEPTH - 1 ? locks + i: NULL;
70 lock_pairs[i].second = locks + i - 1;
71
72 thread_create (name, thread_priority, donor_thread_func, lock_pairs + i);
73 msg ("%s should have priority %d. Actual priority: %d.",
74 thread_name (), thread_priority, thread_get_priority ());
75
76 snprintf (name, sizeof name, "interloper %d", i);
77 thread_create (name, thread_priority - 1, interloper_thread_func, NULL);
78 }
79
80 lock_release (&locks[0]);
81 msg ("%s finishing with priority %d.", thread_name (),
82 thread_get_priority ());
83}
84
85static void
86donor_thread_func (void *locks_)
87{
88 struct lock_pair *locks = locks_;
89
90 if (locks->first)
91 lock_acquire (locks->first);
92
93 lock_acquire (locks->second);
94 msg ("%s got lock", thread_name ());
95
96 lock_release (locks->second);
97 msg ("%s should have priority %d. Actual priority: %d",
98 thread_name (), (NESTING_DEPTH - 1) * 3,
99 thread_get_priority ());
100
101 if (locks->first)
102 lock_release (locks->first);
103
104 msg ("%s finishing with priority %d.", thread_name (),
105 thread_get_priority ());
106}
107
108static void
109interloper_thread_func (void *arg_ UNUSED)
110{
111 msg ("%s finished.", thread_name ());
112}
113
114// vim: sw=2
diff --git a/pintos-progos/tests/threads/priority-donate-chain.ck b/pintos-progos/tests/threads/priority-donate-chain.ck
new file mode 100644
index 0000000..213e649
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-chain.ck
@@ -0,0 +1,46 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-chain) begin
7(priority-donate-chain) main got lock.
8(priority-donate-chain) main should have priority 3. Actual priority: 3.
9(priority-donate-chain) main should have priority 6. Actual priority: 6.
10(priority-donate-chain) main should have priority 9. Actual priority: 9.
11(priority-donate-chain) main should have priority 12. Actual priority: 12.
12(priority-donate-chain) main should have priority 15. Actual priority: 15.
13(priority-donate-chain) main should have priority 18. Actual priority: 18.
14(priority-donate-chain) main should have priority 21. Actual priority: 21.
15(priority-donate-chain) thread 1 got lock
16(priority-donate-chain) thread 1 should have priority 21. Actual priority: 21
17(priority-donate-chain) thread 2 got lock
18(priority-donate-chain) thread 2 should have priority 21. Actual priority: 21
19(priority-donate-chain) thread 3 got lock
20(priority-donate-chain) thread 3 should have priority 21. Actual priority: 21
21(priority-donate-chain) thread 4 got lock
22(priority-donate-chain) thread 4 should have priority 21. Actual priority: 21
23(priority-donate-chain) thread 5 got lock
24(priority-donate-chain) thread 5 should have priority 21. Actual priority: 21
25(priority-donate-chain) thread 6 got lock
26(priority-donate-chain) thread 6 should have priority 21. Actual priority: 21
27(priority-donate-chain) thread 7 got lock
28(priority-donate-chain) thread 7 should have priority 21. Actual priority: 21
29(priority-donate-chain) thread 7 finishing with priority 21.
30(priority-donate-chain) interloper 7 finished.
31(priority-donate-chain) thread 6 finishing with priority 18.
32(priority-donate-chain) interloper 6 finished.
33(priority-donate-chain) thread 5 finishing with priority 15.
34(priority-donate-chain) interloper 5 finished.
35(priority-donate-chain) thread 4 finishing with priority 12.
36(priority-donate-chain) interloper 4 finished.
37(priority-donate-chain) thread 3 finishing with priority 9.
38(priority-donate-chain) interloper 3 finished.
39(priority-donate-chain) thread 2 finishing with priority 6.
40(priority-donate-chain) interloper 2 finished.
41(priority-donate-chain) thread 1 finishing with priority 3.
42(priority-donate-chain) interloper 1 finished.
43(priority-donate-chain) main finishing with priority 0.
44(priority-donate-chain) end
45EOF
46pass;
diff --git a/pintos-progos/tests/threads/priority-donate-lower.c b/pintos-progos/tests/threads/priority-donate-lower.c
new file mode 100644
index 0000000..4965d75
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-lower.c
@@ -0,0 +1,51 @@
1/* The main thread acquires a lock. Then it creates a
2 higher-priority thread that blocks acquiring the lock, causing
3 it to donate their priorities to the main thread. The main
4 thread attempts to lower its priority, which should not take
5 effect until the donation is released. */
6
7#include <stdio.h>
8#include "tests/threads/tests.h"
9#include "threads/init.h"
10#include "threads/synch.h"
11#include "threads/thread.h"
12
13static thread_func acquire_thread_func;
14
15void
16test_priority_donate_lower (void)
17{
18 struct lock lock;
19
20 /* This test does not work with the MLFQS. */
21 ASSERT (!thread_mlfqs);
22
23 /* Make sure our priority is the default. */
24 ASSERT (thread_get_priority () == PRI_DEFAULT);
25
26 lock_init (&lock);
27 lock_acquire (&lock);
28 thread_create ("acquire", PRI_DEFAULT + 10, acquire_thread_func, &lock);
29 msg ("Main thread should have priority %d. Actual priority: %d.",
30 PRI_DEFAULT + 10, thread_get_priority ());
31
32 msg ("Lowering base priority...");
33 thread_set_priority (PRI_DEFAULT - 10);
34 msg ("Main thread should have priority %d. Actual priority: %d.",
35 PRI_DEFAULT + 10, thread_get_priority ());
36 lock_release (&lock);
37 msg ("acquire must already have finished.");
38 msg ("Main thread should have priority %d. Actual priority: %d.",
39 PRI_DEFAULT - 10, thread_get_priority ());
40}
41
42static void
43acquire_thread_func (void *lock_)
44{
45 struct lock *lock = lock_;
46
47 lock_acquire (lock);
48 msg ("acquire: got the lock");
49 lock_release (lock);
50 msg ("acquire: done");
51}
diff --git a/pintos-progos/tests/threads/priority-donate-lower.ck b/pintos-progos/tests/threads/priority-donate-lower.ck
new file mode 100644
index 0000000..c9bb61b
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-lower.ck
@@ -0,0 +1,16 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-lower) begin
7(priority-donate-lower) Main thread should have priority 41. Actual priority: 41.
8(priority-donate-lower) Lowering base priority...
9(priority-donate-lower) Main thread should have priority 41. Actual priority: 41.
10(priority-donate-lower) acquire: got the lock
11(priority-donate-lower) acquire: done
12(priority-donate-lower) acquire must already have finished.
13(priority-donate-lower) Main thread should have priority 21. Actual priority: 21.
14(priority-donate-lower) end
15EOF
16pass;
diff --git a/pintos-progos/tests/threads/priority-donate-multiple.c b/pintos-progos/tests/threads/priority-donate-multiple.c
new file mode 100644
index 0000000..df4689c
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-multiple.c
@@ -0,0 +1,77 @@
1/* The main thread acquires locks A and B, then it creates two
2 higher-priority threads. Each of these threads blocks
3 acquiring one of the locks and thus donate their priority to
4 the main thread. The main thread releases the locks in turn
5 and relinquishes its donated priorities.
6
7 Based on a test originally submitted for Stanford's CS 140 in
8 winter 1999 by Matt Franklin <startled@leland.stanford.edu>,
9 Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu
10 <yph@cs.stanford.edu>. Modified by arens. */
11
12#include <stdio.h>
13#include "tests/threads/tests.h"
14#include "threads/init.h"
15#include "threads/synch.h"
16#include "threads/thread.h"
17
18static thread_func a_thread_func;
19static thread_func b_thread_func;
20
21void
22test_priority_donate_multiple (void)
23{
24 struct lock a, b;
25
26 /* This test does not work with the MLFQS. */
27 ASSERT (!thread_mlfqs);
28
29 /* Make sure our priority is the default. */
30 ASSERT (thread_get_priority () == PRI_DEFAULT);
31
32 lock_init (&a);
33 lock_init (&b);
34
35 lock_acquire (&a);
36 lock_acquire (&b);
37
38 thread_create ("a", PRI_DEFAULT + 1, a_thread_func, &a);
39 msg ("Main thread should have priority %d. Actual priority: %d.",
40 PRI_DEFAULT + 1, thread_get_priority ());
41
42 thread_create ("b", PRI_DEFAULT + 2, b_thread_func, &b);
43 msg ("Main thread should have priority %d. Actual priority: %d.",
44 PRI_DEFAULT + 2, thread_get_priority ());
45
46 lock_release (&b);
47 msg ("Thread b should have just finished.");
48 msg ("Main thread should have priority %d. Actual priority: %d.",
49 PRI_DEFAULT + 1, thread_get_priority ());
50
51 lock_release (&a);
52 msg ("Thread a should have just finished.");
53 msg ("Main thread should have priority %d. Actual priority: %d.",
54 PRI_DEFAULT, thread_get_priority ());
55}
56
57static void
58a_thread_func (void *lock_)
59{
60 struct lock *lock = lock_;
61
62 lock_acquire (lock);
63 msg ("Thread a acquired lock a.");
64 lock_release (lock);
65 msg ("Thread a finished.");
66}
67
68static void
69b_thread_func (void *lock_)
70{
71 struct lock *lock = lock_;
72
73 lock_acquire (lock);
74 msg ("Thread b acquired lock b.");
75 lock_release (lock);
76 msg ("Thread b finished.");
77}
diff --git a/pintos-progos/tests/threads/priority-donate-multiple.ck b/pintos-progos/tests/threads/priority-donate-multiple.ck
new file mode 100644
index 0000000..0afd20b
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-multiple.ck
@@ -0,0 +1,19 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-multiple) begin
7(priority-donate-multiple) Main thread should have priority 32. Actual priority: 32.
8(priority-donate-multiple) Main thread should have priority 33. Actual priority: 33.
9(priority-donate-multiple) Thread b acquired lock b.
10(priority-donate-multiple) Thread b finished.
11(priority-donate-multiple) Thread b should have just finished.
12(priority-donate-multiple) Main thread should have priority 32. Actual priority: 32.
13(priority-donate-multiple) Thread a acquired lock a.
14(priority-donate-multiple) Thread a finished.
15(priority-donate-multiple) Thread a should have just finished.
16(priority-donate-multiple) Main thread should have priority 31. Actual priority: 31.
17(priority-donate-multiple) end
18EOF
19pass;
diff --git a/pintos-progos/tests/threads/priority-donate-multiple2.c b/pintos-progos/tests/threads/priority-donate-multiple2.c
new file mode 100644
index 0000000..7f65fef
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-multiple2.c
@@ -0,0 +1,90 @@
1/* The main thread acquires locks A and B, then it creates three
2 higher-priority threads. The first two of these threads block
3 acquiring one of the locks and thus donate their priority to
4 the main thread. The main thread releases the locks in turn
5 and relinquishes its donated priorities, allowing the third thread
6 to run.
7
8 In this test, the main thread releases the locks in a different
9 order compared to priority-donate-multiple.c.
10
11 Written by Godmar Back <gback@cs.vt.edu>.
12 Based on a test originally submitted for Stanford's CS 140 in
13 winter 1999 by Matt Franklin <startled@leland.stanford.edu>,
14 Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu
15 <yph@cs.stanford.edu>. Modified by arens. */
16
17#include <stdio.h>
18#include "tests/threads/tests.h"
19#include "threads/init.h"
20#include "threads/synch.h"
21#include "threads/thread.h"
22
23static thread_func a_thread_func;
24static thread_func b_thread_func;
25static thread_func c_thread_func;
26
27void
28test_priority_donate_multiple2 (void)
29{
30 struct lock a, b;
31
32 /* This test does not work with the MLFQS. */
33 ASSERT (!thread_mlfqs);
34
35 /* Make sure our priority is the default. */
36 ASSERT (thread_get_priority () == PRI_DEFAULT);
37
38 lock_init (&a);
39 lock_init (&b);
40
41 lock_acquire (&a);
42 lock_acquire (&b);
43
44 thread_create ("a", PRI_DEFAULT + 3, a_thread_func, &a);
45 msg ("Main thread should have priority %d. Actual priority: %d.",
46 PRI_DEFAULT + 3, thread_get_priority ());
47
48 thread_create ("c", PRI_DEFAULT + 1, c_thread_func, NULL);
49
50 thread_create ("b", PRI_DEFAULT + 5, b_thread_func, &b);
51 msg ("Main thread should have priority %d. Actual priority: %d.",
52 PRI_DEFAULT + 5, thread_get_priority ());
53
54 lock_release (&a);
55 msg ("Main thread should have priority %d. Actual priority: %d.",
56 PRI_DEFAULT + 5, thread_get_priority ());
57
58 lock_release (&b);
59 msg ("Threads b, a, c should have just finished, in that order.");
60 msg ("Main thread should have priority %d. Actual priority: %d.",
61 PRI_DEFAULT, thread_get_priority ());
62}
63
64static void
65a_thread_func (void *lock_)
66{
67 struct lock *lock = lock_;
68
69 lock_acquire (lock);
70 msg ("Thread a acquired lock a.");
71 lock_release (lock);
72 msg ("Thread a finished.");
73}
74
75static void
76b_thread_func (void *lock_)
77{
78 struct lock *lock = lock_;
79
80 lock_acquire (lock);
81 msg ("Thread b acquired lock b.");
82 lock_release (lock);
83 msg ("Thread b finished.");
84}
85
86static void
87c_thread_func (void *a_ UNUSED)
88{
89 msg ("Thread c finished.");
90}
diff --git a/pintos-progos/tests/threads/priority-donate-multiple2.ck b/pintos-progos/tests/threads/priority-donate-multiple2.ck
new file mode 100644
index 0000000..b23533a
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-multiple2.ck
@@ -0,0 +1,19 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-multiple2) begin
7(priority-donate-multiple2) Main thread should have priority 34. Actual priority: 34.
8(priority-donate-multiple2) Main thread should have priority 36. Actual priority: 36.
9(priority-donate-multiple2) Main thread should have priority 36. Actual priority: 36.
10(priority-donate-multiple2) Thread b acquired lock b.
11(priority-donate-multiple2) Thread b finished.
12(priority-donate-multiple2) Thread a acquired lock a.
13(priority-donate-multiple2) Thread a finished.
14(priority-donate-multiple2) Thread c finished.
15(priority-donate-multiple2) Threads b, a, c should have just finished, in that order.
16(priority-donate-multiple2) Main thread should have priority 31. Actual priority: 31.
17(priority-donate-multiple2) end
18EOF
19pass;
diff --git a/pintos-progos/tests/threads/priority-donate-nest.c b/pintos-progos/tests/threads/priority-donate-nest.c
new file mode 100644
index 0000000..3a3a9a5
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-nest.c
@@ -0,0 +1,94 @@
1/* Low-priority main thread L acquires lock A. Medium-priority
2 thread M then acquires lock B then blocks on acquiring lock A.
3 High-priority thread H then blocks on acquiring lock B. Thus,
4 thread H donates its priority to M, which in turn donates it
5 to thread L.
6
7 Based on a test originally submitted for Stanford's CS 140 in
8 winter 1999 by Matt Franklin <startled@leland.stanford.edu>,
9 Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu
10 <yph@cs.stanford.edu>. Modified by arens. */
11
12#include <stdio.h>
13#include "tests/threads/tests.h"
14#include "threads/init.h"
15#include "threads/synch.h"
16#include "threads/thread.h"
17
18struct locks
19 {
20 struct lock *a;
21 struct lock *b;
22 };
23
24static thread_func medium_thread_func;
25static thread_func high_thread_func;
26
27void
28test_priority_donate_nest (void)
29{
30 struct lock a, b;
31 struct locks locks;
32
33 /* This test does not work with the MLFQS. */
34 ASSERT (!thread_mlfqs);
35
36 /* Make sure our priority is the default. */
37 ASSERT (thread_get_priority () == PRI_DEFAULT);
38
39 lock_init (&a);
40 lock_init (&b);
41
42 lock_acquire (&a);
43
44 locks.a = &a;
45 locks.b = &b;
46 thread_create ("medium", PRI_DEFAULT + 1, medium_thread_func, &locks);
47 thread_yield ();
48 msg ("Low thread should have priority %d. Actual priority: %d.",
49 PRI_DEFAULT + 1, thread_get_priority ());
50
51 thread_create ("high", PRI_DEFAULT + 2, high_thread_func, &b);
52 thread_yield ();
53 msg ("Low thread should have priority %d. Actual priority: %d.",
54 PRI_DEFAULT + 2, thread_get_priority ());
55
56 lock_release (&a);
57 thread_yield ();
58 msg ("Medium thread should just have finished.");
59 msg ("Low thread should have priority %d. Actual priority: %d.",
60 PRI_DEFAULT, thread_get_priority ());
61}
62
63static void
64medium_thread_func (void *locks_)
65{
66 struct locks *locks = locks_;
67
68 lock_acquire (locks->b);
69 lock_acquire (locks->a);
70
71 msg ("Medium thread should have priority %d. Actual priority: %d.",
72 PRI_DEFAULT + 2, thread_get_priority ());
73 msg ("Medium thread got the lock.");
74
75 lock_release (locks->a);
76 thread_yield ();
77
78 lock_release (locks->b);
79 thread_yield ();
80
81 msg ("High thread should have just finished.");
82 msg ("Middle thread finished.");
83}
84
85static void
86high_thread_func (void *lock_)
87{
88 struct lock *lock = lock_;
89
90 lock_acquire (lock);
91 msg ("High thread got the lock.");
92 lock_release (lock);
93 msg ("High thread finished.");
94}
diff --git a/pintos-progos/tests/threads/priority-donate-nest.ck b/pintos-progos/tests/threads/priority-donate-nest.ck
new file mode 100644
index 0000000..923460e
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-nest.ck
@@ -0,0 +1,19 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-nest) begin
7(priority-donate-nest) Low thread should have priority 32. Actual priority: 32.
8(priority-donate-nest) Low thread should have priority 33. Actual priority: 33.
9(priority-donate-nest) Medium thread should have priority 33. Actual priority: 33.
10(priority-donate-nest) Medium thread got the lock.
11(priority-donate-nest) High thread got the lock.
12(priority-donate-nest) High thread finished.
13(priority-donate-nest) High thread should have just finished.
14(priority-donate-nest) Middle thread finished.
15(priority-donate-nest) Medium thread should just have finished.
16(priority-donate-nest) Low thread should have priority 31. Actual priority: 31.
17(priority-donate-nest) end
18EOF
19pass;
diff --git a/pintos-progos/tests/threads/priority-donate-one.c b/pintos-progos/tests/threads/priority-donate-one.c
new file mode 100644
index 0000000..3189f3a
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-one.c
@@ -0,0 +1,65 @@
1/* The main thread acquires a lock. Then it creates two
2 higher-priority threads that block acquiring the lock, causing
3 them to donate their priorities to the main thread. When the
4 main thread releases the lock, the other threads should
5 acquire it in priority order.
6
7 Based on a test originally submitted for Stanford's CS 140 in
8 winter 1999 by Matt Franklin <startled@leland.stanford.edu>,
9 Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu
10 <yph@cs.stanford.edu>. Modified by arens. */
11
12#include <stdio.h>
13#include "tests/threads/tests.h"
14#include "threads/init.h"
15#include "threads/synch.h"
16#include "threads/thread.h"
17
18static thread_func acquire1_thread_func;
19static thread_func acquire2_thread_func;
20
21void
22test_priority_donate_one (void)
23{
24 struct lock lock;
25
26 /* This test does not work with the MLFQS. */
27 ASSERT (!thread_mlfqs);
28
29 /* Make sure our priority is the default. */
30 ASSERT (thread_get_priority () == PRI_DEFAULT);
31
32 lock_init (&lock);
33 lock_acquire (&lock);
34 thread_create ("acquire1", PRI_DEFAULT + 1, acquire1_thread_func, &lock);
35 msg ("This thread should have priority %d. Actual priority: %d.",
36 PRI_DEFAULT + 1, thread_get_priority ());
37 thread_create ("acquire2", PRI_DEFAULT + 2, acquire2_thread_func, &lock);
38 msg ("This thread should have priority %d. Actual priority: %d.",
39 PRI_DEFAULT + 2, thread_get_priority ());
40 lock_release (&lock);
41 msg ("acquire2, acquire1 must already have finished, in that order.");
42 msg ("This should be the last line before finishing this test.");
43}
44
45static void
46acquire1_thread_func (void *lock_)
47{
48 struct lock *lock = lock_;
49
50 lock_acquire (lock);
51 msg ("acquire1: got the lock");
52 lock_release (lock);
53 msg ("acquire1: done");
54}
55
56static void
57acquire2_thread_func (void *lock_)
58{
59 struct lock *lock = lock_;
60
61 lock_acquire (lock);
62 msg ("acquire2: got the lock");
63 lock_release (lock);
64 msg ("acquire2: done");
65}
diff --git a/pintos-progos/tests/threads/priority-donate-one.ck b/pintos-progos/tests/threads/priority-donate-one.ck
new file mode 100644
index 0000000..b7c8e6f
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-one.ck
@@ -0,0 +1,17 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-one) begin
7(priority-donate-one) This thread should have priority 32. Actual priority: 32.
8(priority-donate-one) This thread should have priority 33. Actual priority: 33.
9(priority-donate-one) acquire2: got the lock
10(priority-donate-one) acquire2: done
11(priority-donate-one) acquire1: got the lock
12(priority-donate-one) acquire1: done
13(priority-donate-one) acquire2, acquire1 must already have finished, in that order.
14(priority-donate-one) This should be the last line before finishing this test.
15(priority-donate-one) end
16EOF
17pass;
diff --git a/pintos-progos/tests/threads/priority-donate-sema.c b/pintos-progos/tests/threads/priority-donate-sema.c
new file mode 100644
index 0000000..b33cb72
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-sema.c
@@ -0,0 +1,82 @@
1/* Low priority thread L acquires a lock, then blocks downing a
2 semaphore. Medium priority thread M then blocks waiting on
3 the same semaphore. Next, high priority thread H attempts to
4 acquire the lock, donating its priority to L.
5
6 Next, the main thread ups the semaphore, waking up L. L
7 releases the lock, which wakes up H. H "up"s the semaphore,
8 waking up M. H terminates, then M, then L, and finally the
9 main thread.
10
11 Written by Godmar Back <gback@cs.vt.edu>. */
12
13#include <stdio.h>
14#include "tests/threads/tests.h"
15#include "threads/init.h"
16#include "threads/synch.h"
17#include "threads/thread.h"
18
19struct lock_and_sema
20 {
21 struct lock lock;
22 struct semaphore sema;
23 };
24
25static thread_func l_thread_func;
26static thread_func m_thread_func;
27static thread_func h_thread_func;
28
29void
30test_priority_donate_sema (void)
31{
32 struct lock_and_sema ls;
33
34 /* This test does not work with the MLFQS. */
35 ASSERT (!thread_mlfqs);
36
37 /* Make sure our priority is the default. */
38 ASSERT (thread_get_priority () == PRI_DEFAULT);
39
40 lock_init (&ls.lock);
41 sema_init (&ls.sema, 0);
42 thread_create ("low", PRI_DEFAULT + 1, l_thread_func, &ls);
43 thread_create ("med", PRI_DEFAULT + 3, m_thread_func, &ls);
44 thread_create ("high", PRI_DEFAULT + 5, h_thread_func, &ls);
45 sema_up (&ls.sema);
46 msg ("Main thread finished.");
47}
48
49static void
50l_thread_func (void *ls_)
51{
52 struct lock_and_sema *ls = ls_;
53
54 lock_acquire (&ls->lock);
55 msg ("Thread L acquired lock.");
56 sema_down (&ls->sema);
57 msg ("Thread L downed semaphore.");
58 lock_release (&ls->lock);
59 msg ("Thread L finished.");
60}
61
62static void
63m_thread_func (void *ls_)
64{
65 struct lock_and_sema *ls = ls_;
66
67 sema_down (&ls->sema);
68 msg ("Thread M finished.");
69}
70
71static void
72h_thread_func (void *ls_)
73{
74 struct lock_and_sema *ls = ls_;
75
76 lock_acquire (&ls->lock);
77 msg ("Thread H acquired lock.");
78
79 sema_up (&ls->sema);
80 lock_release (&ls->lock);
81 msg ("Thread H finished.");
82}
diff --git a/pintos-progos/tests/threads/priority-donate-sema.ck b/pintos-progos/tests/threads/priority-donate-sema.ck
new file mode 100644
index 0000000..92b8d07
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-donate-sema.ck
@@ -0,0 +1,16 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-donate-sema) begin
7(priority-donate-sema) Thread L acquired lock.
8(priority-donate-sema) Thread L downed semaphore.
9(priority-donate-sema) Thread H acquired lock.
10(priority-donate-sema) Thread H finished.
11(priority-donate-sema) Thread M finished.
12(priority-donate-sema) Thread L finished.
13(priority-donate-sema) Main thread finished.
14(priority-donate-sema) end
15EOF
16pass;
diff --git a/pintos-progos/tests/threads/priority-fifo.c b/pintos-progos/tests/threads/priority-fifo.c
new file mode 100644
index 0000000..3af98a3
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-fifo.c
@@ -0,0 +1,99 @@
1/* Creates several threads all at the same priority and ensures
2 that they consistently run in the same round-robin order.
3
4 Based on a test originally submitted for Stanford's CS 140 in
5 winter 1999 by by Matt Franklin
6 <startled@leland.stanford.edu>, Greg Hutchins
7 <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
8 Modified by arens. */
9
10#include <stdio.h>
11#include "tests/threads/tests.h"
12#include "threads/init.h"
13#include "devices/timer.h"
14#include "threads/malloc.h"
15#include "threads/synch.h"
16#include "threads/thread.h"
17
18struct simple_thread_data
19 {
20 int id; /* Sleeper ID. */
21 int iterations; /* Iterations so far. */
22 struct lock *lock; /* Lock on output. */
23 int **op; /* Output buffer position. */
24 };
25
26#define THREAD_CNT 16
27#define ITER_CNT 16
28
29static thread_func simple_thread_func;
30
31void
32test_priority_fifo (void)
33{
34 struct simple_thread_data data[THREAD_CNT];
35 struct lock lock;
36 int *output, *op;
37 int i, cnt;
38
39 /* This test does not work with the MLFQS. */
40 ASSERT (!thread_mlfqs);
41
42 /* Make sure our priority is the default. */
43 ASSERT (thread_get_priority () == PRI_DEFAULT);
44
45 msg ("%d threads will iterate %d times in the same order each time.",
46 THREAD_CNT, ITER_CNT);
47 msg ("If the order varies then there is a bug.");
48
49 output = op = malloc (sizeof *output * THREAD_CNT * ITER_CNT * 2);
50 ASSERT (output != NULL);
51 lock_init (&lock);
52
53 thread_set_priority (PRI_DEFAULT + 2);
54 for (i = 0; i < THREAD_CNT; i++)
55 {
56 char name[16];
57 struct simple_thread_data *d = data + i;
58 snprintf (name, sizeof name, "%d", i);
59 d->id = i;
60 d->iterations = 0;
61 d->lock = &lock;
62 d->op = &op;
63 thread_create (name, PRI_DEFAULT + 1, simple_thread_func, d);
64 }
65
66 thread_set_priority (PRI_DEFAULT);
67 /* All the other threads now run to termination here. */
68 ASSERT (lock.holder == NULL);
69
70 cnt = 0;
71 for (; output < op; output++)
72 {
73 struct simple_thread_data *d;
74
75 ASSERT (*output >= 0 && *output < THREAD_CNT);
76 d = data + *output;
77 if (cnt % THREAD_CNT == 0)
78 printf ("(priority-fifo) iteration:");
79 printf (" %d", d->id);
80 if (++cnt % THREAD_CNT == 0)
81 printf ("\n");
82 d->iterations++;
83 }
84}
85
86static void
87simple_thread_func (void *data_)
88{
89 struct simple_thread_data *data = data_;
90 int i;
91
92 for (i = 0; i < ITER_CNT; i++)
93 {
94 lock_acquire (data->lock);
95 *(*data->op)++ = data->id;
96 lock_release (data->lock);
97 thread_yield ();
98 }
99}
diff --git a/pintos-progos/tests/threads/priority-fifo.ck b/pintos-progos/tests/threads/priority-fifo.ck
new file mode 100644
index 0000000..11f1dd3
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-fifo.ck
@@ -0,0 +1,63 @@
1# -*- perl -*-
2
3# The expected output looks like this:
4#
5# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
6# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
7# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
8# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
9# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
10# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
11# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
12# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
13# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
18# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
19# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
20# (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
21#
22# A different permutation of 0...15 is acceptable, but every line must
23# be in the same order.
24
25use strict;
26use warnings;
27use tests::tests;
28
29our ($test);
30my (@output) = read_text_file ("$test.output");
31
32common_checks ("run", @output);
33
34my ($thread_cnt) = 16;
35my ($iter_cnt) = 16;
36my (@order);
37my (@t) = (-1) x $thread_cnt;
38
39my (@iterations) = grep (/iteration:/, @output);
40fail "No iterations found in output.\n" if !@iterations;
41
42my (@numbering) = $iterations[0] =~ /(\d+)/g;
43fail "First iteration does not list exactly $thread_cnt threads.\n"
44 if @numbering != $thread_cnt;
45
46my (@sorted_numbering) = sort { $a <=> $b } @numbering;
47for my $i (0...$#sorted_numbering) {
48 if ($sorted_numbering[$i] != $i) {
49 fail "First iteration does not list all threads "
50 . "0...$#sorted_numbering\n";
51 }
52}
53
54for my $i (1...$#iterations) {
55 if ($iterations[$i] ne $iterations[0]) {
56 fail "Iteration $i differs from iteration 0\n";
57 }
58}
59
60fail "$iter_cnt iterations expected but " . scalar (@iterations) . " found\n"
61 if $iter_cnt != @iterations;
62
63pass;
diff --git a/pintos-progos/tests/threads/priority-preempt.c b/pintos-progos/tests/threads/priority-preempt.c
new file mode 100644
index 0000000..3c3aacb
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-preempt.c
@@ -0,0 +1,41 @@
1/* Ensures that a high-priority thread really preempts.
2
3 Based on a test originally submitted for Stanford's CS 140 in
4 winter 1999 by by Matt Franklin
5 <startled@leland.stanford.edu>, Greg Hutchins
6 <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
7 Modified by arens. */
8
9#include <stdio.h>
10#include "tests/threads/tests.h"
11#include "threads/init.h"
12#include "threads/synch.h"
13#include "threads/thread.h"
14
15static thread_func simple_thread_func;
16
17void
18test_priority_preempt (void)
19{
20 /* This test does not work with the MLFQS. */
21 ASSERT (!thread_mlfqs);
22
23 /* Make sure our priority is the default. */
24 ASSERT (thread_get_priority () == PRI_DEFAULT);
25
26 thread_create ("high-priority", PRI_DEFAULT + 1, simple_thread_func, NULL);
27 msg ("The high-priority thread should have already completed.");
28}
29
30static void
31simple_thread_func (void *aux UNUSED)
32{
33 int i;
34
35 for (i = 0; i < 5; i++)
36 {
37 msg ("Thread %s iteration %d", thread_name (), i);
38 thread_yield ();
39 }
40 msg ("Thread %s done!", thread_name ());
41}
diff --git a/pintos-progos/tests/threads/priority-preempt.ck b/pintos-progos/tests/threads/priority-preempt.ck
new file mode 100644
index 0000000..43a26ee
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-preempt.ck
@@ -0,0 +1,16 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-preempt) begin
7(priority-preempt) Thread high-priority iteration 0
8(priority-preempt) Thread high-priority iteration 1
9(priority-preempt) Thread high-priority iteration 2
10(priority-preempt) Thread high-priority iteration 3
11(priority-preempt) Thread high-priority iteration 4
12(priority-preempt) Thread high-priority done!
13(priority-preempt) The high-priority thread should have already completed.
14(priority-preempt) end
15EOF
16pass;
diff --git a/pintos-progos/tests/threads/priority-sema.c b/pintos-progos/tests/threads/priority-sema.c
new file mode 100644
index 0000000..2834a88
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-sema.c
@@ -0,0 +1,45 @@
1/* Tests that the highest-priority thread waiting on a semaphore
2 is the first to wake up. */
3
4#include <stdio.h>
5#include "tests/threads/tests.h"
6#include "threads/init.h"
7#include "threads/malloc.h"
8#include "threads/synch.h"
9#include "threads/thread.h"
10#include "devices/timer.h"
11
12static thread_func priority_sema_thread;
13static struct semaphore sema;
14
15void
16test_priority_sema (void)
17{
18 int i;
19
20 /* This test does not work with the MLFQS. */
21 ASSERT (!thread_mlfqs);
22
23 sema_init (&sema, 0);
24 thread_set_priority (PRI_MIN);
25 for (i = 0; i < 10; i++)
26 {
27 int priority = PRI_DEFAULT - (i + 3) % 10 - 1;
28 char name[16];
29 snprintf (name, sizeof name, "priority %d", priority);
30 thread_create (name, priority, priority_sema_thread, NULL);
31 }
32
33 for (i = 0; i < 10; i++)
34 {
35 sema_up (&sema);
36 msg ("Back in main thread.");
37 }
38}
39
40static void
41priority_sema_thread (void *aux UNUSED)
42{
43 sema_down (&sema);
44 msg ("Thread %s woke up.", thread_name ());
45}
diff --git a/pintos-progos/tests/threads/priority-sema.ck b/pintos-progos/tests/threads/priority-sema.ck
new file mode 100644
index 0000000..559988d
--- /dev/null
+++ b/pintos-progos/tests/threads/priority-sema.ck
@@ -0,0 +1,29 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected ([<<'EOF']);
6(priority-sema) begin
7(priority-sema) Thread priority 30 woke up.
8(priority-sema) Back in main thread.
9(priority-sema) Thread priority 29 woke up.
10(priority-sema) Back in main thread.
11(priority-sema) Thread priority 28 woke up.
12(priority-sema) Back in main thread.
13(priority-sema) Thread priority 27 woke up.
14(priority-sema) Back in main thread.
15(priority-sema) Thread priority 26 woke up.
16(priority-sema) Back in main thread.
17(priority-sema) Thread priority 25 woke up.
18(priority-sema) Back in main thread.
19(priority-sema) Thread priority 24 woke up.
20(priority-sema) Back in main thread.
21(priority-sema) Thread priority 23 woke up.
22(priority-sema) Back in main thread.
23(priority-sema) Thread priority 22 woke up.
24(priority-sema) Back in main thread.
25(priority-sema) Thread priority 21 woke up.
26(priority-sema) Back in main thread.
27(priority-sema) end
28EOF
29pass;
diff --git a/pintos-progos/tests/threads/tests.c b/pintos-progos/tests/threads/tests.c
new file mode 100644
index 0000000..af15aee
--- /dev/null
+++ b/pintos-progos/tests/threads/tests.c
@@ -0,0 +1,102 @@
1#include "tests/threads/tests.h"
2#include <debug.h>
3#include <string.h>
4#include <stdio.h>
5
6struct test
7 {
8 const char *name;
9 test_func *function;
10 };
11
12static const struct test tests[] =
13 {
14 {"alarm-single", test_alarm_single},
15 {"alarm-multiple", test_alarm_multiple},
16 {"alarm-simultaneous", test_alarm_simultaneous},
17 {"alarm-priority", test_alarm_priority},
18 {"alarm-zero", test_alarm_zero},
19 {"alarm-negative", test_alarm_negative},
20 {"priority-change", test_priority_change},
21 {"priority-donate-one", test_priority_donate_one},
22 {"priority-donate-multiple", test_priority_donate_multiple},
23 {"priority-donate-multiple2", test_priority_donate_multiple2},
24 {"priority-donate-nest", test_priority_donate_nest},
25 {"priority-donate-sema", test_priority_donate_sema},
26 {"priority-donate-lower", test_priority_donate_lower},
27 {"priority-donate-chain", test_priority_donate_chain},
28 {"priority-fifo", test_priority_fifo},
29 {"priority-preempt", test_priority_preempt},
30 {"priority-sema", test_priority_sema},
31 {"priority-condvar", test_priority_condvar},
32 {"mlfqs-load-1", test_mlfqs_load_1},
33 {"mlfqs-load-60", test_mlfqs_load_60},
34 {"mlfqs-load-avg", test_mlfqs_load_avg},
35 {"mlfqs-recent-1", test_mlfqs_recent_1},
36 {"mlfqs-fair-2", test_mlfqs_fair_2},
37 {"mlfqs-fair-20", test_mlfqs_fair_20},
38 {"mlfqs-nice-2", test_mlfqs_nice_2},
39 {"mlfqs-nice-10", test_mlfqs_nice_10},
40 {"mlfqs-block", test_mlfqs_block},
41 };
42
43static const char *test_name;
44
45/* Runs the test named NAME. */
46void
47run_test (const char *name)
48{
49 const struct test *t;
50
51 for (t = tests; t < tests + sizeof tests / sizeof *tests; t++)
52 if (!strcmp (name, t->name))
53 {
54 test_name = name;
55 msg ("begin");
56 t->function ();
57 msg ("end");
58 return;
59 }
60 PANIC ("no test named \"%s\"", name);
61}
62
63/* Prints FORMAT as if with printf(),
64 prefixing the output by the name of the test
65 and following it with a new-line character. */
66void
67msg (const char *format, ...)
68{
69 va_list args;
70
71 printf ("(%s) ", test_name);
72 va_start (args, format);
73 vprintf (format, args);
74 va_end (args);
75 putchar ('\n');
76}
77
78/* Prints failure message FORMAT as if with printf(),
79 prefixing the output by the name of the test and FAIL:
80 and following it with a new-line character,
81 and then panics the kernel. */
82void
83fail (const char *format, ...)
84{
85 va_list args;
86
87 printf ("(%s) FAIL: ", test_name);
88 va_start (args, format);
89 vprintf (format, args);
90 va_end (args);
91 putchar ('\n');
92
93 PANIC ("test failed");
94}
95
96/* Prints a message indicating the current test passed. */
97void
98pass (void)
99{
100 printf ("(%s) PASS\n", test_name);
101}
102
diff --git a/pintos-progos/tests/threads/tests.h b/pintos-progos/tests/threads/tests.h
new file mode 100644
index 0000000..cd9d489
--- /dev/null
+++ b/pintos-progos/tests/threads/tests.h
@@ -0,0 +1,41 @@
1#ifndef TESTS_THREADS_TESTS_H
2#define TESTS_THREADS_TESTS_H
3
4void run_test (const char *);
5
6typedef void test_func (void);
7
8extern test_func test_alarm_single;
9extern test_func test_alarm_multiple;
10extern test_func test_alarm_simultaneous;
11extern test_func test_alarm_priority;
12extern test_func test_alarm_zero;
13extern test_func test_alarm_negative;
14extern test_func test_priority_change;
15extern test_func test_priority_donate_one;
16extern test_func test_priority_donate_multiple;
17extern test_func test_priority_donate_multiple2;
18extern test_func test_priority_donate_sema;
19extern test_func test_priority_donate_nest;
20extern test_func test_priority_donate_lower;
21extern test_func test_priority_donate_chain;
22extern test_func test_priority_fifo;
23extern test_func test_priority_preempt;
24extern test_func test_priority_sema;
25extern test_func test_priority_condvar;
26extern test_func test_mlfqs_load_1;
27extern test_func test_mlfqs_load_60;
28extern test_func test_mlfqs_load_avg;
29extern test_func test_mlfqs_recent_1;
30extern test_func test_mlfqs_fair_2;
31extern test_func test_mlfqs_fair_20;
32extern test_func test_mlfqs_nice_2;
33extern test_func test_mlfqs_nice_10;
34extern test_func test_mlfqs_block;
35
36void msg (const char *, ...);
37void fail (const char *, ...);
38void pass (void);
39
40#endif /* tests/threads/tests.h */
41