mirror of
https://github.com/rcore-os/rCore.git
synced 2025-01-19 01:07:05 +04:00
Merge stdio and tty
This commit is contained in:
parent
af853431d6
commit
2a914ec011
@ -3,11 +3,9 @@
|
||||
mod fbdev;
|
||||
mod random;
|
||||
mod shm;
|
||||
mod stdio;
|
||||
mod tty;
|
||||
|
||||
pub use fbdev::*;
|
||||
pub use random::*;
|
||||
pub use shm::*;
|
||||
pub use stdio::*;
|
||||
pub use tty::*;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use core::any::Any;
|
||||
use rcore_fs::vfs::*;
|
||||
|
||||
pub use super::{STDIN, STDOUT};
|
||||
use rcore_fs::vfs::FsError::NotSupported;
|
||||
|
||||
// try to create directory under /dev
|
||||
|
@ -1,226 +0,0 @@
|
||||
//! Implement INode for Stdin & Stdout
|
||||
|
||||
use alloc::{collections::vec_deque::VecDeque, sync::Arc};
|
||||
use core::any::Any;
|
||||
|
||||
use rcore_fs::vfs::*;
|
||||
|
||||
use super::tty::TTY;
|
||||
use crate::fs::devfs::foreground_pgid;
|
||||
use crate::fs::ioctl::*;
|
||||
use crate::process::process_group;
|
||||
use crate::signal::{send_signal, Siginfo, Signal, SI_KERNEL};
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use crate::sync::{Condvar, Event, EventBus};
|
||||
use alloc::boxed::Box;
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use spin::RwLock;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stdin {
|
||||
buf: Mutex<VecDeque<u8>>,
|
||||
eventbus: Mutex<EventBus>,
|
||||
winsize: RwLock<Winsize>,
|
||||
termios: RwLock<Termois>,
|
||||
}
|
||||
|
||||
impl Stdin {
|
||||
pub fn push(&self, c: u8) {
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
if lflag.contains(LocalModes::ISIG) && [0o3, 0o34, 0o32, 0o31].contains(&(c as i32)) {
|
||||
use Signal::*;
|
||||
let foregroud_processes = process_group(foreground_pgid());
|
||||
match c as i32 {
|
||||
// INTR
|
||||
0o3 => {
|
||||
for proc in foregroud_processes {
|
||||
send_signal(
|
||||
proc,
|
||||
-1,
|
||||
Siginfo {
|
||||
signo: SIGINT as i32,
|
||||
errno: 0,
|
||||
code: SI_KERNEL,
|
||||
field: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => warn!("special char {} is unimplented", c),
|
||||
}
|
||||
} else {
|
||||
self.buf.lock().push_back(c);
|
||||
self.eventbus.lock().set(Event::READABLE);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&self) -> u8 {
|
||||
let mut buf_lock = self.buf.lock();
|
||||
let c = buf_lock.pop_front().unwrap();
|
||||
if buf_lock.len() == 0 {
|
||||
self.eventbus.lock().clear(Event::READABLE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
pub fn can_read(&self) -> bool {
|
||||
return self.buf.lock().len() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stdout {
|
||||
winsize: RwLock<Winsize>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STDIN: Arc<Stdin> = Arc::new(Stdin::default());
|
||||
pub static ref STDOUT: Arc<Stdout> = Arc::new(Stdout::default());
|
||||
}
|
||||
|
||||
impl INode for Stdin {
|
||||
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
if self.can_read() {
|
||||
buf[0] = self.pop() as u8;
|
||||
Ok(1)
|
||||
} else {
|
||||
Err(FsError::Again)
|
||||
}
|
||||
}
|
||||
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn poll(&self) -> Result<PollStatus> {
|
||||
Ok(PollStatus {
|
||||
read: self.can_read(),
|
||||
write: false,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn async_poll<'a>(
|
||||
&'a self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<PollStatus>> + Send + Sync + 'a>> {
|
||||
struct SerialFuture<'a> {
|
||||
stdin: &'a Stdin,
|
||||
};
|
||||
|
||||
impl<'a> Future for SerialFuture<'a> {
|
||||
type Output = Result<PollStatus>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
if self.stdin.can_read() {
|
||||
return Poll::Ready(self.stdin.poll());
|
||||
}
|
||||
let waker = cx.waker().clone();
|
||||
self.stdin.eventbus.lock().subscribe(Box::new({
|
||||
move |_| {
|
||||
waker.wake_by_ref();
|
||||
true
|
||||
}
|
||||
}));
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
Box::pin(SerialFuture { stdin: self })
|
||||
}
|
||||
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
match cmd as usize {
|
||||
TIOCGWINSZ => {
|
||||
let winsize = data as *mut Winsize;
|
||||
unsafe {
|
||||
*winsize = *self.winsize.read();
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
TCGETS => {
|
||||
let termois = data as *mut Termois;
|
||||
unsafe {
|
||||
*termois = *self.termios.read();
|
||||
}
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
info!("get lfags: {:?}", lflag);
|
||||
Ok(0)
|
||||
}
|
||||
TCSETS => {
|
||||
let termois = data as *const Termois;
|
||||
unsafe {
|
||||
*self.termios.write() = *termois;
|
||||
}
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
info!("set lfags: {:?}", lflag);
|
||||
Ok(0)
|
||||
}
|
||||
TIOCGPGRP => {
|
||||
// pretend to be have a tty process group
|
||||
// Get the process group ID of the foreground process group on
|
||||
// this terminal.
|
||||
// TODO: verify pointer
|
||||
unsafe { *(data as *mut u32) = 0 };
|
||||
Ok(0)
|
||||
}
|
||||
TIOCSPGRP => {
|
||||
let gid = unsafe { *(data as *const i32) };
|
||||
info!("set foreground process group id to {}", gid);
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(FsError::NotSupported),
|
||||
}
|
||||
}
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl INode for Stdout {
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
use core::str;
|
||||
// we do not care the utf-8 things, we just want to print it!
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
print!("{}", s);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn poll(&self) -> Result<PollStatus> {
|
||||
Ok(PollStatus {
|
||||
read: false,
|
||||
write: true,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
match cmd as usize {
|
||||
TIOCGWINSZ => {
|
||||
let winsize = data as *mut Winsize;
|
||||
unsafe {
|
||||
*winsize = *self.winsize.read();
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
TCSETS | TCGETS | TIOCSPGRP => {
|
||||
// pretend to be tty
|
||||
Ok(0)
|
||||
}
|
||||
TIOCGPGRP => {
|
||||
// pretend to be have a tty process group
|
||||
// TODO: verify pointer
|
||||
unsafe { *(data as *mut u32) = 0 };
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(FsError::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
@ -1,18 +1,30 @@
|
||||
use core::any::Any;
|
||||
use rcore_fs::vfs::*;
|
||||
|
||||
pub use super::{STDIN, STDOUT};
|
||||
use crate::fs::ioctl::*;
|
||||
use crate::process::Pgid;
|
||||
use crate::syscall::SysError;
|
||||
use crate::process::{process_group, Pgid};
|
||||
use crate::signal::{send_signal, Signal};
|
||||
use crate::signal::{Siginfo, SI_KERNEL};
|
||||
use crate::{sync::Event, sync::EventBus, syscall::SysError};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::VecDeque;
|
||||
use alloc::sync::Arc;
|
||||
use core::any::Any;
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::task::Context;
|
||||
use core::task::Poll;
|
||||
use rcore_fs::vfs::FsError::NotSupported;
|
||||
use spin::RwLock;
|
||||
use rcore_fs::vfs::*;
|
||||
use spin::{Mutex, RwLock};
|
||||
|
||||
/// console tty
|
||||
// Ref: [https://linux.die.net/man/4/tty]
|
||||
#[derive(Default)]
|
||||
pub struct TtyINode {
|
||||
pub foreground_pgid: RwLock<Pgid>,
|
||||
/// foreground process group
|
||||
foreground_pgid: RwLock<Pgid>,
|
||||
buf: Mutex<VecDeque<u8>>,
|
||||
eventbus: Mutex<EventBus>,
|
||||
winsize: RwLock<Winsize>,
|
||||
termios: RwLock<Termois>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -23,26 +35,107 @@ pub fn foreground_pgid() -> Pgid {
|
||||
*TTY.foreground_pgid.read()
|
||||
}
|
||||
|
||||
impl TtyINode {
|
||||
pub fn push(&self, c: u8) {
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
if lflag.contains(LocalModes::ISIG) && [0o3, 0o34, 0o32, 0o31].contains(&(c as i32)) {
|
||||
use Signal::*;
|
||||
let foregroud_processes = process_group(foreground_pgid());
|
||||
match c as i32 {
|
||||
// INTR
|
||||
0o3 => {
|
||||
for proc in foregroud_processes {
|
||||
send_signal(
|
||||
proc,
|
||||
-1,
|
||||
Siginfo {
|
||||
signo: SIGINT as i32,
|
||||
errno: 0,
|
||||
code: SI_KERNEL,
|
||||
field: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => warn!("special char {} is unimplented", c),
|
||||
}
|
||||
} else {
|
||||
self.buf.lock().push_back(c);
|
||||
self.eventbus.lock().set(Event::READABLE);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&self) -> u8 {
|
||||
let mut buf_lock = self.buf.lock();
|
||||
let c = buf_lock.pop_front().unwrap();
|
||||
if buf_lock.len() == 0 {
|
||||
self.eventbus.lock().clear(Event::READABLE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
pub fn can_read(&self) -> bool {
|
||||
return self.buf.lock().len() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl INode for TtyINode {
|
||||
/// Read bytes at `offset` into `buf`, return the number of bytes read.
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
STDIN.read_at(offset, buf)
|
||||
if self.can_read() {
|
||||
buf[0] = self.pop() as u8;
|
||||
Ok(1)
|
||||
} else {
|
||||
Err(FsError::Again)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write bytes at `offset` from `buf`, return the number of bytes written.
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
STDOUT.write_at(offset, buf)
|
||||
use core::str;
|
||||
// we do not care the utf-8 things, we just want to print it!
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
print!("{}", s);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
/// Poll the events, return a bitmap of events.
|
||||
fn poll(&self) -> Result<PollStatus> {
|
||||
Ok(PollStatus {
|
||||
read: STDIN.can_read(),
|
||||
read: self.can_read(),
|
||||
write: true,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn async_poll<'a>(
|
||||
&'a self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<PollStatus>> + Send + Sync + 'a>> {
|
||||
struct SerialFuture<'a> {
|
||||
tty: &'a TtyINode,
|
||||
};
|
||||
|
||||
impl<'a> Future for SerialFuture<'a> {
|
||||
type Output = Result<PollStatus>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
if self.tty.can_read() {
|
||||
return Poll::Ready(self.tty.poll());
|
||||
}
|
||||
let waker = cx.waker().clone();
|
||||
self.tty.eventbus.lock().subscribe(Box::new({
|
||||
move |_| {
|
||||
waker.wake_by_ref();
|
||||
true
|
||||
}
|
||||
}));
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
Box::pin(SerialFuture { tty: self })
|
||||
}
|
||||
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
let cmd = cmd as usize;
|
||||
match cmd {
|
||||
@ -58,6 +151,31 @@ impl INode for TtyINode {
|
||||
info!("tty: set foreground process group to {}", fpgid);
|
||||
Ok(0)
|
||||
}
|
||||
TIOCGWINSZ => {
|
||||
let winsize = data as *mut Winsize;
|
||||
unsafe {
|
||||
*winsize = *self.winsize.read();
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
TCGETS => {
|
||||
let termois = data as *mut Termois;
|
||||
unsafe {
|
||||
*termois = *self.termios.read();
|
||||
}
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
info!("get lfags: {:?}", lflag);
|
||||
Ok(0)
|
||||
}
|
||||
TCSETS => {
|
||||
let termois = data as *const Termois;
|
||||
unsafe {
|
||||
*self.termios.write() = *termois;
|
||||
}
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
info!("set lfags: {:?}", lflag);
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(NotSupported),
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use rcore_fs_sfs::{INodeImpl, SimpleFileSystem};
|
||||
|
||||
use self::devfs::{Fbdev, RandomINode};
|
||||
|
||||
pub use self::devfs::{ShmINode, STDIN, STDOUT, TTY};
|
||||
pub use self::devfs::{ShmINode, TTY};
|
||||
pub use self::file::*;
|
||||
pub use self::file_like::*;
|
||||
pub use self::pipe::Pipe;
|
||||
|
@ -208,14 +208,14 @@ impl Thread {
|
||||
files.insert(
|
||||
0,
|
||||
FileLike::File(FileHandle::new(
|
||||
crate::fs::STDIN.clone(),
|
||||
crate::fs::TTY.clone(),
|
||||
OpenOptions {
|
||||
read: true,
|
||||
write: false,
|
||||
append: false,
|
||||
nonblock: false,
|
||||
},
|
||||
String::from("stdin"),
|
||||
String::from("/dev/tty"),
|
||||
false,
|
||||
false,
|
||||
)),
|
||||
@ -223,14 +223,14 @@ impl Thread {
|
||||
files.insert(
|
||||
1,
|
||||
FileLike::File(FileHandle::new(
|
||||
crate::fs::STDOUT.clone(),
|
||||
crate::fs::TTY.clone(),
|
||||
OpenOptions {
|
||||
read: false,
|
||||
write: true,
|
||||
append: false,
|
||||
nonblock: false,
|
||||
},
|
||||
String::from("stdout"),
|
||||
String::from("/dev/tty"),
|
||||
false,
|
||||
false,
|
||||
)),
|
||||
@ -238,14 +238,14 @@ impl Thread {
|
||||
files.insert(
|
||||
2,
|
||||
FileLike::File(FileHandle::new(
|
||||
crate::fs::STDOUT.clone(),
|
||||
crate::fs::TTY.clone(),
|
||||
OpenOptions {
|
||||
read: false,
|
||||
write: true,
|
||||
append: false,
|
||||
nonblock: false,
|
||||
},
|
||||
String::from("stderr"),
|
||||
String::from("/dev/tty"),
|
||||
false,
|
||||
false,
|
||||
)),
|
||||
|
@ -158,7 +158,8 @@ impl TimeSpec {
|
||||
metadata.atime = now;
|
||||
metadata.mtime = now;
|
||||
metadata.ctime = now;
|
||||
inode.set_metadata(&metadata).expect("set metadata failed");
|
||||
// silently fail for device file
|
||||
inode.set_metadata(&metadata).ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,8 @@ pub fn timer() {
|
||||
pub fn serial(c: u8) {
|
||||
if c == b'\r' {
|
||||
// in linux, we use '\n' instead
|
||||
crate::fs::STDIN.push(b'\n');
|
||||
crate::fs::TTY.push(b'\n');
|
||||
} else {
|
||||
crate::fs::STDIN.push(c);
|
||||
crate::fs::TTY.push(c);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user