Implement user schemes. Example in pcid. Currently deadlocks in UserInner

This commit is contained in:
Jeremy Soller 2016-09-20 08:47:16 -06:00
parent c512d04378
commit 791dbfa7ad
9 changed files with 231 additions and 79 deletions

View file

@ -26,7 +26,7 @@ clean:
cargo clean --manifest-path libstd/Cargo.toml cargo clean --manifest-path libstd/Cargo.toml
cargo clean --manifest-path init/Cargo.toml cargo clean --manifest-path init/Cargo.toml
cargo clean --manifest-path ion/Cargo.toml cargo clean --manifest-path ion/Cargo.toml
cargo clean --manifest-path drivers/atkbd/Cargo.toml cargo clean --manifest-path drivers/ps2d/Cargo.toml
cargo clean --manifest-path drivers/pcid/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml
rm -rf build rm -rf build

View file

@ -2,8 +2,10 @@
extern crate syscall; extern crate syscall;
use std::fs::File;
use std::io::{Read, Write};
use std::thread; use std::thread;
use syscall::iopl; use syscall::{iopl, Packet};
use pci::{Pci, PciBar, PciClass}; use pci::{Pci, PciBar, PciClass};
@ -75,5 +77,17 @@ fn main() {
unsafe { iopl(3).unwrap() }; unsafe { iopl(3).unwrap() };
enumerate_pci(); enumerate_pci();
let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme");
loop {
let mut packet = Packet::default();
scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme");
println!("{:?}", packet);
packet.a = 0;
scheme.write(&packet).expect("pcid: failed to write responses to pci scheme");
}
}); });
} }

View file

@ -5,7 +5,7 @@ use std::thread;
use keymap; use keymap;
pub fn keyboard() { pub fn keyboard() {
let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1");
loop { loop {

View file

@ -19,6 +19,7 @@ use self::debug::DebugScheme;
use self::env::EnvScheme; use self::env::EnvScheme;
use self::initfs::InitFsScheme; use self::initfs::InitFsScheme;
use self::irq::IrqScheme; use self::irq::IrqScheme;
use self::root::RootScheme;
/// Debug scheme /// Debug scheme
pub mod debug; pub mod debug;
@ -32,6 +33,9 @@ pub mod initfs;
/// IRQ handling /// IRQ handling
pub mod irq; pub mod irq;
/// Root scheme
pub mod root;
/// Userspace schemes /// Userspace schemes
pub mod user; pub mod user;
@ -102,10 +106,11 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
/// Initialize schemes, called if needed /// Initialize schemes, called if needed
fn init_schemes() -> RwLock<SchemeList> { fn init_schemes() -> RwLock<SchemeList> {
let mut list: SchemeList = SchemeList::new(); let mut list: SchemeList = SchemeList::new();
list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug: scheme"); list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme");
list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env: scheme"); list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme");
list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs: scheme"); list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme");
list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq: scheme"); list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme");
list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme");
RwLock::new(list) RwLock::new(list)
} }

84
kernel/scheme/root.rs Normal file
View file

@ -0,0 +1,84 @@
use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::str;
use spin::RwLock;
use syscall::{Error, Result};
use scheme::{self, Scheme};
use scheme::user::{UserInner, UserScheme};
pub struct RootScheme {
next_id: AtomicUsize,
handles: RwLock<BTreeMap<usize, Arc<UserInner>>>
}
impl RootScheme {
pub fn new() -> RootScheme {
RootScheme {
next_id: AtomicUsize::new(0),
handles: RwLock::new(BTreeMap::new())
}
}
}
impl Scheme for RootScheme {
fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
let inner = {
let mut schemes = scheme::schemes_mut();
if schemes.get_name(path).is_some() {
return Err(Error::FileExists);
}
let inner = Arc::new(UserInner::new());
schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme");
inner
};
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.write().insert(id, inner);
Ok(id)
}
fn dup(&self, file: usize) -> Result<usize> {
let inner = {
let handles = self.handles.read();
let inner = handles.get(&file).ok_or(Error::BadFile)?;
inner.clone()
};
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.write().insert(id, inner);
Ok(id)
}
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
let inner = {
let handles = self.handles.read();
let inner = handles.get(&file).ok_or(Error::BadFile)?;
inner.clone()
};
inner.read(buf)
}
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
let inner = {
let handles = self.handles.read();
let inner = handles.get(&file).ok_or(Error::BadFile)?;
inner.clone()
};
inner.write(buf)
}
fn fsync(&self, _file: usize) -> Result<()> {
Ok(())
}
fn close(&self, file: usize) -> Result<()> {
self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
}
}

View file

