mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 08:06:17 +04:00
tty
This commit is contained in:
parent
d70b920b1c
commit
0d3c207cd2
@ -8,17 +8,25 @@ use rcore_fs::vfs::*;
|
||||
use crate::fs::ioctl::*;
|
||||
use crate::sync::Condvar;
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use spin::RwLock;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stdin {
|
||||
buf: Mutex<VecDeque<char>>,
|
||||
pub pushed: Condvar,
|
||||
winsize: RwLock<Winsize>,
|
||||
termios: RwLock<Termois>,
|
||||
}
|
||||
|
||||
impl Stdin {
|
||||
pub fn push(&self, c: char) {
|
||||
self.buf.lock().push_back(c);
|
||||
self.pushed.notify_one();
|
||||
let lflag = LocalModes::from_bits_truncate(self.termios.read().lflag);
|
||||
if lflag.contains(LocalModes::ISIG) && [0x3, 0o34, 0o32, 0o31].contains(&(c as i32)) {
|
||||
|
||||
} else {
|
||||
self.buf.lock().push_back(c);
|
||||
self.pushed.notify_one();
|
||||
}
|
||||
}
|
||||
pub fn pop(&self) -> char {
|
||||
#[cfg(feature = "board_k210")]
|
||||
@ -46,7 +54,9 @@ impl Stdin {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Stdout;
|
||||
pub struct Stdout {
|
||||
winsize: RwLock<Winsize>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STDIN: Arc<Stdin> = Arc::new(Stdin::default());
|
||||
@ -74,8 +84,19 @@ impl INode for Stdin {
|
||||
}
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
match cmd as usize {
|
||||
TCGETS | TCSETS | TIOCGWINSZ => {
|
||||
// pretend to be tty
|
||||
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(); }
|
||||
Ok(0)
|
||||
}
|
||||
TCSETS => {
|
||||
let termois = data as *const Termois;
|
||||
unsafe { *self.termios.write() = *termois; }
|
||||
Ok(0)
|
||||
}
|
||||
TIOCGPGRP => {
|
||||
@ -120,7 +141,12 @@ impl INode for Stdout {
|
||||
}
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
match cmd as usize {
|
||||
TCSETS | TCGETS | TIOCGWINSZ | TIOCSPGRP => {
|
||||
TIOCGWINSZ => {
|
||||
let winsize = data as *mut Winsize;
|
||||
unsafe { *winsize = *self.winsize.read(); }
|
||||
Ok(0)
|
||||
}
|
||||
TCSETS | TCGETS | TIOCSPGRP => {
|
||||
// pretend to be tty
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -2,10 +2,19 @@ use core::any::Any;
|
||||
use rcore_fs::vfs::*;
|
||||
|
||||
pub use super::{STDIN, STDOUT};
|
||||
use crate::syscall::SysError;
|
||||
use rcore_fs::vfs::FsError::NotSupported;
|
||||
use rcore_thread::std_thread::current;
|
||||
use crate::processor;
|
||||
use crate::process::current_thread;
|
||||
use spin::RwLock;
|
||||
use crate::fs::ioctl::*;
|
||||
|
||||
/// Ref: [https://linux.die.net/man/4/tty]
|
||||
// Ref: [https://linux.die.net/man/4/tty]
|
||||
#[derive(Default)]
|
||||
pub struct TtyINode;
|
||||
pub struct TtyINode {
|
||||
foreground_pgid: RwLock<i32>,
|
||||
}
|
||||
|
||||
impl INode for TtyINode {
|
||||
/// Read bytes at `offset` into `buf`, return the number of bytes read.
|
||||
@ -27,6 +36,25 @@ impl INode for TtyINode {
|
||||
})
|
||||
}
|
||||
|
||||
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
|
||||
let cmd = cmd as usize;
|
||||
match cmd {
|
||||
TIOCGPGRP => {
|
||||
// TODO: check the pointer?
|
||||
let argp = data as *mut i32; // pid_t
|
||||
unsafe { *argp = *self.foreground_pgid.read() };
|
||||
Ok(0)
|
||||
}
|
||||
TIOCSPGRP => {
|
||||
let fpgid = unsafe { *(data as *const i32) };
|
||||
*self.foreground_pgid.write() = fpgid;
|
||||
info!("tty: set foreground process group to {}", fpgid);
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get metadata of the INode
|
||||
fn metadata(&self) -> Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
|
@ -12,9 +12,11 @@ pub const F_SETLKW: usize = 7; /* Set record locking info (blocking). */
|
||||
|
||||
const F_LINUX_SPECIFIC_BASE: usize = 1024;
|
||||
|
||||
pub const FD_CLOEXEC: usize = 1;
|
||||
pub const F_DUPFD_CLOEXEC: usize = F_LINUX_SPECIFIC_BASE + 6;
|
||||
|
||||
pub const O_NONBLOCK: usize = 04000;
|
||||
pub const O_CLOEXEC: usize = 02000000; /* set close_on_exec */
|
||||
pub const O_NONBLOCK: usize = 0o4000;
|
||||
pub const O_APPEND: usize = 0o2000;
|
||||
pub const O_CLOEXEC: usize = 0o2000000; /* set close_on_exec */
|
||||
|
||||
pub const AT_SYMLINK_NOFOLLOW: usize = 0x100;
|
||||
|
@ -15,6 +15,7 @@ use crate::sync::SpinLock as Mutex;
|
||||
use crate::syscall::SysError::{EAGAIN, ESPIPE};
|
||||
use bitflags::_core::cell::Cell;
|
||||
use spin::RwLock;
|
||||
use crate::fs::fcntl::{O_NONBLOCK, O_APPEND};
|
||||
|
||||
enum Flock {
|
||||
None = 0,
|
||||
@ -92,11 +93,17 @@ impl FileHandle {
|
||||
}
|
||||
|
||||
pub fn set_options(&self, arg: usize) {
|
||||
if arg & 0x800 > 0 {
|
||||
self.description.write().options.nonblock = true;
|
||||
}
|
||||
let options = &mut self.description.write().options;
|
||||
options.nonblock = (arg & O_NONBLOCK) != 0;
|
||||
// TODO: handle append
|
||||
// options.append = (arg & O_APPEND) != 0;
|
||||
}
|
||||
|
||||
// pub fn get_options(&self) -> usize {
|
||||
// let options = self.description.read().options;
|
||||
// let mut ret = 0 as usize;
|
||||
// }
|
||||
|
||||
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let len = self.read_at(self.description.read().offset as usize, buf)?;
|
||||
self.description.write().offset += len as u64;
|
||||
|
@ -47,17 +47,12 @@ impl FileLike {
|
||||
Ok(len)
|
||||
}
|
||||
pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
|
||||
match request {
|
||||
// TODO: place flags & path in FileLike instead of FileHandle/Socket
|
||||
FIOCLEX => Ok(0),
|
||||
FIONBIO => Ok(0),
|
||||
_ => match self {
|
||||
FileLike::File(file) => file.io_control(request as u32, arg1).map_err(Into::into),
|
||||
FileLike::Socket(socket) => socket.ioctl(request, arg1, arg2, arg3),
|
||||
FileLike::EpollInstance(_) => {
|
||||
return Err(SysError::ENOSYS);
|
||||
}
|
||||
},
|
||||
match self {
|
||||
FileLike::File(file) => file.io_control(request as u32, arg1).map_err(Into::into),
|
||||
FileLike::Socket(socket) => socket.ioctl(request, arg1, arg2, arg3),
|
||||
FileLike::EpollInstance(_) => {
|
||||
return Err(SysError::ENOSYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn mmap(&mut self, area: MMapArea) -> SysResult {
|
||||
|
@ -3,6 +3,9 @@
|
||||
// higher 2 bits: 01 = write, 10 = read
|
||||
#![allow(dead_code)]
|
||||
|
||||
use bitflags::*;
|
||||
|
||||
|
||||
#[cfg(not(target_arch = "mips"))]
|
||||
pub const TCGETS: usize = 0x5401;
|
||||
#[cfg(target_arch = "mips")]
|
||||
@ -44,3 +47,62 @@ pub const FIOCLEX: usize = 0x6601;
|
||||
// rustc using pipe and ioctl pipe file with this request id
|
||||
// for non-blocking/blocking IO control setting
|
||||
pub const FIONBIO: usize = 0x5421;
|
||||
|
||||
bitflags! {
|
||||
pub struct LocalModes : u32 {
|
||||
const ISIG = 0o000001;
|
||||
const ICANON = 0o000002;
|
||||
const ECHO = 0o000010;
|
||||
const ECHOE = 0o000020;
|
||||
const ECHOK = 0o000040;
|
||||
const ECHONL = 0o000100;
|
||||
const NOFLSH = 0o000200;
|
||||
const TOSTOP = 0o000400;
|
||||
const IEXTEN = 0o100000;
|
||||
const XCASE = 0o000004;
|
||||
const ECHOCTL = 0o001000;
|
||||
const ECHOPRT = 0o002000;
|
||||
const ECHOKE = 0o004000;
|
||||
const FLUSHO = 0o010000;
|
||||
const PENDIN = 0o040000;
|
||||
const EXTPROC = 0o200000;
|
||||
}
|
||||
}
|
||||
|
||||
// Ref: https://www.man7.org/linux/man-pages/man3/termios.3.html
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Termois {
|
||||
pub iflag: u32,
|
||||
pub oflag: u32,
|
||||
pub cflag: u32,
|
||||
pub lflag: u32,
|
||||
pub line: u8,
|
||||
pub cc: [u8; 32],
|
||||
pub ispeed: u32,
|
||||
pub ospeed: u32,
|
||||
}
|
||||
|
||||
impl Default for Termois {
|
||||
fn default() -> Self {
|
||||
Termois {
|
||||
iflag: 27906,
|
||||
oflag: 5,
|
||||
cflag: 1215,
|
||||
lflag: 35387,
|
||||
line: 0,
|
||||
cc: [3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 255, 18, 15, 23, 22, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
ispeed: 0,
|
||||
ospeed: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Winsize {
|
||||
row: u16,
|
||||
ws_col: u16,
|
||||
xpixel: u16,
|
||||
ypixel: u16,
|
||||
}
|
@ -23,7 +23,7 @@ pub mod epoll;
|
||||
pub mod fcntl;
|
||||
mod file;
|
||||
mod file_like;
|
||||
mod ioctl;
|
||||
pub mod ioctl;
|
||||
mod pipe;
|
||||
mod pseudo;
|
||||
|
||||
|
@ -56,7 +56,7 @@ impl Pid {
|
||||
|
||||
/// Return whether this pid represents the init process
|
||||
pub fn is_init(&self) -> bool {
|
||||
self.0 == 0
|
||||
self.0 == 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,6 +77,7 @@ pub struct Process {
|
||||
|
||||
// relationship
|
||||
pub pid: Pid, // i.e. tgid, usually the tid of first thread
|
||||
pub pgid: i32,
|
||||
// avoid deadlock, put pid out
|
||||
pub parent: (Pid, Weak<Mutex<Process>>),
|
||||
pub children: Vec<(Pid, Weak<Mutex<Process>>)>,
|
||||
@ -141,6 +142,7 @@ impl Thread {
|
||||
semaphores: SemProc::default(),
|
||||
futexes: BTreeMap::default(),
|
||||
pid: Pid(0),
|
||||
pgid: -1, // kernel thread do not have a process?
|
||||
parent: (Pid(0), Weak::new()),
|
||||
children: Vec::new(),
|
||||
threads: Vec::new(),
|
||||
@ -333,6 +335,7 @@ impl Thread {
|
||||
futexes: BTreeMap::default(),
|
||||
semaphores: SemProc::default(),
|
||||
pid: Pid(0),
|
||||
pgid: 0,
|
||||
parent: (Pid(0), Weak::new()),
|
||||
children: Vec::new(),
|
||||
threads: Vec::new(),
|
||||
@ -363,6 +366,7 @@ impl Thread {
|
||||
futexes: BTreeMap::default(),
|
||||
semaphores: proc.semaphores.clone(),
|
||||
pid: Pid(0),
|
||||
pgid: proc.pgid,
|
||||
parent: (proc.pid.clone(), Arc::downgrade(&self.proc)),
|
||||
children: Vec::new(),
|
||||
threads: Vec::new(),
|
||||
@ -415,8 +419,8 @@ impl Process {
|
||||
fn add_to_table(mut self) -> Arc<Mutex<Self>> {
|
||||
let mut process_table = PROCESSES.write();
|
||||
|
||||
// assign pid
|
||||
let pid = (0..).find(|i| process_table.get(i).is_none()).unwrap();
|
||||
// assign pid, do not start from 0
|
||||
let pid = (1..).find(|i| process_table.get(i).is_none()).unwrap();
|
||||
self.pid = Pid(pid);
|
||||
|
||||
// put to process table
|
||||
|
@ -142,6 +142,7 @@ impl Condvar {
|
||||
let mut queue = self.wait_queue.lock();
|
||||
if let Some(t) = queue.front() {
|
||||
self.epoll_callback(t);
|
||||
// info!("nofity thread: {}", t.id());
|
||||
t.unpark();
|
||||
queue.pop_front();
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use bitvec::prelude::{BitSlice, BitVec, Lsb0};
|
||||
|
||||
use super::*;
|
||||
use crate::fs::epoll::EpollInstance;
|
||||
use crate::fs::fcntl::{O_CLOEXEC, O_NONBLOCK};
|
||||
use crate::fs::fcntl::{O_CLOEXEC, O_NONBLOCK, F_SETFD, FD_CLOEXEC};
|
||||
use crate::fs::FileLike;
|
||||
use crate::process::Process;
|
||||
use crate::syscall::SysError::{EINVAL, ESPIPE};
|
||||
@ -861,9 +861,25 @@ impl Syscall<'_> {
|
||||
"ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}",
|
||||
fd, request, arg1, arg2, arg3
|
||||
);
|
||||
let mut proc = self.process();
|
||||
let file_like = proc.get_file_like(fd)?;
|
||||
file_like.ioctl(request, arg1, arg2, arg3)
|
||||
use crate::fs::ioctl::*;
|
||||
match request {
|
||||
FIOCLEX => self.sys_fcntl(fd, F_SETFD, FD_CLOEXEC),
|
||||
FIONCLEX => self.sys_fcntl(fd, F_SETFD, 0),
|
||||
FIONBIO => {
|
||||
let data = arg1 as *const i32;
|
||||
let val = unsafe { *data };
|
||||
if val == 0 {
|
||||
self.sys_fcntl(fd, F_SETFD, 0)
|
||||
} else {
|
||||
self.sys_fcntl(fd, F_SETFD, O_NONBLOCK)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let mut proc = self.process();
|
||||
let file_like = proc.get_file_like(fd)?;
|
||||
file_like.ioctl(request, arg1, arg2, arg3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sys_chdir(&mut self, path: *const u8) -> SysResult {
|
||||
@ -1270,6 +1286,9 @@ impl Syscall<'_> {
|
||||
file.set_options(arg);
|
||||
Ok(0)
|
||||
}
|
||||
F_GETFL => {
|
||||
self.unimplemented("F_GETFL", Ok(0))
|
||||
}
|
||||
F_DUPFD_CLOEXEC => {
|
||||
info!("fcntl: dupfd_cloexec: arg: {:#x}", arg);
|
||||
// let file_like = proc.get_file_like(fd1)?.clone();
|
||||
|
@ -329,10 +329,10 @@ impl Syscall<'_> {
|
||||
SYS_SETUID => self.unimplemented("setuid", Ok(0)),
|
||||
SYS_GETEUID => self.unimplemented("geteuid", Ok(0)),
|
||||
SYS_GETEGID => self.unimplemented("getegid", Ok(0)),
|
||||
SYS_SETPGID => self.unimplemented("setpgid", Ok(0)),
|
||||
SYS_GETPPID => self.sys_getppid(),
|
||||
SYS_SETSID => self.unimplemented("setsid", Ok(0)),
|
||||
SYS_GETPGID => self.unimplemented("getpgid", Ok(0)),
|
||||
SYS_GETPGID => self.sys_getpgid(args[0]),
|
||||
SYS_SETPGID => self.sys_setpgid(args[0], args[1]),
|
||||
SYS_GETGROUPS => self.unimplemented("getgroups", Ok(0)),
|
||||
SYS_RT_SIGTIMEDWAIT => self.unimplemented("rt_sigtimedwait", Ok(0)),
|
||||
SYS_SETGROUPS => self.unimplemented("setgroups", Ok(0)),
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
use super::*;
|
||||
use crate::fs::FileLike;
|
||||
use alloc::sync::Weak;
|
||||
use crate::syscall::SysError::ESRCH;
|
||||
|
||||
impl Syscall<'_> {
|
||||
/// Fork the current process. Return the child's PID.
|
||||
@ -10,7 +12,7 @@ impl Syscall<'_> {
|
||||
let pid = new_thread.proc.lock().pid.get();
|
||||
let tid = thread_manager().add(new_thread);
|
||||
thread_manager().detach(tid);
|
||||
info!("fork: {} -> {}", thread::current().id(), pid);
|
||||
info!("fork: {} -> {}", self.thread.proc.lock().pid, pid);
|
||||
Ok(pid)
|
||||
}
|
||||
|
||||
@ -266,6 +268,43 @@ impl Syscall<'_> {
|
||||
Ok(self.process().pid.get())
|
||||
}
|
||||
|
||||
pub fn sys_getpgid(&self, mut pid: usize) -> SysResult {
|
||||
if pid == 0 {
|
||||
pid = self.process().pid.get();
|
||||
}
|
||||
info!("getpgid: get pgid of process {}", pid);
|
||||
let process_table = PROCESSES.read();
|
||||
// let process_table: BTreeMap<usize, Weak<Mutex<Process>>> = BTreeMap::new();
|
||||
let proc = process_table.get(&pid);
|
||||
if (proc.is_some()) {
|
||||
let lock = proc.unwrap().upgrade().unwrap();
|
||||
let proc = lock.lock();
|
||||
// let proc = proc.unwrap().upgrade().unwrap().lock();
|
||||
Ok(proc.pgid as usize)
|
||||
} else {
|
||||
Err(ESRCH)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sys_setpgid(&self, mut pid: usize, pgid: usize) -> SysResult {
|
||||
if pid == 0 {
|
||||
pid = self.process().pid.get();
|
||||
}
|
||||
info!("setpgid: set pgid of process {} to {}", pid, pgid);
|
||||
let process_table = PROCESSES.read();
|
||||
// let process_table: BTreeMap<usize, Weak<Mutex<Process>>> = BTreeMap::new();
|
||||
let proc = process_table.get(&pid);
|
||||
if (proc.is_some()) {
|
||||
// TODO: check process pid is the child of calling process
|
||||
let lock = proc.unwrap().upgrade().unwrap();
|
||||
let mut proc = lock.lock();
|
||||
proc.pgid = pgid as i32;
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(ESRCH)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current thread id
|
||||
pub fn sys_gettid(&mut self) -> SysResult {
|
||||
info!("gettid");
|
||||
|
@ -50,7 +50,9 @@ impl Syscall<'_> {
|
||||
*oldset = self.thread.sig_mask;
|
||||
}
|
||||
if !set.is_null() {
|
||||
let set = *unsafe { self.vm().check_read_ptr(set)? };
|
||||
// let set = *unsafe { self.vm().check_read_ptr(set)? };
|
||||
let set = unsafe { self.vm().check_read_ptr(set)? };
|
||||
let set = *set; // prevent deadlock when page fault
|
||||
const BLOCK: usize = 0;
|
||||
const UNBLOCK: usize = 1;
|
||||
const SETMASK: usize = 2;
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::arch::cpu;
|
||||
use crate::arch::interrupt::TrapFrame;
|
||||
use crate::arch::interrupt::{TrapFrame, syscall};
|
||||
use crate::consts::INFORM_PER_MSEC;
|
||||
use crate::process::*;
|
||||
use crate::sync::Condvar;
|
||||
use rcore_thread::std_thread as thread;
|
||||
use rcore_thread::std_thread::current;
|
||||
|
||||
pub static mut TICK: usize = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user