summaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/bitmap.c371
-rw-r--r--lib/kernel/bitmap.h51
-rw-r--r--lib/kernel/console.c191
-rw-r--r--lib/kernel/console.h8
-rw-r--r--lib/kernel/debug.c123
-rw-r--r--lib/kernel/hash.c430
-rw-r--r--lib/kernel/hash.h103
-rw-r--r--lib/kernel/list.c524
-rw-r--r--lib/kernel/list.h181
-rw-r--r--lib/kernel/stdio.h6
10 files changed, 1988 insertions, 0 deletions
diff --git a/lib/kernel/bitmap.c b/lib/kernel/bitmap.c
new file mode 100644
index 0000000..d14a98c
--- /dev/null
+++ b/lib/kernel/bitmap.c
@@ -0,0 +1,371 @@
1#include "bitmap.h"
2#include <debug.h>
3#include <limits.h>
4#include <round.h>
5#include <stdio.h>
6#include "threads/malloc.h"
7#ifdef FILESYS
8#include "filesys/file.h"
9#endif
10
11/* Element type.
12
13 This must be an unsigned integer type at least as wide as int.
14
15 Each bit represents one bit in the bitmap.
16 If bit 0 in an element represents bit K in the bitmap,
17 then bit 1 in the element represents bit K+1 in the bitmap,
18 and so on. */
19typedef unsigned long elem_type;
20
21/* Number of bits in an element. */
22#define ELEM_BITS (sizeof (elem_type) * CHAR_BIT)
23
24/* From the outside, a bitmap is an array of bits. From the
25 inside, it's an array of elem_type (defined above) that
26 simulates an array of bits. */
27struct bitmap
28 {
29 size_t bit_cnt; /* Number of bits. */
30 elem_type *bits; /* Elements that represent bits. */
31 };
32
33/* Returns the index of the element that contains the bit
34 numbered BIT_IDX. */
35static inline size_t
36elem_idx (size_t bit_idx)
37{
38 return bit_idx / ELEM_BITS;
39}
40
41/* Returns an elem_type where only the bit corresponding to
42 BIT_IDX is turned on. */
43static inline elem_type
44bit_mask (size_t bit_idx)
45{
46 return (elem_type) 1 << (bit_idx % ELEM_BITS);
47}
48
49/* Returns the number of elements required for BIT_CNT bits. */
50static inline size_t
51elem_cnt (size_t bit_cnt)
52{
53 return DIV_ROUND_UP (bit_cnt, ELEM_BITS);
54}
55
56/* Returns the number of bytes required for BIT_CNT bits. */
57static inline size_t
58byte_cnt (size_t bit_cnt)
59{
60 return sizeof (elem_type) * elem_cnt (bit_cnt);
61}
62
63/* Returns a bit mask in which the bits actually used in the last
64 element of B's bits are set to 1 and the rest are set to 0. */
65static inline elem_type
66last_mask (const struct bitmap *b)
67{
68 int last_bits = b->bit_cnt % ELEM_BITS;
69 return last_bits ? ((elem_type) 1 << last_bits) - 1 : (elem_type) -1;
70}
71
72/* Creation and destruction. */
73
74/* Creates and returns a pointer to a newly allocated bitmap with room for
75 BIT_CNT (or more) bits. Returns a null pointer if memory allocation fails.
76 The caller is responsible for freeing the bitmap, with bitmap_destroy(),
77 when it is no longer needed. */
78struct bitmap *
79bitmap_create (size_t bit_cnt)
80{
81 struct bitmap *b = malloc (sizeof *b);
82 if (b != NULL)
83 {
84 b->bit_cnt = bit_cnt;
85 b->bits = malloc (byte_cnt (bit_cnt));
86 if (b->bits != NULL || bit_cnt == 0)
87 {
88 bitmap_set_all (b, false);
89 return b;
90 }
91 free (b);
92 }
93 return NULL;
94}
95
96/* Creates and returns a bitmap with BIT_CNT bits in the
97 BLOCK_SIZE bytes of storage preallocated at BLOCK.
98 BLOCK_SIZE must be at least bitmap_needed_bytes(BIT_CNT). */
99struct bitmap *
100bitmap_create_in_buf (size_t bit_cnt, void *block, size_t block_size UNUSED)
101{
102 struct bitmap *b = block;
103
104 ASSERT (block_size >= bitmap_buf_size (bit_cnt));
105
106 b->bit_cnt = bit_cnt;
107 b->bits = (elem_type *) (b + 1);
108 bitmap_set_all (b, false);
109 return b;
110}
111
112/* Returns the number of bytes required to accomodate a bitmap
113 with BIT_CNT bits (for use with bitmap_create_in_buf()). */
114size_t
115bitmap_buf_size (size_t bit_cnt)
116{
117 return sizeof (struct bitmap) + byte_cnt (bit_cnt);
118}
119
120/* Destroys bitmap B, freeing its storage.
121 Not for use on bitmaps created by bitmap_create_in_buf(). */
122void
123bitmap_destroy (struct bitmap *b)
124{
125 if (b != NULL)
126 {
127 free (b->bits);
128 free (b);
129 }
130}
131
132/* Bitmap size. */
133
134/* Returns the number of bits in B. */
135size_t
136bitmap_size (const struct bitmap *b)
137{
138 return b->bit_cnt;
139}
140
141/* Setting and testing single bits. */
142
143/* Atomically sets the bit numbered IDX in B to VALUE. */
144void
145bitmap_set (struct bitmap *b, size_t idx, bool value)
146{
147 ASSERT (b != NULL);
148 ASSERT (idx < b->bit_cnt);
149 if (value)
150 bitmap_mark (b, idx);
151 else
152 bitmap_reset (b, idx);
153}
154
155/* Atomically sets the bit numbered BIT_IDX in B to true. */
156void
157bitmap_mark (struct bitmap *b, size_t bit_idx)
158{
159 size_t idx = elem_idx (bit_idx);
160 elem_type mask = bit_mask (bit_idx);
161
162 /* This is equivalent to `b->bits[idx] |= mask' except that it
163 is guaranteed to be atomic on a uniprocessor machine. See
164 the description of the OR instruction in [IA32-v2b]. */
165 asm ("orl %1, %0" : "=m" (b->bits[idx]) : "r" (mask) : "cc");
166}
167
168/* Atomically sets the bit numbered BIT_IDX in B to false. */
169void
170bitmap_reset (struct bitmap *b, size_t bit_idx)
171{
172 size_t idx = elem_idx (bit_idx);
173 elem_type mask = bit_mask (bit_idx);
174
175 /* This is equivalent to `b->bits[idx] &= ~mask' except that it
176 is guaranteed to be atomic on a uniprocessor machine. See
177 the description of the AND instruction in [IA32-v2a]. */
178 asm ("andl %1, %0" : "=m" (b->bits[idx]) : "r" (~mask) : "cc");
179}
180
181/* Atomically toggles the bit numbered IDX in B;
182 that is, if it is true, makes it false,
183 and if it is false, makes it true. */
184void
185bitmap_flip (struct bitmap *b, size_t bit_idx)
186{
187 size_t idx = elem_idx (bit_idx);
188 elem_type mask = bit_mask (bit_idx);
189
190 /* This is equivalent to `b->bits[idx] ^= mask' except that it
191 is guaranteed to be atomic on a uniprocessor machine. See
192 the description of the XOR instruction in [IA32-v2b]. */
193 asm ("xorl %1, %0" : "=m" (b->bits[idx]) : "r" (mask) : "cc");
194}
195
196/* Returns the value of the bit numbered IDX in B. */
197bool
198bitmap_test (const struct bitmap *b, size_t idx)
199{
200 ASSERT (b != NULL);
201 ASSERT (idx < b->bit_cnt);
202 return (b->bits[elem_idx (idx)] & bit_mask (idx)) != 0;
203}
204
205/* Setting and testing multiple bits. */
206
207/* Sets all bits in B to VALUE. */
208void
209bitmap_set_all (struct bitmap *b, bool value)
210{
211 ASSERT (b != NULL);
212
213 bitmap_set_multiple (b, 0, bitmap_size (b), value);
214}
215
216/* Sets the CNT bits starting at START in B to VALUE. */
217void
218bitmap_set_multiple (struct bitmap *b, size_t start, size_t cnt, bool value)
219{
220 size_t i;
221
222 ASSERT (b != NULL);
223 ASSERT (start <= b->bit_cnt);
224 ASSERT (start + cnt <= b->bit_cnt);
225
226 for (i = 0; i < cnt; i++)
227 bitmap_set (b, start + i, value);
228}
229
230/* Returns the number of bits in B between START and START + CNT,
231 exclusive, that are set to VALUE. */
232size_t
233bitmap_count (const struct bitmap *b, size_t start, size_t cnt, bool value)
234{
235 size_t i, value_cnt;
236
237 ASSERT (b != NULL);
238 ASSERT (start <= b->bit_cnt);
239 ASSERT (start + cnt <= b->bit_cnt);
240
241 value_cnt = 0;
242 for (i = 0; i < cnt; i++)
243 if (bitmap_test (b, start + i) == value)
244 value_cnt++;
245 return value_cnt;
246}
247
248/* Returns true if any bits in B between START and START + CNT,
249 exclusive, are set to VALUE, and false otherwise. */
250bool
251bitmap_contains (const struct bitmap *b, size_t start, size_t cnt, bool value)
252{
253 size_t i;
254
255 ASSERT (b != NULL);
256 ASSERT (start <= b->bit_cnt);
257 ASSERT (start + cnt <= b->bit_cnt);
258
259 for (i = 0; i < cnt; i++)
260 if (bitmap_test (b, start + i) == value)
261 return true;
262 return false;
263}
264
265/* Returns true if any bits in B between START and START + CNT,
266 exclusive, are set to true, and false otherwise.*/
267bool
268bitmap_any (const struct bitmap *b, size_t start, size_t cnt)
269{
270 return bitmap_contains (b, start, cnt, true);
271}
272
273/* Returns true if no bits in B between START and START + CNT,
274 exclusive, are set to true, and false otherwise.*/
275bool
276bitmap_none (const struct bitmap *b, size_t start, size_t cnt)
277{
278 return !bitmap_contains (b, start, cnt, true);
279}
280
281/* Returns true if every bit in B between START and START + CNT,
282 exclusive, is set to true, and false otherwise. */
283bool
284bitmap_all (const struct bitmap *b, size_t start, size_t cnt)
285{
286 return !bitmap_contains (b, start, cnt, false);
287}
288
289/* Finding set or unset bits. */
290
291/* Finds and returns the starting index of the first group of CNT
292 consecutive bits in B at or after START that are all set to
293 VALUE.
294 If there is no such group, returns BITMAP_ERROR. */
295size_t
296bitmap_scan (const struct bitmap *b, size_t start, size_t cnt, bool value)
297{
298 ASSERT (b != NULL);
299 ASSERT (start <= b->bit_cnt);
300
301 if (cnt <= b->bit_cnt)
302 {
303 size_t last = b->bit_cnt - cnt;
304 size_t i;
305 for (i = start; i <= last; i++)
306 if (!bitmap_contains (b, i, cnt, !value))
307 return i;
308 }
309 return BITMAP_ERROR;
310}
311
312/* Finds the first group of CNT consecutive bits in B at or after
313 START that are all set to VALUE, flips them all to !VALUE,
314 and returns the index of the first bit in the group.
315 If there is no such group, returns BITMAP_ERROR.
316 If CNT is zero, returns 0.
317 Bits are set atomically, but testing bits is not atomic with
318 setting them. */
319size_t
320bitmap_scan_and_flip (struct bitmap *b, size_t start, size_t cnt, bool value)
321{
322 size_t idx = bitmap_scan (b, start, cnt, value);
323 if (idx != BITMAP_ERROR)
324 bitmap_set_multiple (b, idx, cnt, !value);
325 return idx;
326}
327
328/* File input and output. */
329
330#ifdef FILESYS
331/* Returns the number of bytes needed to store B in a file. */
332size_t
333bitmap_file_size (const struct bitmap *b)
334{
335 return byte_cnt (b->bit_cnt);
336}
337
338/* Reads B from FILE. Returns true if successful, false
339 otherwise. */
340bool
341bitmap_read (struct bitmap *b, struct file *file)
342{
343 bool success = true;
344 if (b->bit_cnt > 0)
345 {
346 off_t size = byte_cnt (b->bit_cnt);
347 success = file_read_at (file, b->bits, size, 0) == size;
348 b->bits[elem_cnt (b->bit_cnt) - 1] &= last_mask (b);
349 }
350 return success;
351}
352
353/* Writes B to FILE. Return true if successful, false
354 otherwise. */
355bool
356bitmap_write (const struct bitmap *b, struct file *file)
357{
358 off_t size = byte_cnt (b->bit_cnt);
359 return file_write_at (file, b->bits, size, 0) == size;
360}
361#endif /* FILESYS */
362
363/* Debugging. */
364
365/* Dumps the contents of B to the console as hexadecimal. */
366void
367bitmap_dump (const struct bitmap *b)
368{
369 hex_dump (0, b->bits, byte_cnt (b->bit_cnt), false);
370}
371
diff --git a/lib/kernel/bitmap.h b/lib/kernel/bitmap.h
new file mode 100644
index 0000000..a50593c
--- /dev/null
+++ b/lib/kernel/bitmap.h
@@ -0,0 +1,51 @@
1#ifndef __LIB_KERNEL_BITMAP_H
2#define __LIB_KERNEL_BITMAP_H
3
4#include <stdbool.h>
5#include <stddef.h>
6#include <inttypes.h>
7
8/* Bitmap abstract data type. */
9
10/* Creation and destruction. */
11struct bitmap *bitmap_create (size_t bit_cnt);
12struct bitmap *bitmap_create_in_buf (size_t bit_cnt, void *, size_t byte_cnt);
13size_t bitmap_buf_size (size_t bit_cnt);
14void bitmap_destroy (struct bitmap *);
15
16/* Bitmap size. */
17size_t bitmap_size (const struct bitmap *);
18
19/* Setting and testing single bits. */
20void bitmap_set (struct bitmap *, size_t idx, bool);
21void bitmap_mark (struct bitmap *, size_t idx);
22void bitmap_reset (struct bitmap *, size_t idx);
23void bitmap_flip (struct bitmap *, size_t idx);
24bool bitmap_test (const struct bitmap *, size_t idx);
25
26/* Setting and testing multiple bits. */
27void bitmap_set_all (struct bitmap *, bool);
28void bitmap_set_multiple (struct bitmap *, size_t start, size_t cnt, bool);
29size_t bitmap_count (const struct bitmap *, size_t start, size_t cnt, bool);
30bool bitmap_contains (const struct bitmap *, size_t start, size_t cnt, bool);
31bool bitmap_any (const struct bitmap *, size_t start, size_t cnt);
32bool bitmap_none (const struct bitmap *, size_t start, size_t cnt);
33bool bitmap_all (const struct bitmap *, size_t start, size_t cnt);
34
35/* Finding set or unset bits. */
36#define BITMAP_ERROR SIZE_MAX
37size_t bitmap_scan (const struct bitmap *, size_t start, size_t cnt, bool);
38size_t bitmap_scan_and_flip (struct bitmap *, size_t start, size_t cnt, bool);
39
40/* File input and output. */
41#ifdef FILESYS
42struct file;
43size_t bitmap_file_size (const struct bitmap *);
44bool bitmap_read (struct bitmap *, struct file *);
45bool bitmap_write (const struct bitmap *, struct file *);
46#endif
47
48/* Debugging. */
49void bitmap_dump (const struct bitmap *);
50
51#endif /* lib/kernel/bitmap.h */
diff --git a/lib/kernel/console.c b/lib/kernel/console.c
new file mode 100644
index 0000000..844b184
--- /dev/null
+++ b/lib/kernel/console.c
@@ -0,0 +1,191 @@
1#include <console.h>
2#include <stdarg.h>
3#include <stdio.h>
4#include "devices/serial.h"
5#include "devices/vga.h"
6#include "threads/init.h"
7#include "threads/interrupt.h"
8#include "threads/synch.h"
9
10static void vprintf_helper (char, void *);
11static void putchar_have_lock (uint8_t c);
12
13/* The console lock.
14 Both the vga and serial layers do their own locking, so it's
15 safe to call them at any time.
16 But this lock is useful to prevent simultaneous printf() calls
17 from mixing their output, which looks confusing. */
18static struct lock console_lock;
19
20/* True in ordinary circumstances: we want to use the console
21 lock to avoid mixing output between threads, as explained
22 above.
23
24 False in early boot before the point that locks are functional
25 or the console lock has been initialized, or after a kernel
26 panics. In the former case, taking the lock would cause an
27 assertion failure, which in turn would cause a panic, turning
28 it into the latter case. In the latter case, if it is a buggy
29 lock_acquire() implementation that caused the panic, we'll
30 likely just recurse. */
31static bool use_console_lock;
32
33/* It's possible, if you add enough debug output to Pintos, to
34 try to recursively grab console_lock from a single thread. As
35 a real example, I added a printf() call to palloc_free().
36 Here's a real backtrace that resulted:
37
38 lock_console()
39 vprintf()
40 printf() - palloc() tries to grab the lock again
41 palloc_free()
42 thread_schedule_tail() - another thread dying as we switch threads
43 schedule()
44 thread_yield()
45 intr_handler() - timer interrupt
46 intr_set_level()
47 serial_putc()
48 putchar_have_lock()
49 putbuf()
50 sys_write() - one process writing to the console
51 syscall_handler()
52 intr_handler()
53
54 This kind of thing is very difficult to debug, so we avoid the
55 problem by simulating a recursive lock with a depth
56 counter. */
57static int console_lock_depth;
58
59/* Number of characters written to console. */
60static int64_t write_cnt;
61
62/* Enable console locking. */
63void
64console_init (void)
65{
66 lock_init (&console_lock);
67 use_console_lock = true;
68}
69
70/* Notifies the console that a kernel panic is underway,
71 which warns it to avoid trying to take the console lock from
72 now on. */
73void
74console_panic (void)
75{
76 use_console_lock = false;
77}
78
79/* Prints console statistics. */
80void
81console_print_stats (void)
82{
83 printf ("Console: %lld characters output\n", write_cnt);
84}
85
86/* Acquires the console lock. */
87static void
88acquire_console (void)
89{
90 if (!intr_context () && use_console_lock)
91 {
92 if (lock_held_by_current_thread (&console_lock))
93 console_lock_depth++;
94 else
95 lock_acquire (&console_lock);
96 }
97}
98
99/* Releases the console lock. */
100static void
101release_console (void)
102{
103 if (!intr_context () && use_console_lock)
104 {
105 if (console_lock_depth > 0)
106 console_lock_depth--;
107 else
108 lock_release (&console_lock);
109 }
110}
111
112/* Returns true if the current thread has the console lock,
113 false otherwise. */
114static bool
115console_locked_by_current_thread (void)
116{
117 return (intr_context ()
118 || !use_console_lock
119 || lock_held_by_current_thread (&console_lock));
120}
121
122/* The standard vprintf() function,
123 which is like printf() but uses a va_list.
124 Writes its output to both vga display and serial port. */
125int
126vprintf (const char *format, va_list args)
127{
128 int char_cnt = 0;
129
130 acquire_console ();
131 __vprintf (format, args, vprintf_helper, &char_cnt);
132 release_console ();
133
134 return char_cnt;
135}
136
137/* Writes string S to the console, followed by a new-line
138 character. */
139int
140puts (const char *s)
141{
142 acquire_console ();
143 while (*s != '\0')
144 putchar_have_lock (*s++);
145 putchar_have_lock ('\n');
146 release_console ();
147
148 return 0;
149}
150
151/* Writes the N characters in BUFFER to the console. */
152void
153putbuf (const char *buffer, size_t n)
154{
155 acquire_console ();
156 while (n-- > 0)
157 putchar_have_lock (*buffer++);
158 release_console ();
159}
160
161/* Writes C to the vga display and serial port. */
162int
163putchar (int c)
164{
165 acquire_console ();
166 putchar_have_lock (c);
167 release_console ();
168
169 return c;
170}
171
172/* Helper function for vprintf(). */
173static void
174vprintf_helper (char c, void *char_cnt_)
175{
176 int *char_cnt = char_cnt_;
177 (*char_cnt)++;
178 putchar_have_lock (c);
179}
180
181/* Writes C to the vga display and serial port.
182 The caller has already acquired the console lock if
183 appropriate. */
184static void
185putchar_have_lock (uint8_t c)
186{
187 ASSERT (console_locked_by_current_thread ());
188 write_cnt++;
189 serial_putc (c);
190 vga_putc (c);
191}
diff --git a/lib/kernel/console.h b/lib/kernel/console.h
new file mode 100644
index 0000000..ab99249
--- /dev/null
+++ b/lib/kernel/console.h
@@ -0,0 +1,8 @@
1#ifndef __LIB_KERNEL_CONSOLE_H
2#define __LIB_KERNEL_CONSOLE_H
3
4void console_init (void);
5void console_panic (void);
6void console_print_stats (void);
7
8#endif /* lib/kernel/console.h */
diff --git a/lib/kernel/debug.c b/lib/kernel/debug.c
new file mode 100644
index 0000000..b12f4f9
--- /dev/null
+++ b/lib/kernel/debug.c
@@ -0,0 +1,123 @@
1#include <debug.h>
2#include <console.h>
3#include <stdarg.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdio.h>
7#include <string.h>
8#include "threads/init.h"
9#include "threads/interrupt.h"
10#include "threads/thread.h"
11#include "threads/switch.h"
12#include "threads/vaddr.h"
13#include "devices/serial.h"
14#include "devices/shutdown.h"
15
16/* Halts the OS, printing the source file name, line number, and
17 function name, plus a user-specific message. */
18void
19debug_panic (const char *file, int line, const char *function,
20 const char *message, ...)
21{
22 static int level;
23 va_list args;
24
25 intr_disable ();
26 console_panic ();
27
28 level++;
29 if (level == 1)
30 {
31 printf ("Kernel PANIC at %s:%d in %s(): ", file, line, function);
32
33 va_start (args, message);
34 vprintf (message, args);
35 printf ("\n");
36 va_end (args);
37
38 debug_backtrace ();
39 }
40 else if (level == 2)
41 printf ("Kernel PANIC recursion at %s:%d in %s().\n",
42 file, line, function);
43 else
44 {
45 /* Don't print anything: that's probably why we recursed. */
46 }
47
48 serial_flush ();
49 shutdown ();
50 for (;;);
51}
52
53/* Print call stack of a thread.
54 The thread may be running, ready, or blocked. */
55static void
56print_stacktrace(struct thread *t, void *aux UNUSED)
57{
58 void *retaddr = NULL, **frame = NULL;
59 const char *status = "UNKNOWN";
60
61 switch (t->status) {
62 case THREAD_RUNNING:
63 status = "RUNNING";
64 break;
65
66 case THREAD_READY:
67 status = "READY";
68 break;
69
70 case THREAD_BLOCKED:
71 status = "BLOCKED";
72 break;
73
74 default:
75 break;
76 }
77
78 printf ("Call stack of thread `%s' (status %s):", t->name, status);
79
80 if (t == thread_current())
81 {
82 frame = __builtin_frame_address (1);
83 retaddr = __builtin_return_address (0);
84 }
85 else
86 {
87 /* Retrieve the values of the base and instruction pointers
88 as they were saved when this thread called switch_threads. */
89 struct switch_threads_frame * saved_frame;
90
91 saved_frame = (struct switch_threads_frame *)t->stack;
92
93 /* Skip threads if they have been added to the all threads
94 list, but have never been scheduled.
95 We can identify because their `stack' member either points
96 at the top of their kernel stack page, or the
97 switch_threads_frame's 'eip' member points at switch_entry.
98 See also threads.c. */
99 if (t->stack == (uint8_t *)t + PGSIZE || saved_frame->eip == switch_entry)
100 {
101 printf (" thread was never scheduled.\n");
102 return;
103 }
104
105 frame = (void **) saved_frame->ebp;
106 retaddr = (void *) saved_frame->eip;
107 }
108
109 printf (" %p", retaddr);
110 for (; (uintptr_t) frame >= 0x1000 && frame[0] != NULL; frame = frame[0])
111 printf (" %p", frame[1]);
112 printf (".\n");
113}
114
115/* Prints call stack of all threads. */
116void
117debug_backtrace_all (void)
118{
119 enum intr_level oldlevel = intr_disable ();
120
121 thread_foreach (print_stacktrace, 0);
122 intr_set_level (oldlevel);
123}
diff --git a/lib/kernel/hash.c b/lib/kernel/hash.c
new file mode 100644
index 0000000..57eed45
--- /dev/null
+++ b/lib/kernel/hash.c
@@ -0,0 +1,430 @@
1/* Hash table.
2
3 This data structure is thoroughly documented in the Tour of
4 Pintos for Project 3.
5
6 See hash.h for basic information. */
7
8#include "hash.h"
9#include "../debug.h"
10#include "threads/malloc.h"
11
12#define list_elem_to_hash_elem(LIST_ELEM) \
13 list_entry(LIST_ELEM, struct hash_elem, list_elem)
14
15static struct list *find_bucket (struct hash *, struct hash_elem *);
16static struct hash_elem *find_elem (struct hash *, struct list *,
17 struct hash_elem *);
18static void insert_elem (struct hash *, struct list *, struct hash_elem *);
19static void remove_elem (struct hash *, struct hash_elem *);
20static void rehash (struct hash *);
21
22/* Initializes hash table H to compute hash values using HASH and
23 compare hash elements using LESS, given auxiliary data AUX. */
24bool
25hash_init (struct hash *h,
26 hash_hash_func *hash, hash_less_func *less, void *aux)
27{
28 h->elem_cnt = 0;
29 h->bucket_cnt = 4;
30 h->buckets = malloc (sizeof *h->buckets * h->bucket_cnt);
31 h->hash = hash;
32 h->less = less;
33 h->aux = aux;
34
35 if (h->buckets != NULL)
36 {
37 hash_clear (h, NULL);
38 return true;
39 }
40 else
41 return false;
42}
43
44/* Removes all the elements from H.
45
46 If DESTRUCTOR is non-null, then it is called for each element
47 in the hash. DESTRUCTOR may, if appropriate, deallocate the
48 memory used by the hash element. However, modifying hash
49 table H while hash_clear() is running, using any of the
50 functions hash_clear(), hash_destroy(), hash_insert(),
51 hash_replace(), or hash_delete(), yields undefined behavior,
52 whether done in DESTRUCTOR or elsewhere. */
53void
54hash_clear (struct hash *h, hash_action_func *destructor)
55{
56 size_t i;
57
58 for (i = 0; i < h->bucket_cnt; i++)
59 {
60 struct list *bucket = &h->buckets[i];
61
62 if (destructor != NULL)
63 while (!list_empty (bucket))
64 {
65 struct list_elem *list_elem = list_pop_front (bucket);
66 struct hash_elem *hash_elem = list_elem_to_hash_elem (list_elem);
67 destructor (hash_elem, h->aux);
68 }
69
70 list_init (bucket);
71 }
72
73 h->elem_cnt = 0;
74}
75
76/* Destroys hash table H.
77
78 If DESTRUCTOR is non-null, then it is first called for each
79 element in the hash. DESTRUCTOR may, if appropriate,
80 deallocate the memory used by the hash element. However,
81 modifying hash table H while hash_clear() is running, using
82 any of the functions hash_clear(), hash_destroy(),
83 hash_insert(), hash_replace(), or hash_delete(), yields
84 undefined behavior, whether done in DESTRUCTOR or
85 elsewhere. */
86void
87hash_destroy (struct hash *h, hash_action_func *destructor)
88{
89 if (destructor != NULL)
90 hash_clear (h, destructor);
91 free (h->buckets);
92}
93
94/* Inserts NEW into hash table H and returns a null pointer, if
95 no equal element is already in the table.
96 If an equal element is already in the table, returns it
97 without inserting NEW. */
98struct hash_elem *
99hash_insert (struct hash *h, struct hash_elem *new)
100{
101 struct list *bucket = find_bucket (h, new);
102 struct hash_elem *old = find_elem (h, bucket, new);
103
104 if (old == NULL)
105 insert_elem (h, bucket, new);
106
107 rehash (h);
108
109 return old;
110}
111
112/* Inserts NEW into hash table H, replacing any equal element
113 already in the table, which is returned. */
114struct hash_elem *
115hash_replace (struct hash *h, struct hash_elem *new)
116{
117 struct list *bucket = find_bucket (h, new);
118 struct hash_elem *old = find_elem (h, bucket, new);
119
120 if (old != NULL)
121 remove_elem (h, old);
122 insert_elem (h, bucket, new);
123
124 rehash (h);
125
126 return old;
127}
128
129/* Finds and returns an element equal to E in hash table H, or a
130 null pointer if no equal element exists in the table. */
131struct hash_elem *
132hash_find (struct hash *h, struct hash_elem *e)
133{
134 return find_elem (h, find_bucket (h, e), e);
135}
136
137/* Finds, removes, and returns an element equal to E in hash
138 table H. Returns a null pointer if no equal element existed
139 in the table.
140
141 If the elements of the hash table are dynamically allocated,
142 or own resources that are, then it is the caller's
143 responsibility to deallocate them. */
144struct hash_elem *
145hash_delete (struct hash *h, struct hash_elem *e)
146{
147 struct hash_elem *found = find_elem (h, find_bucket (h, e), e);
148 if (found != NULL)
149 {
150 remove_elem (h, found);
151 rehash (h);
152 }
153 return found;
154}
155
156/* Calls ACTION for each element in hash table H in arbitrary
157 order.
158 Modifying hash table H while hash_apply() is running, using
159 any of the functions hash_clear(), hash_destroy(),
160 hash_insert(), hash_replace(), or hash_delete(), yields
161 undefined behavior, whether done from ACTION or elsewhere. */
162void
163hash_apply (struct hash *h, hash_action_func *action)
164{
165 size_t i;
166
167 ASSERT (action != NULL);
168
169 for (i = 0; i < h->bucket_cnt; i++)
170 {
171 struct list *bucket = &h->buckets[i];
172 struct list_elem *elem, *next;
173
174 for (elem = list_begin (bucket); elem != list_end (bucket); elem = next)
175 {
176 next = list_next (elem);
177 action (list_elem_to_hash_elem (elem), h->aux);
178 }
179 }
180}
181
182/* Initializes I for iterating hash table H.
183
184 Iteration idiom:
185
186 struct hash_iterator i;
187
188 hash_first (&i, h);
189 while (hash_next (&i))
190 {
191 struct foo *f = hash_entry (hash_cur (&i), struct foo, elem);
192 ...do something with f...
193 }
194
195 Modifying hash table H during iteration, using any of the
196 functions hash_clear(), hash_destroy(), hash_insert(),
197 hash_replace(), or hash_delete(), invalidates all
198 iterators. */
199void
200hash_first (struct hash_iterator *i, struct hash *h)
201{
202 ASSERT (i != NULL);
203 ASSERT (h != NULL);
204
205 i->hash = h;
206 i->bucket = i->hash->buckets;
207 i->elem = list_elem_to_hash_elem (list_head (i->bucket));
208}
209
210/* Advances I to the next element in the hash table and returns
211 it. Returns a null pointer if no elements are left. Elements
212 are returned in arbitrary order.
213
214 Modifying a hash table H during iteration, using any of the
215 functions hash_clear(), hash_destroy(), hash_insert(),
216 hash_replace(), or hash_delete(), invalidates all
217 iterators. */
218struct hash_elem *
219hash_next (struct hash_iterator *i)
220{
221 ASSERT (i != NULL);
222
223 i->elem = list_elem_to_hash_elem (list_next (&i->elem->list_elem));
224 while (i->elem == list_elem_to_hash_elem (list_end (i->bucket)))
225 {
226 if (++i->bucket >= i->hash->buckets + i->hash->bucket_cnt)
227 {
228 i->elem = NULL;
229 break;
230 }
231 i->elem = list_elem_to_hash_elem (list_begin (i->bucket));
232 }
233
234 return i->elem;
235}
236
237/* Returns the current element in the hash table iteration, or a
238 null pointer at the end of the table. Undefined behavior
239 after calling hash_first() but before hash_next(). */
240struct hash_elem *
241hash_cur (struct hash_iterator *i)
242{
243 return i->elem;
244}
245
246/* Returns the number of elements in H. */
247size_t
248hash_size (struct hash *h)
249{
250 return h->elem_cnt;
251}
252
253/* Returns true if H contains no elements, false otherwise. */
254bool
255hash_empty (struct hash *h)
256{
257 return h->elem_cnt == 0;
258}
259
260/* Fowler-Noll-Vo hash constants, for 32-bit word sizes. */
261#define FNV_32_PRIME 16777619u
262#define FNV_32_BASIS 2166136261u
263
264/* Returns a hash of the SIZE bytes in BUF. */
265unsigned
266hash_bytes (const void *buf_, size_t size)
267{
268 /* Fowler-Noll-Vo 32-bit hash, for bytes. */
269 const unsigned char *buf = buf_;
270 unsigned hash;
271
272 ASSERT (buf != NULL);
273
274 hash = FNV_32_BASIS;
275 while (size-- > 0)
276 hash = (hash * FNV_32_PRIME) ^ *buf++;
277
278 return hash;
279}
280
281/* Returns a hash of string S. */
282unsigned
283hash_string (const char *s_)
284{
285 const unsigned char *s = (const unsigned char *) s_;
286 unsigned hash;
287
288 ASSERT (s != NULL);
289
290 hash = FNV_32_BASIS;
291 while (*s != '\0')
292 hash = (hash * FNV_32_PRIME) ^ *s++;
293
294 return hash;
295}
296
297/* Returns a hash of integer I. */
298unsigned
299hash_int (int i)
300{
301 return hash_bytes (&i, sizeof i);
302}
303
304/* Returns the bucket in H that E belongs in. */
305static struct list *
306find_bucket (struct hash *h, struct hash_elem *e)
307{
308 size_t bucket_idx = h->hash (e, h->aux) & (h->bucket_cnt - 1);
309 return &h->buckets[bucket_idx];
310}
311
312/* Searches BUCKET in H for a hash element equal to E. Returns
313 it if found or a null pointer otherwise. */
314static struct hash_elem *
315find_elem (struct hash *h, struct list *bucket, struct hash_elem *e)
316{
317 struct list_elem *i;
318
319 for (i = list_begin (bucket); i != list_end (bucket); i = list_next (i))
320 {
321 struct hash_elem *hi = list_elem_to_hash_elem (i);
322 if (!h->less (hi, e, h->aux) && !h->less (e, hi, h->aux))
323 return hi;
324 }
325 return NULL;
326}
327
328/* Returns X with its lowest-order bit set to 1 turned off. */
329static inline size_t
330turn_off_least_1bit (size_t x)
331{
332 return x & (x - 1);
333}
334
335/* Returns true if X is a power of 2, otherwise false. */
336static inline size_t
337is_power_of_2 (size_t x)
338{
339 return x != 0 && turn_off_least_1bit (x) == 0;
340}
341
342/* Element per bucket ratios. */
343#define MIN_ELEMS_PER_BUCKET 1 /* Elems/bucket < 1: reduce # of buckets. */
344#define BEST_ELEMS_PER_BUCKET 2 /* Ideal elems/bucket. */
345#define MAX_ELEMS_PER_BUCKET 4 /* Elems/bucket > 4: increase # of buckets. */
346
347/* Changes the number of buckets in hash table H to match the
348 ideal. This function can fail because of an out-of-memory
349 condition, but that'll just make hash accesses less efficient;
350 we can still continue. */
351static void
352rehash (struct hash *h)
353{
354 size_t old_bucket_cnt, new_bucket_cnt;
355 struct list *new_buckets, *old_buckets;
356 size_t i;
357
358 ASSERT (h != NULL);
359
360 /* Save old bucket info for later use. */
361 old_buckets = h->buckets;
362 old_bucket_cnt = h->bucket_cnt;
363
364 /* Calculate the number of buckets to use now.
365 We want one bucket for about every BEST_ELEMS_PER_BUCKET.
366 We must have at least four buckets, and the number of
367 buckets must be a power of 2. */
368 new_bucket_cnt = h->elem_cnt / BEST_ELEMS_PER_BUCKET;
369 if (new_bucket_cnt < 4)
370 new_bucket_cnt = 4;
371 while (!is_power_of_2 (new_bucket_cnt))
372 new_bucket_cnt = turn_off_least_1bit (new_bucket_cnt);
373
374 /* Don't do anything if the bucket count wouldn't change. */
375 if (new_bucket_cnt == old_bucket_cnt)
376 return;
377
378 /* Allocate new buckets and initialize them as empty. */
379 new_buckets = malloc (sizeof *new_buckets * new_bucket_cnt);
380 if (new_buckets == NULL)
381 {
382 /* Allocation failed. This means that use of the hash table will
383 be less efficient. However, it is still usable, so
384 there's no reason for it to be an error. */
385 return;
386 }
387 for (i = 0; i < new_bucket_cnt; i++)
388 list_init (&new_buckets[i]);
389
390 /* Install new bucket info. */
391 h->buckets = new_buckets;
392 h->bucket_cnt = new_bucket_cnt;
393
394 /* Move each old element into the appropriate new bucket. */
395 for (i = 0; i < old_bucket_cnt; i++)
396 {
397 struct list *old_bucket;
398 struct list_elem *elem, *next;
399
400 old_bucket = &old_buckets[i];
401 for (elem = list_begin (old_bucket);
402 elem != list_end (old_bucket); elem = next)
403 {
404 struct list *new_bucket
405 = find_bucket (h, list_elem_to_hash_elem (elem));
406 next = list_next (elem);
407 list_remove (elem);
408 list_push_front (new_bucket, elem);
409 }
410 }
411
412 free (old_buckets);
413}
414
415/* Inserts E into BUCKET (in hash table H). */
416static void
417insert_elem (struct hash *h, struct list *bucket, struct hash_elem *e)
418{
419 h->elem_cnt++;
420 list_push_front (bucket, &e->list_elem);
421}
422
423/* Removes E from hash table H. */
424static void
425remove_elem (struct hash *h, struct hash_elem *e)
426{
427 h->elem_cnt--;
428 list_remove (&e->list_elem);
429}
430
diff --git a/lib/kernel/hash.h b/lib/kernel/hash.h
new file mode 100644
index 0000000..db9f674
--- /dev/null
+++ b/lib/kernel/hash.h
@@ -0,0 +1,103 @@
1#ifndef __LIB_KERNEL_HASH_H
2#define __LIB_KERNEL_HASH_H
3
4/* Hash table.
5
6 This data structure is thoroughly documented in the Tour of
7 Pintos for Project 3.
8
9 This is a standard hash table with chaining. To locate an
10 element in the table, we compute a hash function over the
11 element's data and use that as an index into an array of
12 doubly linked lists, then linearly search the list.
13
14 The chain lists do not use dynamic allocation. Instead, each
15 structure that can potentially be in a hash must embed a
16 struct hash_elem member. All of the hash functions operate on
17 these `struct hash_elem's. The hash_entry macro allows
18 conversion from a struct hash_elem back to a structure object
19 that contains it. This is the same technique used in the
20 linked list implementation. Refer to lib/kernel/list.h for a
21 detailed explanation. */
22
23#include <stdbool.h>
24#include <stddef.h>
25#include <stdint.h>
26#include "list.h"
27
28/* Hash element. */
29struct hash_elem
30 {
31 struct list_elem list_elem;
32 };
33
34/* Converts pointer to hash element HASH_ELEM into a pointer to
35 the structure that HASH_ELEM is embedded inside. Supply the
36 name of the outer structure STRUCT and the member name MEMBER
37 of the hash element. See the big comment at the top of the
38 file for an example. */
39#define hash_entry(HASH_ELEM, STRUCT, MEMBER) \
40 ((STRUCT *) ((uint8_t *) &(HASH_ELEM)->list_elem \
41 - offsetof (STRUCT, MEMBER.list_elem)))
42
43/* Computes and returns the hash value for hash element E, given
44 auxiliary data AUX. */
45typedef unsigned hash_hash_func (const struct hash_elem *e, void *aux);
46
47/* Compares the value of two hash elements A and B, given
48 auxiliary data AUX. Returns true if A is less than B, or
49 false if A is greater than or equal to B. */
50typedef bool hash_less_func (const struct hash_elem *a,
51 const struct hash_elem *b,
52 void *aux);
53
54/* Performs some operation on hash element E, given auxiliary
55 data AUX. */
56typedef void hash_action_func (struct hash_elem *e, void *aux);
57
58/* Hash table. */
59struct hash
60 {
61 size_t elem_cnt; /* Number of elements in table. */
62 size_t bucket_cnt; /* Number of buckets, a power of 2. */
63 struct list *buckets; /* Array of `bucket_cnt' lists. */
64 hash_hash_func *hash; /* Hash function. */
65 hash_less_func *less; /* Comparison function. */
66 void *aux; /* Auxiliary data for `hash' and `less'. */
67 };
68
69/* A hash table iterator. */
70struct hash_iterator
71 {
72 struct hash *hash; /* The hash table. */
73 struct list *bucket; /* Current bucket. */
74 struct hash_elem *elem; /* Current hash element in current bucket. */
75 };
76
77/* Basic life cycle. */
78bool hash_init (struct hash *, hash_hash_func *, hash_less_func *, void *aux);
79void hash_clear (struct hash *, hash_action_func *);
80void hash_destroy (struct hash *, hash_action_func *);
81
82/* Search, insertion, deletion. */
83struct hash_elem *hash_insert (struct hash *, struct hash_elem *);
84struct hash_elem *hash_replace (struct hash *, struct hash_elem *);
85struct hash_elem *hash_find (struct hash *, struct hash_elem *);
86struct hash_elem *hash_delete (struct hash *, struct hash_elem *);
87
88/* Iteration. */
89void hash_apply (struct hash *, hash_action_func *);
90void hash_first (struct hash_iterator *, struct hash *);
91struct hash_elem *hash_next (struct hash_iterator *);
92struct hash_elem *hash_cur (struct hash_iterator *);
93
94/* Information. */
95size_t hash_size (struct hash *);
96bool hash_empty (struct hash *);
97
98/* Sample hash functions. */
99unsigned hash_bytes (const void *, size_t);
100unsigned hash_string (const char *);
101unsigned hash_int (int);
102
103#endif /* lib/kernel/hash.h */
diff --git a/lib/kernel/list.c b/lib/kernel/list.c
new file mode 100644
index 0000000..316d9ef
--- /dev/null
+++ b/lib/kernel/list.c
@@ -0,0 +1,524 @@
1#include "list.h"
2#include "../debug.h"
3
4/* Our doubly linked lists have two header elements: the "head"
5 just before the first element and the "tail" just after the
6 last element. The `prev' link of the front header is null, as
7 is the `next' link of the back header. Their other two links
8 point toward each other via the interior elements of the list.
9
10 An empty list looks like this:
11
12 +------+ +------+
13 <---| head |<--->| tail |--->
14 +------+ +------+
15
16 A list with two elements in it looks like this:
17
18 +------+ +-------+ +-------+ +------+
19 <---| head |<--->| 1 |<--->| 2 |<--->| tail |<--->
20 +------+ +-------+ +-------+ +------+
21
22 The symmetry of this arrangement eliminates lots of special
23 cases in list processing. For example, take a look at
24 list_remove(): it takes only two pointer assignments and no
25 conditionals. That's a lot simpler than the code would be
26 without header elements.
27
28 (Because only one of the pointers in each header element is used,
29 we could in fact combine them into a single header element
30 without sacrificing this simplicity. But using two separate
31 elements allows us to do a little bit of checking on some
32 operations, which can be valuable.) */
33
34static bool is_sorted (struct list_elem *a, struct list_elem *b,
35 list_less_func *less, void *aux) UNUSED;
36
37/* Returns true if ELEM is a head, false otherwise. */
38static inline bool
39is_head (struct list_elem *elem)
40{
41 return elem != NULL && elem->prev == NULL && elem->next != NULL;
42}
43
44/* Returns true if ELEM is an interior element,
45 false otherwise. */
46static inline bool
47is_interior (struct list_elem *elem)
48{
49 return elem != NULL && elem->prev != NULL && elem->next != NULL;
50}
51
52/* Returns true if ELEM is a tail, false otherwise. */
53static inline bool
54is_tail (struct list_elem *elem)
55{
56 return elem != NULL && elem->prev != NULL && elem->next == NULL;
57}
58
59/* Initializes LIST as an empty list. */
60void
61list_init (struct list *list)
62{
63 ASSERT (list != NULL);
64 list->head.prev = NULL;
65 list->head.next = &list->tail;
66 list->tail.prev = &list->head;
67 list->tail.next = NULL;
68}
69
70/* Returns the beginning of LIST. */
71struct list_elem *
72list_begin (struct list *list)
73{
74 ASSERT (list != NULL);
75 return list->head.next;
76}
77
78/* Returns the element after ELEM in its list. If ELEM is the
79 last element in its list, returns the list tail. Results are
80 undefined if ELEM is itself a list tail. */
81struct list_elem *
82list_next (struct list_elem *elem)
83{
84 ASSERT (is_head (elem) || is_interior (elem));
85 return elem->next;
86}
87
88/* Returns LIST's tail.
89
90 list_end() is often used in iterating through a list from
91 front to back. See the big comment at the top of list.h for
92 an example. */
93struct list_elem *
94list_end (struct list *list)
95{
96 ASSERT (list != NULL);
97 return &list->tail;
98}
99
100/* Returns the LIST's reverse beginning, for iterating through
101 LIST in reverse order, from back to front. */
102struct list_elem *
103list_rbegin (struct list *list)
104{
105 ASSERT (list != NULL);
106 return list->tail.prev;
107}
108
109/* Returns the element before ELEM in its list. If ELEM is the
110 first element in its list, returns the list head. Results are
111 undefined if ELEM is itself a list head. */
112struct list_elem *
113list_prev (struct list_elem *elem)
114{
115 ASSERT (is_interior (elem) || is_tail (elem));
116 return elem->prev;
117}
118
119/* Returns LIST's head.
120
121 list_rend() is often used in iterating through a list in
122 reverse order, from back to front. Here's typical usage,
123 following the example from the top of list.h:
124
125 for (e = list_rbegin (&foo_list); e != list_rend (&foo_list);
126 e = list_prev (e))
127 {
128 struct foo *f = list_entry (e, struct foo, elem);
129 ...do something with f...
130 }
131*/
132struct list_elem *
133list_rend (struct list *list)
134{
135 ASSERT (list != NULL);
136 return &list->head;
137}
138
139/* Return's LIST's head.
140
141 list_head() can be used for an alternate style of iterating
142 through a list, e.g.:
143
144 e = list_head (&list);
145 while ((e = list_next (e)) != list_end (&list))
146 {
147 ...
148 }
149*/
150struct list_elem *
151list_head (struct list *list)
152{
153 ASSERT (list != NULL);
154 return &list->head;
155}
156
157/* Return's LIST's tail. */
158struct list_elem *
159list_tail (struct list *list)
160{
161 ASSERT (list != NULL);
162 return &list->tail;
163}
164
165/* Inserts ELEM just before BEFORE, which may be either an
166 interior element or a tail. The latter case is equivalent to
167 list_push_back(). */
168void
169list_insert (struct list_elem *before, struct list_elem *elem)
170{
171 ASSERT (is_interior (before) || is_tail (before));
172 ASSERT (elem != NULL);
173
174 elem->prev = before->prev;
175 elem->next = before;
176 before->prev->next = elem;
177 before->prev = elem;
178}
179
180/* Removes elements FIRST though LAST (exclusive) from their
181 current list, then inserts them just before BEFORE, which may
182 be either an interior element or a tail. */
183void
184list_splice (struct list_elem *before,
185 struct list_elem *first, struct list_elem *last)
186{
187 ASSERT (is_interior (before) || is_tail (before));
188 if (first == last)
189 return;
190 last = list_prev (last);
191
192 ASSERT (is_interior (first));
193 ASSERT (is_interior (last));
194
195 /* Cleanly remove FIRST...LAST from its current list. */
196 first->prev->next = last->next;
197 last->next->prev = first->prev;
198
199 /* Splice FIRST...LAST into new list. */
200 first->prev = before->prev;
201 last->next = before;
202 before->prev->next = first;
203 before->prev = last;
204}
205
206/* Inserts ELEM at the beginning of LIST, so that it becomes the
207 front in LIST. */
208void
209list_push_front (struct list *list, struct list_elem *elem)
210{
211 list_insert (list_begin (list), elem);
212}
213
214/* Inserts ELEM at the end of LIST, so that it becomes the
215 back in LIST. */
216void
217list_push_back (struct list *list, struct list_elem *elem)
218{
219 list_insert (list_end (list), elem);
220}
221
222/* Removes ELEM from its list and returns the element that
223 followed it. Undefined behavior if ELEM is not in a list.
224
225 A list element must be treated very carefully after removing
226 it from its list. Calling list_next() or list_prev() on ELEM
227 will return the item that was previously before or after ELEM,
228 but, e.g., list_prev(list_next(ELEM)) is no longer ELEM!
229
230 The list_remove() return value provides a convenient way to
231 iterate and remove elements from a list:
232
233 for (e = list_begin (&list); e != list_end (&list); e = list_remove (e))
234 {
235 ...do something with e...
236 }
237
238 If you need to free() elements of the list then you need to be
239 more conservative. Here's an alternate strategy that works
240 even in that case:
241
242 while (!list_empty (&list))
243 {
244 struct list_elem *e = list_pop_front (&list);
245 ...do something with e...
246 }
247*/
248struct list_elem *
249list_remove (struct list_elem *elem)
250{
251 ASSERT (is_interior (elem));
252 elem->prev->next = elem->next;
253 elem->next->prev = elem->prev;
254 return elem->next;
255}
256
257/* Removes the front element from LIST and returns it.
258 Undefined behavior if LIST is empty before removal. */
259struct list_elem *
260list_pop_front (struct list *list)
261{
262 struct list_elem *front = list_front (list);
263 list_remove (front);
264 return front;
265}
266
267/* Removes the back element from LIST and returns it.
268 Undefined behavior if LIST is empty before removal. */
269struct list_elem *
270list_pop_back (struct list *list)
271{
272 struct list_elem *back = list_back (list);
273 list_remove (back);
274 return back;
275}
276
277/* Returns the front element in LIST.
278 Undefined behavior if LIST is empty. */
279struct list_elem *
280list_front (struct list *list)
281{
282 ASSERT (!list_empty (list));
283 return list->head.next;
284}
285
286/* Returns the back element in LIST.
287 Undefined behavior if LIST is empty. */
288struct list_elem *
289list_back (struct list *list)
290{
291 ASSERT (!list_empty (list));
292 return list->tail.prev;
293}
294
295/* Returns the number of elements in LIST.
296 Runs in O(n) in the number of elements. */
297size_t
298list_size (struct list *list)
299{
300 struct list_elem *e;
301 size_t cnt = 0;
302
303 for (e = list_begin (list); e != list_end (list); e = list_next (e))
304 cnt++;
305 return cnt;
306}
307
308/* Returns true if LIST is empty, false otherwise. */
309bool
310list_empty (struct list *list)
311{
312 return list_begin (list) == list_end (list);
313}
314
315/* Swaps the `struct list_elem *'s that A and B point to. */
316static void
317swap (struct list_elem **a, struct list_elem **b)
318{
319 struct list_elem *t = *a;
320 *a = *b;
321 *b = t;
322}
323
324/* Reverses the order of LIST. */
325void
326list_reverse (struct list *list)
327{
328 if (!list_empty (list))
329 {
330 struct list_elem *e;
331
332 for (e = list_begin (list); e != list_end (list); e = e->prev)
333 swap (&e->prev, &e->next);
334 swap (&list->head.next, &list->tail.prev);
335 swap (&list->head.next->prev, &list->tail.prev->next);
336 }
337}
338
339/* Returns true only if the list elements A through B (exclusive)
340 are in order according to LESS given auxiliary data AUX. */
341static bool
342is_sorted (struct list_elem *a, struct list_elem *b,
343 list_less_func *less, void *aux)
344{
345 if (a != b)
346 while ((a = list_next (a)) != b)
347 if (less (a, list_prev (a), aux))
348 return false;
349 return true;
350}
351
352/* Finds a run, starting at A and ending not after B, of list
353 elements that are in nondecreasing order according to LESS
354 given auxiliary data AUX. Returns the (exclusive) end of the
355 run.
356 A through B (exclusive) must form a non-empty range. */
357static struct list_elem *
358find_end_of_run (struct list_elem *a, struct list_elem *b,
359 list_less_func *less, void *aux)
360{
361 ASSERT (a != NULL);
362 ASSERT (b != NULL);
363 ASSERT (less != NULL);
364 ASSERT (a != b);
365
366 do
367 {
368 a = list_next (a);
369 }
370 while (a != b && !less (a, list_prev (a), aux));
371 return a;
372}
373
374/* Merges A0 through A1B0 (exclusive) with A1B0 through B1
375 (exclusive) to form a combined range also ending at B1
376 (exclusive). Both input ranges must be nonempty and sorted in
377 nondecreasing order according to LESS given auxiliary data
378 AUX. The output range will be sorted the same way. */
379static void
380inplace_merge (struct list_elem *a0, struct list_elem *a1b0,
381 struct list_elem *b1,
382 list_less_func *less, void *aux)
383{
384 ASSERT (a0 != NULL);
385 ASSERT (a1b0 != NULL);
386 ASSERT (b1 != NULL);
387 ASSERT (less != NULL);
388 ASSERT (is_sorted (a0, a1b0, less, aux));
389 ASSERT (is_sorted (a1b0, b1, less, aux));
390
391 while (a0 != a1b0 && a1b0 != b1)
392 if (!less (a1b0, a0, aux))
393 a0 = list_next (a0);
394 else
395 {
396 a1b0 = list_next (a1b0);
397 list_splice (a0, list_prev (a1b0), a1b0);
398 }
399}
400
401/* Sorts LIST according to LESS given auxiliary data AUX, using a
402 natural iterative merge sort that runs in O(n lg n) time and
403 O(1) space in the number of elements in LIST. */
404void
405list_sort (struct list *list, list_less_func *less, void *aux)
406{
407 size_t output_run_cnt; /* Number of runs output in current pass. */
408
409 ASSERT (list != NULL);
410 ASSERT (less != NULL);
411
412 /* Pass over the list repeatedly, merging adjacent runs of
413 nondecreasing elements, until only one run is left. */
414 do
415 {
416 struct list_elem *a0; /* Start of first run. */
417 struct list_elem *a1b0; /* End of first run, start of second. */
418 struct list_elem *b1; /* End of second run. */
419
420 output_run_cnt = 0;
421 for (a0 = list_begin (list); a0 != list_end (list); a0 = b1)
422 {
423 /* Each iteration produces one output run. */
424 output_run_cnt++;
425
426 /* Locate two adjacent runs of nondecreasing elements
427 A0...A1B0 and A1B0...B1. */
428 a1b0 = find_end_of_run (a0, list_end (list), less, aux);
429 if (a1b0 == list_end (list))
430 break;
431 b1 = find_end_of_run (a1b0, list_end (list), less, aux);
432
433 /* Merge the runs. */
434 inplace_merge (a0, a1b0, b1, less, aux);
435 }
436 }
437 while (output_run_cnt > 1);
438
439 ASSERT (is_sorted (list_begin (list), list_end (list), less, aux));
440}
441
442/* Inserts ELEM in the proper position in LIST, which must be
443 sorted according to LESS given auxiliary data AUX.
444 Runs in O(n) average case in the number of elements in LIST. */
445void
446list_insert_ordered (struct list *list, struct list_elem *elem,
447 list_less_func *less, void *aux)
448{
449 struct list_elem *e;
450
451 ASSERT (list != NULL);
452 ASSERT (elem != NULL);
453 ASSERT (less != NULL);
454
455 for (e = list_begin (list); e != list_end (list); e = list_next (e))
456 if (less (elem, e, aux))
457 break;
458 return list_insert (e, elem);
459}
460
461/* Iterates through LIST and removes all but the first in each
462 set of adjacent elements that are equal according to LESS
463 given auxiliary data AUX. If DUPLICATES is non-null, then the
464 elements from LIST are appended to DUPLICATES. */
465void
466list_unique (struct list *list, struct list *duplicates,
467 list_less_func *less, void *aux)
468{
469 struct list_elem *elem, *next;
470
471 ASSERT (list != NULL);
472 ASSERT (less != NULL);
473 if (list_empty (list))
474 return;
475
476 elem = list_begin (list);
477 while ((next = list_next (elem)) != list_end (list))
478 if (!less (elem, next, aux) && !less (next, elem, aux))
479 {
480 list_remove (next);
481 if (duplicates != NULL)
482 list_push_back (duplicates, next);
483 }
484 else
485 elem = next;
486}
487
488/* Returns the element in LIST with the largest value according
489 to LESS given auxiliary data AUX. If there is more than one
490 maximum, returns the one that appears earlier in the list. If
491 the list is empty, returns its tail. */
492struct list_elem *
493list_max (struct list *list, list_less_func *less, void *aux)
494{
495 struct list_elem *max = list_begin (list);
496 if (max != list_end (list))
497 {
498 struct list_elem *e;
499
500 for (e = list_next (max); e != list_end (list); e = list_next (e))
501 if (less (max, e, aux))
502 max = e;
503 }
504 return max;
505}
506
507/* Returns the element in LIST with the smallest value according
508 to LESS given auxiliary data AUX. If there is more than one
509 minimum, returns the one that appears earlier in the list. If
510 the list is empty, returns its tail. */
511struct list_elem *
512list_min (struct list *list, list_less_func *less, void *aux)
513{
514 struct list_elem *min = list_begin (list);
515 if (min != list_end (list))
516 {
517 struct list_elem *e;
518
519 for (e = list_next (min); e != list_end (list); e = list_next (e))
520 if (less (e, min, aux))
521 min = e;
522 }
523 return min;
524}
diff --git a/lib/kernel/list.h b/lib/kernel/list.h
new file mode 100644
index 0000000..82efbb5
--- /dev/null
+++ b/lib/kernel/list.h
@@ -0,0 +1,181 @@
1#ifndef __LIB_KERNEL_LIST_H
2#define __LIB_KERNEL_LIST_H
3
4/* Doubly linked list.
5
6 This implementation of a doubly linked list does not require
7 use of dynamically allocated memory. Instead, each structure
8 that is a potential list element must embed a struct list_elem
9 member. All of the list functions operate on these `struct
10 list_elem's. The list_entry macro allows conversion from a
11 struct list_elem back to a structure object that contains it.
12
13 For example, suppose there is a needed for a list of `struct
14 foo'. `struct foo' should contain a `struct list_elem'
15 member, like so:
16
17 struct foo
18 {
19 struct list_elem elem;
20 int bar;
21 ...other members...
22 };
23
24 Then a list of `struct foo' can be be declared and initialized
25 like so:
26
27 struct list foo_list;
28
29 list_init (&foo_list);
30
31 Iteration is a typical situation where it is necessary to
32 convert from a struct list_elem back to its enclosing
33 structure. Here's an example using foo_list:
34
35 struct list_elem *e;
36
37 for (e = list_begin (&foo_list); e != list_end (&foo_list);
38 e = list_next (e))
39 {
40 struct foo *f = list_entry (e, struct foo, elem);
41 ...do something with f...
42 }
43
44 You can find real examples of list usage throughout the
45 source; for example, malloc.c, palloc.c, and thread.c in the
46 threads directory all use lists.
47
48 The interface for this list is inspired by the list<> template
49 in the C++ STL. If you're familiar with list<>, you should
50 find this easy to use. However, it should be emphasized that
51 these lists do *no* type checking and can't do much other
52 correctness checking. If you screw up, it will bite you.
53
54 Glossary of list terms:
55
56 - "front": The first element in a list. Undefined in an
57 empty list. Returned by list_front().
58
59 - "back": The last element in a list. Undefined in an empty
60 list. Returned by list_back().
61
62 - "tail": The element figuratively just after the last
63 element of a list. Well defined even in an empty list.
64 Returned by list_end(). Used as the end sentinel for an
65 iteration from front to back.
66
67 - "beginning": In a non-empty list, the front. In an empty
68 list, the tail. Returned by list_begin(). Used as the
69 starting point for an iteration from front to back.
70
71 - "head": The element figuratively just before the first
72 element of a list. Well defined even in an empty list.
73 Returned by list_rend(). Used as the end sentinel for an
74 iteration from back to front.
75
76 - "reverse beginning": In a non-empty list, the back. In an
77 empty list, the head. Returned by list_rbegin(). Used as
78 the starting point for an iteration from back to front.
79
80 - "interior element": An element that is not the head or
81 tail, that is, a real list element. An empty list does
82 not have any interior elements.
83*/
84
85#include <stdbool.h>
86#include <stddef.h>
87#include <stdint.h>
88
89/* List element. */
90struct list_elem
91 {
92 struct list_elem *prev; /* Previous list element. */
93 struct list_elem *next; /* Next list element. */
94 };
95
96/* List. */
97struct list
98 {
99 struct list_elem head; /* List head. */
100 struct list_elem tail; /* List tail. */
101 };
102
103/* Converts pointer to list element LIST_ELEM into a pointer to
104 the structure that LIST_ELEM is embedded inside. Supply the
105 name of the outer structure STRUCT and the member name MEMBER
106 of the list element. See the big comment at the top of the
107 file for an example. */
108#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
109 ((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
110 - offsetof (STRUCT, MEMBER.next)))
111
112/* List initialization.
113
114 A list may be initialized by calling list_init():
115
116 struct list my_list;
117 list_init (&my_list);
118
119 or with an initializer using LIST_INITIALIZER:
120
121 struct list my_list = LIST_INITIALIZER (my_list); */
122#define LIST_INITIALIZER(NAME) { { NULL, &(NAME).tail }, \
123 { &(NAME).head, NULL } }
124
125void list_init (struct list *);
126
127/* List traversal. */
128struct list_elem *list_begin (struct list *);
129struct list_elem *list_next (struct list_elem *);
130struct list_elem *list_end (struct list *);
131
132struct list_elem *list_rbegin (struct list *);
133struct list_elem *list_prev (struct list_elem *);
134struct list_elem *list_rend (struct list *);
135
136struct list_elem *list_head (struct list *);
137struct list_elem *list_tail (struct list *);
138
139/* List insertion. */
140void list_insert (struct list_elem *, struct list_elem *);
141void list_splice (struct list_elem *before,
142 struct list_elem *first, struct list_elem *last);
143void list_push_front (struct list *, struct list_elem *);
144void list_push_back (struct list *, struct list_elem *);
145
146/* List removal. */
147struct list_elem *list_remove (struct list_elem *);
148struct list_elem *list_pop_front (struct list *);
149struct list_elem *list_pop_back (struct list *);
150
151/* List elements. */
152struct list_elem *list_front (struct list *);
153struct list_elem *list_back (struct list *);
154
155/* List properties. */
156size_t list_size (struct list *);
157bool list_empty (struct list *);
158
159/* Miscellaneous. */
160void list_reverse (struct list *);
161
162/* Compares the value of two list elements A and B, given
163 auxiliary data AUX. Returns true if A is less than B, or
164 false if A is greater than or equal to B. */
165typedef bool list_less_func (const struct list_elem *a,
166 const struct list_elem *b,
167 void *aux);
168
169/* Operations on lists with ordered elements. */
170void list_sort (struct list *,
171 list_less_func *, void *aux);
172void list_insert_ordered (struct list *, struct list_elem *,
173 list_less_func *, void *aux);
174void list_unique (struct list *, struct list *duplicates,
175 list_less_func *, void *aux);
176
177/* Max and min. */
178struct list_elem *list_max (struct list *, list_less_func *, void *aux);
179struct list_elem *list_min (struct list *, list_less_func *, void *aux);
180
181#endif /* lib/kernel/list.h */
diff --git a/lib/kernel/stdio.h b/lib/kernel/stdio.h
new file mode 100644
index 0000000..3e5bae9
--- /dev/null
+++ b/lib/kernel/stdio.h
@@ -0,0 +1,6 @@
1#ifndef __LIB_KERNEL_STDIO_H
2#define __LIB_KERNEL_STDIO_H
3
4void putbuf (const char *, size_t);
5
6#endif /* lib/kernel/stdio.h */