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:
parent
316d32496c
commit
0b0dac3c81
39
src/lib.rs
39
src/lib.rs
@ -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()`.
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user