1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 00:16:17 +04:00

Complete Semaphore Condvar, dining-philosophers-problem using monitor

This commit is contained in:
WangRunji 2018-06-05 00:34:34 +08:00
parent 316d32496c
commit 0b0dac3c81
5 changed files with 110 additions and 62 deletions

View File

@ -16,28 +16,30 @@
#[macro_use]
extern crate alloc;
extern crate rlibc;
extern crate volatile;
extern crate spin;
extern crate multiboot2;
extern crate arrayvec;
extern crate bit_allocator;
extern crate bit_field;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate x86_64;
#[macro_use]
extern crate once;
extern crate lazy_static;
extern crate linked_list_allocator;
#[macro_use]
extern crate lazy_static;
extern crate bit_field;
extern crate syscall as redox_syscall;
extern crate xmas_elf;
extern crate arrayvec;
#[macro_use]
extern crate log;
extern crate multiboot2;
#[macro_use]
extern crate once;
extern crate rlibc;
extern crate simple_filesystem;
extern crate bit_allocator;
extern crate spin;
extern crate syscall as redox_syscall;
extern crate volatile;
#[macro_use]
extern crate x86_64;
extern crate xmas_elf;
pub use arch::interrupt::{rust_trap, set_return_rsp};
use linked_list_allocator::LockedHeap;
#[macro_use] // print!
mod io;
@ -93,7 +95,8 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
unsafe{ arch::interrupt::enable(); }
// thread::test::unpack();
sync::test::philosopher();
sync::test::philosopher_using_mutex();
sync::test::philosopher_using_monitor();
// 直接进入用户态暂不可用:内核代码用户不可访问
// unsafe{
@ -129,10 +132,6 @@ pub extern "C" fn other_main() -> ! {
loop {}
}
pub use arch::interrupt::{rust_trap, set_return_rsp};
use linked_list_allocator::LockedHeap;
/// Global heap allocator
///
/// Available after `memory::init()`.

View File

