95 lines
2.4 KiB
C
95 lines
2.4 KiB
C
|
/* Low-priority main thread L acquires lock A. Medium-priority
|
||
|
thread M then acquires lock B then blocks on acquiring lock A.
|
||
|
High-priority thread H then blocks on acquiring lock B. Thus,
|
||
|
thread H donates its priority to M, which in turn donates it
|
||
|
to thread L.
|
||
|
|
||
|
Based on a test originally submitted for Stanford's CS 140 in
|
||
|
winter 1999 by Matt Franklin <startled@leland.stanford.edu>,
|
||
|
Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu
|
||
|
<yph@cs.stanford.edu>. Modified by arens. */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include "tests/threads/tests.h"
|
||
|
#include "threads/init.h"
|
||
|
#include "threads/synch.h"
|
||
|
#include "threads/thread.h"
|
||
|
|
||
|
struct locks
|
||
|
{
|
||
|
struct lock *a;
|
||
|
struct lock *b;
|
||
|
};
|
||
|
|
||
|
static thread_func medium_thread_func;
|
||
|
static thread_func high_thread_func;
|
||
|
|
||
|
void
|
||
|
test_priority_donate_nest (void)
|
||
|
{
|
||
|
struct lock a, b;
|
||
|
struct locks locks;
|
||
|
|
||
|
/* This test does not work with the MLFQS. */
|
||
|
ASSERT (!thread_mlfqs);
|
||
|
|
||
|
/* Make sure our priority is the default. */
|
||
|
ASSERT (thread_get_priority () == PRI_DEFAULT);
|
||
|
|
||
|
lock_init (&a);
|
||
|
lock_init (&b);
|
||
|
|
||
|
lock_acquire (&a);
|
||
|
|
||
|
locks.a = &a;
|
||
|
locks.b = &b;
|
||
|
thread_create ("medium", PRI_DEFAULT + 1, medium_thread_func, &locks);
|
||
|
thread_yield ();
|
||
|
msg ("Low thread should have priority %d. Actual priority: %d.",
|
||
|
PRI_DEFAULT + 1, thread_get_priority ());
|
||
|
|
||
|
thread_create ("high", PRI_DEFAULT + 2, high_thread_func, &b);
|
||
|
thread_yield ();
|
||
|
msg ("Low thread should have priority %d. Actual priority: %d.",
|
||
|
PRI_DEFAULT + 2, thread_get_priority ());
|
||
|
|
||
|
lock_release (&a);
|
||
|
thread_yield ();
|
||
|
msg ("Medium thread should just have finished.");
|
||
|
msg ("Low thread should have priority %d. Actual priority: %d.",
|
||
|
PRI_DEFAULT, thread_get_priority ());
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
medium_thread_func (void *locks_)
|
||
|
{
|
||
|
struct locks *locks = locks_;
|
||
|
|
||
|
lock_acquire (locks->b);
|
||
|
lock_acquire (locks->a);
|
||
|
|
||
|
msg ("Medium thread should have priority %d. Actual priority: %d.",
|
||
|
PRI_DEFAULT + 2, thread_get_priority ());
|
||
|
msg ("Medium thread got the lock.");
|
||
|
|
||
|
lock_release (locks->a);
|
||
|
thread_yield ();
|
||
|
|
||
|
lock_release (locks->b);
|
||
|
thread_yield ();
|
||
|
|
||
|
msg ("High thread should have just finished.");
|
||
|
msg ("Middle thread finished.");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
high_thread_func (void *lock_)
|
||
|
{
|
||
|
struct lock *lock = lock_;
|
||
|
|
||
|
lock_acquire (lock);
|
||
|
msg ("High thread got the lock.");
|
||
|
lock_release (lock);
|
||
|
msg ("High thread finished.");
|
||
|
}
|