@ -1,7 +1,8 @@
use alloc::arc::Weak;
use collections::{BTreeMap, VecDeque}; use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use core::{mem, usize}; use core::{mem, usize};
use spin::RwLock; use spin::Mutex;
use context; use context;
use syscall::{convert_to_result, Call, Error, Result}; use syscall::{convert_to_result, Call, Error, Result};
@ -18,109 +19,125 @@ pub struct Packet {
pub d: usize pub d: usize
} }
/// UserScheme has to be wrapped pub struct UserInner {
pub struct UserScheme {
next_id: AtomicUsize, next_id: AtomicUsize,
todo: RwLock<VecDeque<Packet>>, todo: Mutex<VecDeque<Packet>>,
done: RwLock<BTreeMap<usize, usize>> done: Mutex<BTreeMap<usize, usize>>
} }
impl UserScheme { impl UserInner {
fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> { pub fn new() -> UserInner {
UserInner {
next_id: AtomicUsize::new(0),
todo: Mutex::new(VecDeque::new()),
done: Mutex::new(BTreeMap::new())
}
}
pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
let id = self.next_id.fetch_add(1, Ordering::SeqCst); let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.todo.write().push_back(Packet { let packet = Packet {
id: id, id: id,
a: a as usize, a: a as usize,
b: b, b: b,
c: c, c: c,
d: d d: d
}); };
self.todo.lock().push_back(packet);
loop { loop {
if let Some(a) = self.done.write().remove(&id) { if let Some(a) = self.done.lock().remove(&id) {
return convert_to_result(a); return convert_to_result(a);
} }
unsafe { context::switch(); } unsafe { context::switch(); }
} }
} }
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
let packet_size = mem::size_of::<Packet>();
let len = buf.len()/packet_size;
if len > 0 {
loop {
let mut i = 0;
{
let mut todo = self.todo.lock();
while ! todo.is_empty() && i < len {
let packet = todo.pop_front().unwrap();
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = packet; }
i += 1;
}
}
if i > 0 {
return Ok(i * packet_size);
} else {
unsafe { context::switch(); }
}
}
} else {
Ok(0)
}
}
pub fn write(&self, buf: &[u8]) -> Result<usize> {
let packet_size = mem::size_of::<Packet>();
let len = buf.len()/packet_size;
let mut i = 0;
while i < len {
let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
self.done.lock().insert(packet.id, packet.a);
i += 1;
}
Ok(i * packet_size)
}
}
/// UserInner has to be wrapped
pub struct UserScheme {
inner: Weak<UserInner>
}
impl UserScheme {
pub fn new(inner: Weak<UserInner>) -> UserScheme {
UserScheme {
inner: inner
}
}
} }
impl Scheme for UserScheme { impl Scheme for UserScheme {
fn open(&self, path: &[u8], flags: usize) -> Result<usize> { fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
self.call(Call::Open, path.as_ptr() as usize, path.len(), flags) let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
} }
fn dup(&self, file: usize) -> Result<usize> { fn dup(&self, file: usize) -> Result<usize> {
if file == usize::MAX { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
Ok(file) inner.call(Call::Dup, file, 0, 0)
} else {
self.call(Call::Dup, file, 0, 0)
}
} }
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> { fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
if file == usize::MAX { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
let packet_size = mem::size_of::<Packet>(); inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
let len = buf.len()/packet_size;
if len > 0 {
loop {
let mut i = 0;
{
let mut todo = self.todo.write();
while ! todo.is_empty() && i < len {
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); }
i += 1;
}
}
if i > 0 {
return Ok(i * packet_size);
} else {
unsafe { context::switch(); }
}
}
} else {
Ok(0)
}
} else {
self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
}
} }
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> { fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
if file == usize::MAX { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
let packet_size = mem::size_of::<Packet>(); inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
let len = buf.len()/packet_size;
let mut i = 0;
while i < len {
let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
self.done.write().insert(packet.id, packet.a);
i += 1;
}
Ok(i * packet_size)
} else {
self.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
}
} }
fn fsync(&self, file: usize) -> Result<()> { fn fsync(&self, file: usize) -> Result<()> {
if file == usize::MAX { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
Ok(()) inner.call(Call::FSync, file, 0, 0).and(Ok(()))
} else {
self.call(Call::FSync, file, 0, 0).and(Ok(()))
}
} }
fn close(&self, file: usize) -> Result<()> { fn close(&self, file: usize) -> Result<()> {
if file == usize::MAX { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
println!("Close user scheme"); inner.call(Call::Close, file, 0, 0).and(Ok(()))
Ok(())
} else {
self.call(Call::Close, file, 0, 0).and(Ok(()))
}
} }
} }

2
libstd

@ -1 +1 @@
Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826 Subproject commit 3d771c76c4cbd82ad699c59d3bfb645556d90f39

View file

@ -3,16 +3,19 @@
pub use self::arch::*; pub use self::arch::*;
pub use self::error::*; pub use self::error::*;
pub use self::scheme::*;
#[cfg(target_arch = "x86")] #[cfg(target_arch = "x86")]
#[path="x86.rs"] #[path="x86.rs"]
pub mod arch; mod arch;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[path="x86_64.rs"] #[path="x86_64.rs"]
pub mod arch; mod arch;
pub mod error; mod error;
mod scheme;
pub const SYS_BRK: usize = 45; pub const SYS_BRK: usize = 45;
pub const SYS_CHDIR: usize = 12; pub const SYS_CHDIR: usize = 12;

29
syscall/src/scheme.rs Normal file
View file

@ -0,0 +1,29 @@
use core::ops::{Deref, DerefMut};
use core::{mem, slice};
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct Packet {
pub id: usize,
pub a: usize,
pub b: usize,
pub c: usize,
pub d: usize
}
impl Deref for Packet {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::<Packet>()) as &[u8]
}
}
}
impl DerefMut for Packet {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::<Packet>()) as &mut [u8]
}
}
}