feature: Stdin/Stdout/Stderr structs
This commit is contained in:
parent
1f204e1d4c
commit
6bb4f38edc
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -97,6 +97,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsys"
|
||||
version = "0.1.0"
|
||||
@ -108,6 +117,7 @@ dependencies = [
|
||||
name = "libusr"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libsys",
|
||||
]
|
||||
|
||||
@ -195,6 +205,12 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -7,3 +7,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libsys = { path = "../libsys", features = ["user"] }
|
||||
lazy_static = { version = "^1.4.0", features = ["spin_no_std"] }
|
||||
|
@ -1,12 +1,26 @@
|
||||
use crate::io::{AsRawFd, Error};
|
||||
use crate::os;
|
||||
use crate::trace;
|
||||
use libsys::stat::FileDescriptor;
|
||||
use crate::io;
|
||||
|
||||
pub struct File {
|
||||
fd: FileDescriptor
|
||||
fd: FileDescriptor,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn open(path: &str) -> Result<File, io::Error> {
|
||||
pub fn open(path: &str) -> Result<File, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for File {
|
||||
fn as_raw_fd(&self) -> FileDescriptor {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for File {
|
||||
fn drop(&mut self) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
use core::fmt;
|
||||
use libsys::{
|
||||
calls::{sys_fstatat, sys_write},
|
||||
stat::{Stat, FileDescriptor},
|
||||
};
|
||||
|
||||
// TODO populate this type
|
||||
pub struct Error;
|
||||
|
||||
pub fn stat(pathname: &str) -> Result<Stat, Error> {
|
||||
let mut buf = Stat::default();
|
||||
// TODO error handling
|
||||
let res = unsafe { sys_fstatat(None, pathname, &mut buf, 0).unwrap() };
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
// print!/println! group
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDOUT, format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
($($args:tt)+) => (print!("{}\n", format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprint {
|
||||
($($args:tt)+) => ($crate::io::_print($crate::sys::FileDescriptor::STDERR, format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprintln {
|
||||
($($args:tt)+) => (eprint!("{}\n", format_args!($($args)+)))
|
||||
}
|
||||
|
||||
struct BufferWriter<'a> {
|
||||
buf: &'a mut [u8],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl fmt::Write for BufferWriter<'_> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for byte in s.bytes() {
|
||||
self.buf[self.pos] = byte;
|
||||
self.pos += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _print(fd: FileDescriptor, args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
static mut BUFFER: [u8; 4096] = [0; 4096];
|
||||
let mut writer = BufferWriter {
|
||||
buf: unsafe { &mut BUFFER },
|
||||
pos: 0,
|
||||
};
|
||||
writer.write_fmt(args).ok();
|
||||
unsafe {
|
||||
sys_write(fd, &BUFFER[..writer.pos]);
|
||||
}
|
||||
}
|
35
libusr/src/io/error.rs
Normal file
35
libusr/src/io/error.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use libsys::error::Errno;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
repr: Repr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub enum ErrorKind {
|
||||
NotFound,
|
||||
PermissionDenied,
|
||||
InvalidData,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Repr {
|
||||
Os(Errno),
|
||||
Simple(ErrorKind),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub const fn new(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
repr: Repr::Simple(kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Errno> for Error {
|
||||
fn from(e: Errno) -> Self {
|
||||
Self {
|
||||
repr: Repr::Os(e)
|
||||
}
|
||||
}
|
||||
}
|
32
libusr/src/io/mod.rs
Normal file
32
libusr/src/io/mod.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use libsys::{
|
||||
calls::sys_fstatat,
|
||||
stat::{FileDescriptor, Stat},
|
||||
};
|
||||
use core::fmt;
|
||||
|
||||
mod error;
|
||||
pub use error::{Error, ErrorKind};
|
||||
mod writer;
|
||||
pub use writer::{_print};
|
||||
mod stdio;
|
||||
pub use stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
|
||||
|
||||
pub trait Read {
|
||||
fn read(&mut self, bytes: &mut [u8]) -> Result<usize, Error>;
|
||||
}
|
||||
|
||||
pub trait Write {
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<usize, Error>;
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait AsRawFd {
|
||||
fn as_raw_fd(&self) -> FileDescriptor;
|
||||
}
|
||||
|
||||
pub fn stat(pathname: &str) -> Result<Stat, Error> {
|
||||
let mut buf = Stat::default();
|
||||
// TODO error handling
|
||||
let res = sys_fstatat(None, pathname, &mut buf, 0).unwrap();
|
||||
Ok(buf)
|
||||
}
|
130
libusr/src/io/stdio.rs
Normal file
130
libusr/src/io/stdio.rs
Normal file
@ -0,0 +1,130 @@
|
||||
use libsys::{
|
||||
stat::FileDescriptor,
|
||||
calls::{sys_read, sys_write}
|
||||
};
|
||||
use crate::io::{Read, Write, Error};
|
||||
use crate::sync::{Mutex, MutexGuard};
|
||||
use core::fmt;
|
||||
|
||||
struct InputInner {
|
||||
fd: FileDescriptor
|
||||
}
|
||||
struct OutputInner {
|
||||
fd: FileDescriptor
|
||||
}
|
||||
|
||||
pub struct StdinLock<'a> {
|
||||
lock: MutexGuard<'a, InputInner>
|
||||
}
|
||||
|
||||
pub struct StdoutLock<'a> {
|
||||
lock: MutexGuard<'a, OutputInner>
|
||||
}
|
||||
|
||||
pub struct StderrLock<'a> {
|
||||
lock: MutexGuard<'a, OutputInner>
|
||||
}
|
||||
|
||||
pub struct Stdin {
|
||||
inner: &'static Mutex<InputInner>,
|
||||
}
|
||||
|
||||
pub struct Stdout {
|
||||
inner: &'static Mutex<OutputInner>
|
||||
}
|
||||
|
||||
pub struct Stderr {
|
||||
inner: &'static Mutex<OutputInner>
|
||||
}
|
||||
|
||||
// STDIN
|
||||
|
||||
impl Read for InputInner {
|
||||
fn read(&mut self, bytes: &mut [u8]) -> Result<usize, Error> {
|
||||
sys_read(self.fd, bytes).map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Stdin {
|
||||
fn read(&mut self, bytes: &mut [u8]) -> Result<usize, Error> {
|
||||
self.inner.lock().read(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// STDOUT/STDERR
|
||||
|
||||
impl fmt::Write for OutputInner {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write(s.as_bytes()).map(|_| ()).map_err(|_| todo!())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for OutputInner {
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
sys_write(self.fd, bytes).map_err(Error::from)
|
||||
}
|
||||
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> {
|
||||
fmt::Write::write_fmt(self, args).map_err(|_| todo!())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stdout {
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
self.inner.lock().write(bytes)
|
||||
}
|
||||
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> {
|
||||
self.inner.lock().write_fmt(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stderr {
|
||||
fn write(&mut self, bytes: &[u8]) -> Result<usize, Error> {
|
||||
self.inner.lock().write(bytes)
|
||||
}
|
||||
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Error> {
|
||||
self.inner.lock().write_fmt(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
pub fn lock(&self) -> StdoutLock {
|
||||
StdoutLock {
|
||||
lock: self.inner.lock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stderr {
|
||||
pub fn lock(&self) -> StderrLock {
|
||||
StderrLock {
|
||||
lock: self.inner.lock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref STDIN: Mutex<InputInner> = Mutex::new(InputInner {
|
||||
fd: FileDescriptor::STDIN
|
||||
});
|
||||
static ref STDOUT: Mutex<OutputInner> = Mutex::new(OutputInner {
|
||||
fd: FileDescriptor::STDOUT
|
||||
});
|
||||
static ref STDERR: Mutex<OutputInner> = Mutex::new(OutputInner {
|
||||
fd: FileDescriptor::STDOUT
|
||||
});
|
||||
}
|
||||
|
||||
pub fn stdin() -> Stdin {
|
||||
Stdin { inner: &STDIN }
|
||||
}
|
||||
|
||||
pub fn stdout() -> Stdout {
|
||||
Stdout { inner: &STDOUT }
|
||||
}
|
||||
|
||||
pub fn stderr() -> Stderr {
|
||||
Stderr { inner: &STDERR }
|
||||
}
|
26
libusr/src/io/writer.rs
Normal file
26
libusr/src/io/writer.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use core::fmt;
|
||||
use crate::io::{self, Write};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($args:tt)+) => ($crate::io::_print($crate::io::stdout, format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
($($args:tt)+) => (print!("{}\n", format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprint {
|
||||
($($args:tt)+) => ($crate::io::_print($crate::io::stderr, format_args!($($args)+)))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprintln {
|
||||
($($args:tt)+) => (eprint!("{}\n", format_args!($($args)+)))
|
||||
}
|
||||
|
||||
pub fn _print<T: Write>(out: fn() -> T, args: fmt::Arguments) {
|
||||
out().write_fmt(args).expect("stdout/stderr write failed");
|
||||
}
|
@ -4,24 +4,20 @@
|
||||
use core::panic::PanicInfo;
|
||||
use libsys::proc::ExitCode;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod file;
|
||||
pub mod io;
|
||||
pub mod os;
|
||||
pub mod file;
|
||||
|
||||
pub mod sys {
|
||||
pub use libsys::signal::{Signal, SignalDestination};
|
||||
pub use libsys::termios;
|
||||
pub use libsys::calls::*;
|
||||
pub use libsys::stat::{self, FileDescriptor};
|
||||
}
|
||||
pub mod sys;
|
||||
pub mod sync;
|
||||
|
||||
#[inline(never)]
|
||||
extern "C" fn _signal_handler(arg: sys::Signal) -> ! {
|
||||
trace!("Entered signal handler: arg={:?}", arg);
|
||||
unsafe {
|
||||
sys::sys_ex_sigreturn();
|
||||
}
|
||||
}
|
||||
|
||||
static mut SIGNAL_STACK: [u8; 4096] = [0; 4096];
|
||||
|
||||
@ -31,17 +27,22 @@ extern "C" fn _start(_arg: usize) -> ! {
|
||||
extern "Rust" {
|
||||
fn main() -> i32;
|
||||
}
|
||||
unsafe {
|
||||
SIGNAL_STACK[0] = 1;
|
||||
sys::sys_ex_signal(_signal_handler as usize, SIGNAL_STACK.as_ptr() as usize + 4096);
|
||||
|
||||
sys::sys_exit(ExitCode::from(main()));
|
||||
unsafe {
|
||||
sys::sys_ex_signal(
|
||||
_signal_handler as usize,
|
||||
SIGNAL_STACK.as_ptr() as usize + 4096,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let res = unsafe { main() };
|
||||
sys::sys_exit(ExitCode::from(res));
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(pi: &PanicInfo) -> ! {
|
||||
// TODO formatted messages
|
||||
// TODO print to stdout/stderr (if available)
|
||||
trace!("Panic ocurred: {}", pi);
|
||||
sys::sys_exit(ExitCode::from(-1));
|
||||
}
|
||||
|
@ -3,35 +3,6 @@ use core::fmt;
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use libsys::{ioctl::IoctlCmd, stat::FileDescriptor, termios::Termios};
|
||||
|
||||
pub fn get_tty_attrs(fd: FileDescriptor) -> Result<Termios, &'static str> {
|
||||
let mut termios = MaybeUninit::<Termios>::uninit();
|
||||
let res = sys::sys_ioctl(
|
||||
fd,
|
||||
IoctlCmd::TtyGetAttributes,
|
||||
termios.as_mut_ptr() as usize,
|
||||
size_of::<Termios>(),
|
||||
)
|
||||
.unwrap();
|
||||
if res != size_of::<Termios>() {
|
||||
return Err("Failed");
|
||||
}
|
||||
Ok(unsafe { termios.assume_init() })
|
||||
}
|
||||
|
||||
pub fn set_tty_attrs(fd: FileDescriptor, attrs: &Termios) -> Result<(), &'static str> {
|
||||
let res = sys::sys_ioctl(
|
||||
fd,
|
||||
IoctlCmd::TtySetAttributes,
|
||||
attrs as *const _ as usize,
|
||||
size_of::<Termios>(),
|
||||
)
|
||||
.unwrap();
|
||||
if res != size_of::<Termios>() {
|
||||
return Err("Failed");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trace {
|
||||
($($args:tt)+) => ($crate::os::_trace(format_args!($($args)+)))
|
||||
@ -60,7 +31,5 @@ pub fn _trace(args: fmt::Arguments) {
|
||||
pos: 0,
|
||||
};
|
||||
writer.write_fmt(args).ok();
|
||||
unsafe {
|
||||
sys::sys_ex_debug_trace(&BUFFER[..writer.pos]);
|
||||
}
|
||||
sys::sys_ex_debug_trace(unsafe { &BUFFER[..writer.pos] }).ok();
|
||||
}
|
||||
|
54
libusr/src/sync.rs
Normal file
54
libusr/src/sync.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use core::cell::UnsafeCell;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use crate::sys::RawMutex;
|
||||
|
||||
pub struct Mutex<T> {
|
||||
inner: RawMutex,
|
||||
data: UnsafeCell<T>
|
||||
}
|
||||
|
||||
pub struct MutexGuard<'a, T> {
|
||||
data: &'a mut T,
|
||||
lock: &'a RawMutex,
|
||||
}
|
||||
|
||||
impl<T> Mutex<T> {
|
||||
pub fn new(t: T) -> Self {
|
||||
Self {
|
||||
inner: RawMutex::new(),
|
||||
data: UnsafeCell::new(t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> MutexGuard<'_, T> {
|
||||
unsafe {
|
||||
self.inner.lock();
|
||||
MutexGuard {
|
||||
data: (&mut *self.data.get()),
|
||||
lock: &self.inner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.lock.release(); }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for MutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Sync for Mutex<T> {}
|
39
libusr/src/sys/mod.rs
Normal file
39
libusr/src/sys/mod.rs
Normal file
@ -0,0 +1,39 @@
|
||||
pub use libsys::signal::{Signal, SignalDestination};
|
||||
pub use libsys::termios;
|
||||
pub use libsys::calls::*;
|
||||
pub use libsys::stat::{self, FileDescriptor};
|
||||
|
||||
use core::sync::atomic::{Ordering, AtomicBool};
|
||||
|
||||
// TODO replace with a proper mutex impl
|
||||
pub(crate) struct RawMutex {
|
||||
inner: AtomicBool
|
||||
}
|
||||
|
||||
impl RawMutex {
|
||||
pub const fn new() -> Self {
|
||||
Self { inner: AtomicBool::new(false) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_lock(&self) -> bool {
|
||||
self.inner.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn is_locked(&self) -> bool {
|
||||
self.inner.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn lock(&self) {
|
||||
while !self.try_lock() {
|
||||
asm!("nop");
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn release(&self) {
|
||||
self.inner.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
@ -4,54 +4,22 @@
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
use libusr::sys::stat::{FdSet, FileDescriptor};
|
||||
use libusr::sys::{Signal, SignalDestination};
|
||||
|
||||
fn readline(fd: FileDescriptor, buf: &mut [u8]) -> Result<&str, ()> {
|
||||
// select() just for test
|
||||
loop {
|
||||
let mut rfds = FdSet::empty();
|
||||
rfds.set(fd);
|
||||
let res = unsafe {
|
||||
libusr::sys::sys_select(Some(&mut rfds), None, 1_000_000_000).unwrap()
|
||||
};
|
||||
if res == 0 {
|
||||
continue;
|
||||
}
|
||||
if !rfds.is_set(fd) {
|
||||
panic!();
|
||||
}
|
||||
|
||||
let count = unsafe { libusr::sys::sys_read(fd, buf).unwrap() };
|
||||
return core::str::from_utf8(&buf[..count as usize]).map_err(|_| ());
|
||||
}
|
||||
}
|
||||
use libusr::io::{self, Read};
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let mut buf = [0; 512];
|
||||
let mut stdin = io::stdin();
|
||||
|
||||
eprintln!("stderr test");
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
let line = readline(FileDescriptor::STDIN, &mut buf).unwrap();
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
let line = line.trim_end_matches('\n');
|
||||
|
||||
println!(":: {:?}", line);
|
||||
|
||||
if line == "test" {
|
||||
unsafe {
|
||||
libusr::sys::sys_ex_kill(SignalDestination::This, Signal::Interrupt);
|
||||
}
|
||||
trace!("Returned from signal");
|
||||
continue;
|
||||
}
|
||||
|
||||
if line == "quit" || line == "exit" {
|
||||
let count = stdin.read(&mut buf).unwrap();
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
let line = core::str::from_utf8(&buf[..count]).unwrap();
|
||||
println!("{:?}", line);
|
||||
}
|
||||
|
||||
0
|
||||
|
Loading…
x
Reference in New Issue
Block a user