Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • y2-rhymansaib/pintos_student
1 result
Select Git revision
Show changes
Showing
with 143 additions and 289 deletions
# Percentage of the testing point total designated for each set of
# tests.
20.0% tests/threads/Rubric.alarm
40.0% tests/threads/Rubric.priority
40.0% tests/threads/Rubric.mlfqs
30.0% tests/threads/Rubric.alarm
70.0% tests/threads/Rubric.priority
#40.0% tests/threads/Rubric.mlfqs
......@@ -7,9 +7,9 @@ alarm-negative priority-change priority-donate-one \
priority-donate-multiple priority-donate-multiple2 \
priority-donate-nest priority-donate-sema priority-donate-lower \
priority-fifo priority-preempt priority-sema priority-condvar \
priority-donate-chain \
mlfqs-load-1 mlfqs-load-60 mlfqs-load-avg mlfqs-recent-1 mlfqs-fair-2 \
mlfqs-fair-20 mlfqs-nice-2 mlfqs-nice-10 mlfqs-block)
priority-donate-chain)
#mlfqs-load-1 mlfqs-load-60 mlfqs-load-avg mlfqs-recent-1 mlfqs-fair-2 \
#mlfqs-fair-20 mlfqs-nice-2 mlfqs-nice-10 mlfqs-block)
# Sources for tests.
tests/threads_SRC = tests/threads/tests.c
......
/* Invokes a system call with the stack pointer (%esp) set to a
bad address. The process must be terminated with -1 exit
code.
For Project 3: The bad address lies approximately 64MB below
the code segment, so there is no ambiguity that this attempt
must be rejected even after stack growth is implemented.
Moreover, a good stack growth heuristics should probably not
grow the stack for the purpose of reading the system call
number and arguments. */
#include "tests/lib.h"
#include "tests/main.h"
......
Functionality of virtual memory subsystem:
- Test stack growth.
3 pt-grow-stack
3 pt-grow-stk-sc
3 pt-big-stk-obj
3 pt-grow-pusha
- Test paging behavior.
3 page-linear
3 page-parallel
3 page-shuffle
4 page-merge-seq
4 page-merge-par
4 page-merge-mm
4 page-merge-stk
- Test "mmap" system call.
2 mmap-read
2 mmap-write
2 mmap-shuffle
2 mmap-twice
2 mmap-unmap
1 mmap-exit
3 mmap-clean
2 mmap-close
2 mmap-remove
Robustness of virtual memory subsystem:
- Test robustness of page table support.
2 pt-bad-addr
3 pt-bad-read
2 pt-write-code
3 pt-write-code2
4 pt-grow-bad
- Test robustness of "mmap" system call.
1 mmap-bad-fd
1 mmap-inherit
1 mmap-null
1 mmap-zero
2 mmap-misalign
2 mmap-over-code
2 mmap-over-data
2 mmap-over-stk
2 mmap-overlap
# -*- perl -*-
use strict;
use warnings;
use tests::tests;
check_expected ([<<'EOF']);
(pt-write-code2) begin
(pt-write-code2) open "sample.txt"
pt-write-code2: exit(-1)
EOF
pass;
#include "tests/vm/qsort.h"
#include <stdbool.h>
#include <debug.h>
#include <random.h>
/* Picks a pivot for the quicksort from the SIZE bytes in BUF. */
static unsigned char
pick_pivot (unsigned char *buf, size_t size)
{
ASSERT (size >= 1);
return buf[random_ulong () % size];
}
/* Checks whether the SIZE bytes in ARRAY are divided into an
initial LEFT_SIZE elements all less than PIVOT followed by
SIZE - LEFT_SIZE elements all greater than or equal to
PIVOT. */
static bool
is_partitioned (const unsigned char *array, size_t size,
unsigned char pivot, size_t left_size)
{
size_t i;
for (i = 0; i < left_size; i++)
if (array[i] >= pivot)
return false;
for (; i < size; i++)
if (array[i] < pivot)
return false;
return true;
}
/* Swaps the bytes at *A and *B. */
static void
swap (unsigned char *a, unsigned char *b)
{
unsigned char t = *a;
*a = *b;
*b = t;
}
/* Partitions ARRAY in-place in an initial run of bytes all less
than PIVOT, followed by a run of bytes all greater than or
equal to PIVOT. Returns the length of the initial run. */
static size_t
partition (unsigned char *array, size_t size, int pivot)
{
size_t left_size = size;
unsigned char *first = array;
unsigned char *last = first + left_size;
for (;;)
{
/* Move FIRST forward to point to first element greater than
PIVOT. */
for (;;)
{
if (first == last)
{
ASSERT (is_partitioned (array, size, pivot, left_size));
return left_size;
}
else if (*first >= pivot)
break;
first++;
}
left_size--;
/* Move LAST backward to point to last element no bigger
than PIVOT. */
for (;;)
{
last--;
if (first == last)
{
ASSERT (is_partitioned (array, size, pivot, left_size));
return left_size;
}
else if (*last < pivot)
break;
else
left_size--;
}
/* By swapping FIRST and LAST we extend the starting and
ending sequences that pass and fail, respectively,
PREDICATE. */
swap (first, last);
first++;
}
}
/* Returns true if the SIZE bytes in BUF are in nondecreasing
order, false otherwise. */
static bool
is_sorted (const unsigned char *buf, size_t size)
{
size_t i;
for (i = 1; i < size; i++)
if (buf[i - 1] > buf[i])
return false;
return true;
}
/* Sorts the SIZE bytes in BUF into nondecreasing order, using
the quick-sort algorithm. */
void
qsort_bytes (unsigned char *buf, size_t size)
{
if (!is_sorted (buf, size))
{
int pivot = pick_pivot (buf, size);
unsigned char *left_half = buf;
size_t left_size = partition (buf, size, pivot);
unsigned char *right_half = left_half + left_size;
size_t right_size = size - left_size;
if (left_size <= right_size)
{
qsort_bytes (left_half, left_size);
qsort_bytes (right_half, right_size);
}
else
{
qsort_bytes (right_half, right_size);
qsort_bytes (left_half, left_size);
}
}
}
#ifndef TESTS_VM_QSORT_H
#define TESTS_VM_QSORT_H 1
#include <stddef.h>
void qsort_bytes (unsigned char *buf, size_t size);
#endif /* tests/vm/qsort.h */
char sample[] = {
"=== ALL USERS PLEASE NOTE ========================\n"
"\n"
"CAR and CDR now return extra values.\n"
"\n"
"The function CAR now returns two values. Since it has to go to the\n"
"trouble to figure out if the object is carcdr-able anyway, we figured\n"
"you might as well get both halves at once. For example, the following\n"
"code shows how to destructure a cons (SOME-CONS) into its two slots\n"
"(THE-CAR and THE-CDR):\n"
"\n"
" (MULTIPLE-VALUE-BIND (THE-CAR THE-CDR) (CAR SOME-CONS) ...)\n"
"\n"
"For symmetry with CAR, CDR returns a second value which is the CAR of\n"
"the object. In a related change, the functions MAKE-ARRAY and CONS\n"
"have been fixed so they don't allocate any storage except on the\n"
"stack. This should hopefully help people who don't like using the\n"
"garbage collector because it cold boots the machine so often.\n"
};
=== ALL USERS PLEASE NOTE ========================
CAR and CDR now return extra values.
The function CAR now returns two values. Since it has to go to the
trouble to figure out if the object is carcdr-able anyway, we figured
you might as well get both halves at once. For example, the following
code shows how to destructure a cons (SOME-CONS) into its two slots
(THE-CAR and THE-CDR):
(MULTIPLE-VALUE-BIND (THE-CAR THE-CDR) (CAR SOME-CONS) ...)
For symmetry with CAR, CDR returns a second value which is the CAR of
the object. In a related change, the functions MAKE-ARRAY and CONS
have been fixed so they don't allocate any storage except on the
stack. This should hopefully help people who don't like using the
garbage collector because it cold boots the machine so often.
......@@ -287,7 +287,7 @@ run_task (char **argv)
#ifdef USERPROG
process_wait (process_execute (task));
#else
run_test (task);
// run_test (task);
#endif
printf ("Execution of '%s' complete.\n", task);
}
......
......@@ -32,6 +32,10 @@
#include "threads/interrupt.h"
#include "threads/thread.h"
static bool comparator_greater_thread_priority(const struct list_elem*, const struct list_elem*, void *);
static bool comparator_greater_lock_priority(const struct list_elem*, const struct list_elem*, void *);
static bool comparator_greater_sema_priority(const struct list_elem*, const struct list_elem*, void *);
/* Initializes semaphore SEMA to VALUE. A semaphore is a
nonnegative integer along with two atomic operators for
manipulating it:
......@@ -68,7 +72,8 @@ sema_down (struct semaphore *sema)
old_level = intr_disable ();
while (sema->value == 0)
{
list_push_back (&sema->waiters, &thread_current ()->elem);
list_insert_ordered (&sema->waiters, &thread_current()->elem,
comparator_greater_thread_priority, NULL);
thread_block ();
}
sema->value--;
......@@ -109,14 +114,22 @@ void
sema_up (struct semaphore *sema)
{
enum intr_level old_level;
struct thread *target = NULL;
ASSERT (sema != NULL);
old_level = intr_disable ();
if (!list_empty (&sema->waiters))
thread_unblock (list_entry (list_pop_front (&sema->waiters),
struct thread, elem));
sema->value++;
if (!list_empty (&sema->waiters)) {
list_sort(&(sema->waiters), comparator_greater_thread_priority, NULL);
// the thread of highest priority (in sema waiters) should wake up
target = list_entry (list_pop_front (&sema->waiters), struct thread, elem);
thread_unblock (target);
}
intr_set_level (old_level);
}
......@@ -178,6 +191,7 @@ lock_init (struct lock *lock)
ASSERT (lock != NULL);
lock->holder = NULL;
lock->priority = PRI_MIN;
sema_init (&lock->semaphore, 1);
}
......@@ -196,8 +210,38 @@ lock_acquire (struct lock *lock)
ASSERT (!intr_context ());
ASSERT (!lock_held_by_current_thread (lock));
// priority donation, when locking
struct lock *current_lock = lock;
struct thread *t_holder = lock->holder; // current holder thread
struct thread *t_current = thread_current();
// The current process is waiting on [lock]
t_current->waiting_lock = lock;
if(t_holder == NULL) {
current_lock->priority = t_current->priority;
}
while (t_holder != NULL && t_holder->priority < t_current->priority) {
// Donate priority to [t_holder]
thread_priority_donate(t_holder, t_current->priority);
if (current_lock->priority < t_current->priority) {
current_lock->priority = t_current->priority;
}
current_lock = t_holder->waiting_lock;
if(current_lock == NULL) break;
t_holder = current_lock->holder;
}
sema_down (&lock->semaphore);
lock->holder = thread_current ();
// lock is finally acquired.
lock->holder->waiting_lock = NULL; // no longer waiting
list_insert_ordered(&(lock->holder->locks), &(lock->lockelem),
comparator_greater_lock_priority, NULL);
}
/* Tries to acquires LOCK and returns true if successful or false
......@@ -215,8 +259,10 @@ lock_try_acquire (struct lock *lock)
ASSERT (!lock_held_by_current_thread (lock));
success = sema_try_down (&lock->semaphore);
if (success)
lock->holder = thread_current ();
if (success) {
struct thread *t_current = thread_current();
lock->holder = t_current;
}
return success;
}
......@@ -231,8 +277,30 @@ lock_release (struct lock *lock)
ASSERT (lock != NULL);
ASSERT (lock_held_by_current_thread (lock));
struct thread *t_current = thread_current();
lock->holder = NULL;
sema_up (&lock->semaphore);
// Remove the lock from locklist
list_remove (&lock->lockelem);
// priority donation : restoration
if (list_empty(&t_current->locks)) {
// no more locks: there is no priority donors
// the original priority of the current thread
thread_priority_donate(t_current, t_current->original_priority);
}
else {
// donated: lookup the donors, find the highest priority lock
// then it should be the (newly updated) donated priority of t
list_sort(&(t_current->locks), comparator_greater_lock_priority, NULL); // TODO why it is needed?
struct lock *highest_lock = list_entry( list_front(&(t_current->locks)), struct lock, lockelem );
thread_priority_donate(t_current, highest_lock->priority);
}
}
/* Returns true if the current thread holds LOCK, false
......@@ -295,7 +363,11 @@ cond_wait (struct condition *cond, struct lock *lock)
ASSERT (lock_held_by_current_thread (lock));
sema_init (&waiter.semaphore, 0);
list_push_back (&cond->waiters, &waiter.elem);
// sort threads in condition's waiters
waiter.semaphore.priority = thread_current()->priority;
list_insert_ordered (&cond->waiters, &(waiter.elem), comparator_greater_sema_priority, NULL);
lock_release (lock);
sema_down (&waiter.semaphore);
lock_acquire (lock);
......@@ -316,10 +388,11 @@ cond_signal (struct condition *cond, struct lock *lock UNUSED)
ASSERT (!intr_context ());
ASSERT (lock_held_by_current_thread (lock));
if (!list_empty (&cond->waiters))
if (!list_empty (&cond->waiters)) {
sema_up (&list_entry (list_pop_front (&cond->waiters),
struct semaphore_elem, elem)->semaphore);
}
}
/* Wakes up all threads, if any, waiting on COND (protected by
LOCK). LOCK must be held before calling this function.
......@@ -336,3 +409,32 @@ cond_broadcast (struct condition *cond, struct lock *lock)
while (!list_empty (&cond->waiters))
cond_signal (cond, lock);
}
/* Helpers */
static bool
comparator_greater_thread_priority(const struct list_elem* a, const struct list_elem *b, void* aux UNUSED)
{
const struct thread* x = list_entry(a, struct thread, elem);
const struct thread* y = list_entry(b, struct thread, elem);
ASSERT(x != NULL && y != NULL);
return x->priority > y->priority;
}
static bool
comparator_greater_lock_priority(const struct list_elem* a, const struct list_elem *b, void* aux UNUSED)
{
const struct lock* x = list_entry(a, struct lock, lockelem);
const struct lock* y = list_entry(b, struct lock, lockelem);
ASSERT(x != NULL && y != NULL);
return x->priority > y->priority;
}
static bool
comparator_greater_sema_priority(const struct list_elem* a, const struct list_elem *b, void* aux UNUSED)
{
const struct semaphore_elem* x = list_entry(a, struct semaphore_elem, elem);
const struct semaphore_elem* y = list_entry(b, struct semaphore_elem, elem);
ASSERT(x != NULL && y != NULL);
return x->semaphore.priority > y->semaphore.priority;
}
......@@ -9,6 +9,7 @@ struct semaphore
{
unsigned value; /* Current value. */
struct list waiters; /* List of waiting threads. */
int priority; /* Priority of semaphore */
};
void sema_init (struct semaphore *, unsigned value);
......@@ -22,6 +23,9 @@ struct lock
{
struct thread *holder; /* Thread holding lock (for debugging). */
struct semaphore semaphore; /* Binary semaphore controlling access. */
struct list_elem lockelem; /* List element for the thread's 'locks' list. */
int priority; /* priority of the the thread holding the lock (for priority donation) */
};
void lock_init (struct lock *);
......