@ -1,6 +1,6 @@
use thread;
use alloc::VecDeque;
use super::SpinNoIrqLock;
use super::*;
use thread;
pub struct Condvar {
wait_queue: SpinNoIrqLock<VecDeque<thread::Thread>>,
@ -10,10 +10,18 @@ impl Condvar {
pub fn new() -> Self {
Condvar { wait_queue: SpinNoIrqLock::new(VecDeque::new()) }
}
pub fn wait(&self) {
pub fn _wait(&self) {
self.wait_queue.lock().push_back(thread::current());
thread::park();
}
pub fn wait<'a, T, S>(&self, guard: MutexGuard<'a, T, S>) -> MutexGuard<'a, T, S>
where S: MutexSupport
{
let mutex = guard.mutex;
drop(guard);
self._wait();
mutex.lock()
}
pub fn notify_one(&self) {
if let Some(t) = self.wait_queue.lock().pop_front() {
t.unpark();

View File

@ -49,9 +49,7 @@ pub struct Mutex<T: ?Sized, S: MutexSupport>
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T: ?Sized + 'a, S: MutexSupport + 'a>
{
lock: &'a AtomicBool,
data: &'a mut T,
support: &'a S,
pub(super) mutex: &'a Mutex<T, S>,
support_guard: S::GuardData,
}
@ -126,9 +124,7 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
let support_guard = S::before_lock();
self.obtain_lock();
MutexGuard {
lock: &self.lock,
data: unsafe { &mut *self.data.get() },
support: &self.support,
mutex: self,
support_guard,
}
}
@ -150,9 +146,7 @@ impl<T: ?Sized, S: MutexSupport> Mutex<T, S>
let support_guard = S::before_lock();
if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false {
Some(MutexGuard {
lock: &self.lock,
data: unsafe { &mut *self.data.get() },
support: &self.support,
mutex: self,
support_guard,
})
} else {
@ -180,20 +174,20 @@ impl<T: ?Sized + Default, S: MutexSupport> Default for Mutex<T, S> {
impl<'a, T: ?Sized, S: MutexSupport> Deref for MutexGuard<'a, T, S>
{
type Target = T;
fn deref<'b>(&'b self) -> &'b T { &*self.data }
fn deref<'b>(&'b self) -> &'b T { unsafe { &*self.mutex.data.get() } }
}
impl<'a, T: ?Sized, S: MutexSupport> DerefMut for MutexGuard<'a, T, S>
{
fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
fn deref_mut<'b>(&'b mut self) -> &'b mut T { unsafe { &mut *self.mutex.data.get() } }
}
impl<'a, T: ?Sized, S: MutexSupport> Drop for MutexGuard<'a, T, S>
{
/// The dropping of the MutexGuard will release the lock it was created from.
fn drop(&mut self) {
self.lock.store(false, Ordering::Release);
self.support.after_unlock();
self.mutex.lock.store(false, Ordering::Release);
self.mutex.support.after_unlock();
}
}
@ -257,7 +251,7 @@ impl MutexSupport for Condvar {
Condvar::new()
}
fn cpu_relax(&self) {
self.wait();
self._wait();
}
fn before_lock() -> Self::GuardData {}
fn after_unlock(&self) {

View File

@ -1,9 +1,9 @@
//! A counting, blocking, semaphore.
//!
//! Borrowed from std at rust 1.7.0
//! Same as [std::sync::Semaphore at rust 1.7.0](https://docs.rs/std-semaphore/0.1.0/std_semaphore/)
use super::SpinNoIrqLock as Mutex;
use super::Condvar;
use super::SpinNoIrqLock as Mutex;
/// A counting, blocking, semaphore.
pub struct Semaphore {
@ -38,10 +38,7 @@ impl Semaphore {
pub fn acquire(&self) {
let mut count = self.lock.lock();
while *count <= 0 {
// TODO: -> cvar.wait(count)
drop(count);
self.cvar.wait();
count = self.lock.lock();
count = self.cvar.wait(count);
}
*count -= 1;
}

View File

@ -2,10 +2,11 @@
//!
//! The code is borrowed from [RustDoc - Dining Philosophers](https://doc.rust-lang.org/1.6.0/book/dining-philosophers.html)
use thread;
use core::time::Duration;
use alloc::{arc::Arc, Vec};
use core::time::Duration;
use sync::Condvar;
use sync::ThreadLock as Mutex;
use thread;
struct Philosopher {
name: &'static str,
@ -22,12 +23,8 @@ impl Philosopher {
}
}
fn eat(&self, table: &Table) {
let _left = table.forks[self.left].lock();
let _right = table.forks[self.right].lock();
println!("{} is eating.", self.name);
thread::sleep(Duration::from_secs(1));
fn eat(&self, table: &Arc<Table>) {
table.eat(self.name, self.left, self.right);
}
fn think(&self) {
@ -36,21 +33,55 @@ impl Philosopher {
}
}
struct Table {
trait Table: Send + Sync {
fn eat(&self, name: &str, left: usize, right: usize);
}
struct MutexTable {
forks: Vec<Mutex<()>>,
}
pub fn philosopher() {
let table = Arc::new(Table {
forks: vec![
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
Mutex::new(()),
]
});
impl Table for MutexTable {
fn eat(&self, name: &str, left: usize, right: usize) {
let _left = self.forks[left].lock();
let _right = self.forks[right].lock();
println!("{} is eating.", name);
thread::sleep(Duration::from_secs(1));
}
}
struct MonitorTable {
fork_status: Mutex<Vec<bool>>,
fork_condvar: Vec<Condvar>,
}
impl Table for MonitorTable {
fn eat(&self, name: &str, left: usize, right: usize) {
{
let mut fork_status = self.fork_status.lock();
if fork_status[left] {
fork_status = self.fork_condvar[left].wait(fork_status);
}
fork_status[left] = true;
if fork_status[right] {
fork_status = self.fork_condvar[right].wait(fork_status);
}
fork_status[right] = true;
}
println!("{} is eating.", name);
thread::sleep(Duration::from_secs(1));
{
let mut fork_status = self.fork_status.lock();
fork_status[left] = false;
fork_status[right] = false;
self.fork_condvar[left].notify_one();
self.fork_condvar[right].notify_one();
}
}
}
fn philosopher(table: Arc<Table>) {
let philosophers = vec![
Philosopher::new("1", 0, 1),
Philosopher::new("2", 1, 2),
@ -76,3 +107,22 @@ pub fn philosopher() {
}
println!("philosophers dining end");
}
pub fn philosopher_using_mutex() {
println!("philosophers using mutex");
let table = Arc::new(MutexTable {
forks: vec![Mutex::new(()), Mutex::new(()), Mutex::new(()), Mutex::new(()), Mutex::new(())]
});
philosopher(table);
}
pub fn philosopher_using_monitor() {
println!("philosophers using monitor");
let table = Arc::new(MonitorTable {
fork_status: Mutex::new(vec![false; 5]),
fork_condvar: vec![Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new(), Condvar::new()],
});
philosopher(table);
}