This repository has been archived by the owner on Jul 10, 2020. It is now read-only.
/
alarm-wait.c
168 lines (140 loc) · 4.25 KB
/
alarm-wait.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* Creates N threads, each of which sleeps a different, fixed
duration, M times. Records the wake-up order and verifies
that it is valid. */
#include <stdio.h>
#include "tests/threads/tests.h"
#include "threads/init.h"
#include "threads/malloc.h"
#include "threads/synch.h"
#include "threads/thread.h"
#include "devices/timer.h"
static void test_sleep (int thread_cnt, int iterations);
void
test_alarm_single (void)
{
test_sleep (5, 1);
}
void
test_alarm_multiple (void)
{
test_sleep (5, 7);
}
void
test_alarm_many (void)
{
test_sleep (5, 14);
}
void
test_alarm_mega (void)
{
test_sleep (5, 70);
}
void
test_alarm_onethousand (void)
{
test_sleep (5, 100);
}
/* Information about the test. */
struct sleep_test
{
int64_t start; /* Current time at start of test. */
int iterations; /* Number of iterations per thread. */
/* Output. */
struct lock output_lock; /* Lock protecting output buffer. */
int *output_pos; /* Current position in output buffer. */
};
/* Information about an individual thread in the test. */
struct sleep_thread
{
struct sleep_test *test; /* Info shared between all threads. */
int id; /* Sleeper ID. */
int duration; /* Number of ticks to sleep. */
int iterations; /* Iterations counted so far. */
};
static void sleeper (void *);
/* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */
static void
test_sleep (int thread_cnt, int iterations)
{
struct sleep_test test;
struct sleep_thread *threads;
int *output, *op;
int product;
int i;
/* This test does not work with the MLFQS. */
ASSERT (!thread_mlfqs);
msg ("Creating %d threads to sleep %d times each.", thread_cnt, iterations);
msg ("Thread 0 sleeps 10 ticks each time,");
msg ("thread 1 sleeps 20 ticks each time, and so on.");
msg ("If successful, product of iteration count and");
msg ("sleep duration will appear in nondescending order.");
/* Allocate memory. */
threads = malloc (sizeof *threads * thread_cnt);
output = malloc (sizeof *output * iterations * thread_cnt * 2);
if (threads == NULL || output == NULL)
PANIC ("couldn't allocate memory for test");
/* Initialize test. */
test.start = timer_ticks () + 100;
test.iterations = iterations;
lock_init (&test.output_lock);
test.output_pos = output;
/* Start threads. */
ASSERT (output != NULL);
for (i = 0; i < thread_cnt; i++)
{
struct sleep_thread *t = threads + i;
char name[16];
t->test = &test;
t->id = i;
t->duration = (i + 1) * 10;
t->iterations = 0;
snprintf (name, sizeof name, "thread %d", i);
thread_create (name, PRI_DEFAULT, sleeper, t);
}
/* Wait long enough for all the threads to finish. */
timer_sleep (100 + thread_cnt * iterations * 10 + 100);
/* Acquire the output lock in case some rogue thread is still
running. */
lock_acquire (&test.output_lock);
/* Print completion order. */
product = 0;
for (op = output; op < test.output_pos; op++)
{
struct sleep_thread *t;
int new_prod;
ASSERT (*op >= 0 && *op < thread_cnt);
t = threads + *op;
new_prod = ++t->iterations * t->duration;
msg ("thread %d: duration=%d, iteration=%d, product=%d",
t->id, t->duration, t->iterations, new_prod);
if (new_prod >= product)
product = new_prod;
else
fail ("thread %d woke up out of order (%d > %d)!",
t->id, product, new_prod);
}
/* Verify that we had the proper number of wakeups. */
for (i = 0; i < thread_cnt; i++)
if (threads[i].iterations != iterations)
fail ("thread %d woke up %d times instead of %d",
i, threads[i].iterations, iterations);
lock_release (&test.output_lock);
free (output);
free (threads);
}
/* Sleeper thread. */
static void
sleeper (void *t_)
{
struct sleep_thread *t = t_;
struct sleep_test *test = t->test;
int i;
for (i = 1; i <= test->iterations; i++)
{
int64_t sleep_until = test->start + i * t->duration;
timer_sleep (sleep_until - timer_ticks ());
lock_acquire (&test->output_lock);
*test->output_pos++ = t->id;
lock_release (&test->output_lock);
}
}