feature: Ctrl+C signal to foreground pgid
This commit is contained in:
parent
349418ed36
commit
a7d89158cb
@ -149,7 +149,11 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) {
|
|||||||
|
|
||||||
if sched::is_ready() {
|
if sched::is_ready() {
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
errorln!("Unhandled exception in thread {}, {:?}", thread.id(), thread.owner().map(|e| e.id()));
|
errorln!(
|
||||||
|
"Unhandled exception in thread {}, {:?}",
|
||||||
|
thread.id(),
|
||||||
|
thread.owner().map(|e| e.id())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
errorln!(
|
errorln!(
|
||||||
|
@ -86,9 +86,7 @@ impl IntController for Gic {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.scheduler_irq.0 == irq_number {
|
gicc.clear_irq(irq_number as u32, ic);
|
||||||
gicc.clear_irq(irq_number as u32, ic);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let table = self.table.lock();
|
let table = self.table.lock();
|
||||||
@ -100,8 +98,6 @@ impl IntController for Gic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gicc.clear_irq(irq_number as u32, ic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_handler(
|
fn register_handler(
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
//! Teletype (TTY) device facilities
|
//! Teletype (TTY) device facilities
|
||||||
use crate::dev::serial::SerialDevice;
|
use crate::dev::serial::SerialDevice;
|
||||||
use crate::proc::wait::{Wait, WAIT_SELECT};
|
use crate::proc::{Process, wait::{Wait, WAIT_SELECT}};
|
||||||
use crate::sync::IrqSafeSpinLock;
|
use crate::sync::IrqSafeSpinLock;
|
||||||
use libsys::error::Errno;
|
use libsys::error::Errno;
|
||||||
use libsys::{
|
use libsys::{
|
||||||
termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag},
|
termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag},
|
||||||
|
proc::Pid,
|
||||||
|
signal::Signal,
|
||||||
ioctl::IoctlCmd
|
ioctl::IoctlCmd
|
||||||
};
|
};
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
@ -16,6 +18,7 @@ struct CharRingInner<const N: usize> {
|
|||||||
wr: usize,
|
wr: usize,
|
||||||
data: [u8; N],
|
data: [u8; N],
|
||||||
flags: u8,
|
flags: u8,
|
||||||
|
fg_pgid: Option<Pid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ring buffer for TTYs
|
/// Ring buffer for TTYs
|
||||||
@ -54,6 +57,11 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
|
|||||||
*self.ring().config.lock() = src.clone();
|
*self.ring().config.lock() = src.clone();
|
||||||
Ok(size_of::<Termios>())
|
Ok(size_of::<Termios>())
|
||||||
},
|
},
|
||||||
|
IoctlCmd::TtySetPgrp => {
|
||||||
|
let src = arg::struct_ref::<u32>(ptr)?;
|
||||||
|
self.ring().inner.lock().fg_pgid = Some(unsafe { Pid::from_raw(*src) });
|
||||||
|
Ok(0)
|
||||||
|
},
|
||||||
_ => Err(Errno::InvalidArgument)
|
_ => Err(Errno::InvalidArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +118,19 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if byte == 0x3 && config.lflag.contains(TermiosLflag::ISIG) {
|
||||||
|
drop(config);
|
||||||
|
let pgid = ring.inner.lock().fg_pgid;
|
||||||
|
if let Some(pgid) = pgid {
|
||||||
|
// TODO send to pgid
|
||||||
|
let proc = Process::get(pgid);
|
||||||
|
if let Some(proc) = proc {
|
||||||
|
proc.set_signal(Signal::Interrupt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.ring().putc(byte, false).ok();
|
self.ring().putc(byte, false).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,14 +253,15 @@ impl<const N: usize> CharRing<N> {
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: IrqSafeSpinLock::new(CharRingInner {
|
inner: IrqSafeSpinLock::new(CharRingInner {
|
||||||
|
fg_pgid: None,
|
||||||
rd: 0,
|
rd: 0,
|
||||||
wr: 0,
|
wr: 0,
|
||||||
data: [0; N],
|
data: [0; N],
|
||||||
flags: 0,
|
flags: 0,
|
||||||
}),
|
}),
|
||||||
config: IrqSafeSpinLock::new(Termios::new()),
|
config: IrqSafeSpinLock::new(Termios::new()),
|
||||||
wait_read: Wait::new(),
|
wait_read: Wait::new("tty_read"),
|
||||||
wait_write: Wait::new(),
|
wait_write: Wait::new("tty_write"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
|
|||||||
io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
||||||
io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
||||||
io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
||||||
|
io.set_ctty(tty_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(cfg);
|
drop(cfg);
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
//! Process file descriptors and I/O context
|
//! Process file descriptors and I/O context
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use libsys::{error::Errno, stat::FileDescriptor};
|
use libsys::{error::Errno, stat::FileDescriptor};
|
||||||
use vfs::{FileRef, Ioctx};
|
use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind};
|
||||||
|
|
||||||
/// Process I/O context. Contains file tables, root/cwd info etc.
|
/// Process I/O context. Contains file tables, root/cwd info etc.
|
||||||
pub struct ProcessIo {
|
pub struct ProcessIo {
|
||||||
ioctx: Option<Ioctx>,
|
ioctx: Option<Ioctx>,
|
||||||
files: BTreeMap<u32, FileRef>,
|
files: BTreeMap<u32, FileRef>,
|
||||||
|
ctty: Option<VnodeRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessIo {
|
impl ProcessIo {
|
||||||
@ -21,6 +22,15 @@ impl ProcessIo {
|
|||||||
Ok(dst)
|
Ok(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_ctty(&mut self, node: VnodeRef) {
|
||||||
|
assert_eq!(node.kind(), VnodeKind::Char);
|
||||||
|
self.ctty = Some(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ctty(&mut self) -> Option<VnodeRef> {
|
||||||
|
self.ctty.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns [File] struct referred to by file descriptor `idx`
|
/// Returns [File] struct referred to by file descriptor `idx`
|
||||||
pub fn file(&mut self, fd: FileDescriptor) -> Result<FileRef, Errno> {
|
pub fn file(&mut self, fd: FileDescriptor) -> Result<FileRef, Errno> {
|
||||||
self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile)
|
self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile)
|
||||||
@ -54,6 +64,7 @@ impl ProcessIo {
|
|||||||
Self {
|
Self {
|
||||||
files: BTreeMap::new(),
|
files: BTreeMap::new(),
|
||||||
ioctx: None,
|
ioctx: None,
|
||||||
|
ctty: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use libsys::{
|
|||||||
proc::{ExitCode, Pid},
|
proc::{ExitCode, Pid},
|
||||||
signal::Signal,
|
signal::Signal,
|
||||||
};
|
};
|
||||||
|
use vfs::{VnodeRef, VnodeKind};
|
||||||
|
|
||||||
/// Wrapper type for a process struct reference
|
/// Wrapper type for a process struct reference
|
||||||
pub type ProcessRef = Rc<Process>;
|
pub type ProcessRef = Rc<Process>;
|
||||||
@ -33,6 +34,9 @@ struct ProcessInner {
|
|||||||
space: Option<&'static mut Space>,
|
space: Option<&'static mut Space>,
|
||||||
state: ProcessState,
|
state: ProcessState,
|
||||||
id: Pid,
|
id: Pid,
|
||||||
|
pgid: Pid,
|
||||||
|
ppid: Option<Pid>,
|
||||||
|
sid: Pid,
|
||||||
exit: Option<ExitCode>,
|
exit: Option<ExitCode>,
|
||||||
threads: Vec<u32>,
|
threads: Vec<u32>,
|
||||||
}
|
}
|
||||||
@ -56,6 +60,25 @@ impl Process {
|
|||||||
self.inner.lock().id
|
self.inner.lock().id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn sid(&self) -> Pid {
|
||||||
|
self.inner.lock().sid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn pgid(&self) -> Pid {
|
||||||
|
self.inner.lock().pgid
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ppid(&self) -> Option<Pid> {
|
||||||
|
self.inner.lock().ppid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pgid(&self, pgid: Pid) {
|
||||||
|
self.inner.lock().pgid = pgid;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current() -> ProcessRef {
|
pub fn current() -> ProcessRef {
|
||||||
Thread::current().owner().unwrap()
|
Thread::current().owner().unwrap()
|
||||||
@ -75,6 +98,9 @@ impl Process {
|
|||||||
let mut inner = ProcessInner {
|
let mut inner = ProcessInner {
|
||||||
threads: Vec::new(),
|
threads: Vec::new(),
|
||||||
id,
|
id,
|
||||||
|
pgid: id,
|
||||||
|
ppid: None,
|
||||||
|
sid: id,
|
||||||
exit: None,
|
exit: None,
|
||||||
space: None,
|
space: None,
|
||||||
state: ProcessState::Active,
|
state: ProcessState::Active,
|
||||||
@ -82,7 +108,7 @@ impl Process {
|
|||||||
inner.threads.push(thread.id());
|
inner.threads.push(thread.id());
|
||||||
|
|
||||||
let res = Rc::new(Self {
|
let res = Rc::new(Self {
|
||||||
exit_wait: Wait::new(),
|
exit_wait: Wait::new("process_exit"),
|
||||||
io: IrqSafeSpinLock::new(ProcessIo::new()),
|
io: IrqSafeSpinLock::new(ProcessIo::new()),
|
||||||
signal_state: AtomicU32::new(0),
|
signal_state: AtomicU32::new(0),
|
||||||
inner: IrqSafeSpinLock::new(inner),
|
inner: IrqSafeSpinLock::new(inner),
|
||||||
@ -107,8 +133,11 @@ impl Process {
|
|||||||
|
|
||||||
/// Sets a pending signal for a process
|
/// Sets a pending signal for a process
|
||||||
pub fn set_signal(&self, signal: Signal) {
|
pub fn set_signal(&self, signal: Signal) {
|
||||||
let lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
|
let ttbr0 =
|
||||||
|
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||||
|
drop(lock);
|
||||||
|
|
||||||
// TODO check that `signal` is not a fault signal
|
// TODO check that `signal` is not a fault signal
|
||||||
// it is illegal to call this function with
|
// it is illegal to call this function with
|
||||||
@ -116,14 +145,15 @@ impl Process {
|
|||||||
|
|
||||||
match main_thread.state() {
|
match main_thread.state() {
|
||||||
ThreadState::Running => {
|
ThreadState::Running => {
|
||||||
Process::enter_signal_on(lock, main_thread, signal);
|
main_thread.enter_signal(signal, ttbr0);
|
||||||
}
|
}
|
||||||
ThreadState::Waiting => {
|
ThreadState::Waiting => {
|
||||||
// TODO abort whatever the process is waiting for
|
main_thread.clone().setup_signal(signal, ttbr0);
|
||||||
todo!()
|
main_thread.interrupt_wait(true);
|
||||||
}
|
}
|
||||||
ThreadState::Ready => {
|
ThreadState::Ready => {
|
||||||
todo!()
|
main_thread.clone().setup_signal(signal, ttbr0);
|
||||||
|
main_thread.interrupt_wait(false);
|
||||||
}
|
}
|
||||||
ThreadState::Finished => {
|
ThreadState::Finished => {
|
||||||
// TODO report error back
|
// TODO report error back
|
||||||
@ -132,20 +162,11 @@ impl Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_signal_on(
|
|
||||||
mut inner: IrqSafeSpinLockGuard<ProcessInner>,
|
|
||||||
thread: ThreadRef,
|
|
||||||
signal: Signal,
|
|
||||||
) {
|
|
||||||
let ttbr0 =
|
|
||||||
inner.space.as_mut().unwrap().address_phys() | ((inner.id.asid() as usize) << 48);
|
|
||||||
drop(inner);
|
|
||||||
thread.enter_signal(signal, ttbr0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||||
let lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
Process::enter_signal_on(lock, thread, signal);
|
let ttbr0 =
|
||||||
|
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||||
|
thread.enter_signal(signal, ttbr0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<u32, Errno> {
|
pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<u32, Errno> {
|
||||||
@ -178,7 +199,7 @@ impl Process {
|
|||||||
threads.push(tid);
|
threads.push(tid);
|
||||||
|
|
||||||
let dst = Rc::new(Self {
|
let dst = Rc::new(Self {
|
||||||
exit_wait: Wait::new(),
|
exit_wait: Wait::new("process_exit"),
|
||||||
io: IrqSafeSpinLock::new(src_io.fork()?),
|
io: IrqSafeSpinLock::new(src_io.fork()?),
|
||||||
signal_state: AtomicU32::new(0),
|
signal_state: AtomicU32::new(0),
|
||||||
inner: IrqSafeSpinLock::new(ProcessInner {
|
inner: IrqSafeSpinLock::new(ProcessInner {
|
||||||
@ -187,6 +208,9 @@ impl Process {
|
|||||||
space: Some(dst_space),
|
space: Some(dst_space),
|
||||||
state: ProcessState::Active,
|
state: ProcessState::Active,
|
||||||
id: dst_id,
|
id: dst_id,
|
||||||
|
pgid: src_inner.pgid,
|
||||||
|
ppid: Some(src_inner.id),
|
||||||
|
sid: src_inner.sid
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -198,15 +222,11 @@ impl Process {
|
|||||||
Ok(dst_id)
|
Ok(dst_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO a way to terminate a single thread?
|
|
||||||
/// Terminates a process.
|
/// Terminates a process.
|
||||||
pub fn exit(status: ExitCode) {
|
pub fn exit(self: ProcessRef, status: ExitCode) {
|
||||||
unsafe {
|
|
||||||
asm!("msr daifclr, #0xF");
|
|
||||||
}
|
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
let process = thread.owner().unwrap();
|
let mut lock = self.inner.lock();
|
||||||
let mut lock = process.inner.lock();
|
let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false);
|
||||||
|
|
||||||
infoln!("Process {:?} is exiting: {:?}", lock.id, status);
|
infoln!("Process {:?} is exiting: {:?}", lock.id, status);
|
||||||
assert!(lock.exit.is_none());
|
assert!(lock.exit.is_none());
|
||||||
@ -214,11 +234,9 @@ impl Process {
|
|||||||
lock.state = ProcessState::Finished;
|
lock.state = ProcessState::Finished;
|
||||||
|
|
||||||
for &tid in lock.threads.iter() {
|
for &tid in lock.threads.iter() {
|
||||||
debugln!("Dequeue {:?}", tid);
|
|
||||||
Thread::get(tid).unwrap().terminate(status);
|
Thread::get(tid).unwrap().terminate(status);
|
||||||
SCHED.dequeue(tid);
|
SCHED.dequeue(tid);
|
||||||
}
|
}
|
||||||
SCHED.debug();
|
|
||||||
|
|
||||||
if let Some(space) = lock.space.take() {
|
if let Some(space) = lock.space.take() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -227,13 +245,16 @@ impl Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process.io.lock().handle_exit();
|
self.io.lock().handle_exit();
|
||||||
|
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
process.exit_wait.wakeup_all();
|
self.exit_wait.wakeup_all();
|
||||||
SCHED.switch(true);
|
|
||||||
panic!("This code should never run");
|
if is_running {
|
||||||
|
SCHED.switch(true);
|
||||||
|
panic!("This code should never run");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
|
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
|
||||||
@ -246,8 +267,8 @@ impl Process {
|
|||||||
if lock.threads.len() == 1 {
|
if lock.threads.len() == 1 {
|
||||||
// TODO call Process::exit instead?
|
// TODO call Process::exit instead?
|
||||||
drop(lock);
|
drop(lock);
|
||||||
Process::exit(status);
|
process.exit(status);
|
||||||
panic!();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.threads.retain(|&e| e != tid);
|
lock.threads.retain(|&e| e != tid);
|
||||||
@ -291,7 +312,6 @@ impl Process {
|
|||||||
if let Some(r) = proc.collect() {
|
if let Some(r) = proc.collect() {
|
||||||
// TODO drop the process struct itself
|
// TODO drop the process struct itself
|
||||||
PROCESSES.lock().remove(&proc.id());
|
PROCESSES.lock().remove(&proc.id());
|
||||||
debugln!("pid {:?} has {} refs", proc.id(), Rc::strong_count(&proc));
|
|
||||||
return Ok(r);
|
return Ok(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +347,8 @@ impl Process {
|
|||||||
let r = processes.remove(&old_pid);
|
let r = processes.remove(&old_pid);
|
||||||
assert!(r.is_some());
|
assert!(r.is_some());
|
||||||
process_lock.id = new_pid;
|
process_lock.id = new_pid;
|
||||||
|
process_lock.pgid = new_pid;
|
||||||
|
process_lock.sid = new_pid;
|
||||||
let r = processes.insert(new_pid, proc.clone());
|
let r = processes.insert(new_pid, proc.clone());
|
||||||
assert!(r.is_none());
|
assert!(r.is_none());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::arch::aarch64::exception::ExceptionFrame;
|
use crate::arch::aarch64::exception::ExceptionFrame;
|
||||||
use crate::proc::{wait::Wait, Process, ProcessRef, SCHED, THREADS};
|
use crate::proc::{wait::{Wait, WaitStatus}, Process, ProcessRef, SCHED, THREADS};
|
||||||
use crate::sync::IrqSafeSpinLock;
|
use crate::sync::IrqSafeSpinLock;
|
||||||
use crate::util::InitOnce;
|
use crate::util::InitOnce;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
@ -33,7 +33,7 @@ struct ThreadInner {
|
|||||||
state: State,
|
state: State,
|
||||||
owner: Option<Pid>,
|
owner: Option<Pid>,
|
||||||
pending_wait: Option<&'static Wait>,
|
pending_wait: Option<&'static Wait>,
|
||||||
wait_flag: bool,
|
wait_status: WaitStatus,
|
||||||
signal_entry: usize,
|
signal_entry: usize,
|
||||||
signal_stack: usize,
|
signal_stack: usize,
|
||||||
}
|
}
|
||||||
@ -63,6 +63,10 @@ impl Thread {
|
|||||||
self.inner.lock().owner.and_then(Process::get)
|
self.inner.lock().owner.and_then(Process::get)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn owner_id(&self) -> Option<Pid> {
|
||||||
|
self.inner.lock().owner
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new kernel process
|
/// Creates a new kernel process
|
||||||
pub fn new_kernel(
|
pub fn new_kernel(
|
||||||
owner: Option<Pid>,
|
owner: Option<Pid>,
|
||||||
@ -75,7 +79,7 @@ impl Thread {
|
|||||||
ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)),
|
ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)),
|
||||||
signal_ctx: UnsafeCell::new(Context::empty()),
|
signal_ctx: UnsafeCell::new(Context::empty()),
|
||||||
signal_pending: AtomicU32::new(0),
|
signal_pending: AtomicU32::new(0),
|
||||||
exit_wait: Wait::new(),
|
exit_wait: Wait::new("thread_exit"),
|
||||||
exit_status: InitOnce::new(),
|
exit_status: InitOnce::new(),
|
||||||
inner: IrqSafeSpinLock::new(ThreadInner {
|
inner: IrqSafeSpinLock::new(ThreadInner {
|
||||||
signal_entry: 0,
|
signal_entry: 0,
|
||||||
@ -83,7 +87,7 @@ impl Thread {
|
|||||||
id,
|
id,
|
||||||
owner,
|
owner,
|
||||||
pending_wait: None,
|
pending_wait: None,
|
||||||
wait_flag: false,
|
wait_status: WaitStatus::Done,
|
||||||
state: State::Ready,
|
state: State::Ready,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@ -106,7 +110,7 @@ impl Thread {
|
|||||||
ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)),
|
ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)),
|
||||||
signal_ctx: UnsafeCell::new(Context::empty()),
|
signal_ctx: UnsafeCell::new(Context::empty()),
|
||||||
signal_pending: AtomicU32::new(0),
|
signal_pending: AtomicU32::new(0),
|
||||||
exit_wait: Wait::new(),
|
exit_wait: Wait::new("thread_exit"),
|
||||||
exit_status: InitOnce::new(),
|
exit_status: InitOnce::new(),
|
||||||
inner: IrqSafeSpinLock::new(ThreadInner {
|
inner: IrqSafeSpinLock::new(ThreadInner {
|
||||||
signal_entry: 0,
|
signal_entry: 0,
|
||||||
@ -114,7 +118,7 @@ impl Thread {
|
|||||||
id,
|
id,
|
||||||
owner: Some(owner),
|
owner: Some(owner),
|
||||||
pending_wait: None,
|
pending_wait: None,
|
||||||
wait_flag: false,
|
wait_status: WaitStatus::Done,
|
||||||
state: State::Ready,
|
state: State::Ready,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@ -134,7 +138,7 @@ impl Thread {
|
|||||||
ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
||||||
signal_ctx: UnsafeCell::new(Context::empty()),
|
signal_ctx: UnsafeCell::new(Context::empty()),
|
||||||
signal_pending: AtomicU32::new(0),
|
signal_pending: AtomicU32::new(0),
|
||||||
exit_wait: Wait::new(),
|
exit_wait: Wait::new("thread_exit"),
|
||||||
exit_status: InitOnce::new(),
|
exit_status: InitOnce::new(),
|
||||||
inner: IrqSafeSpinLock::new(ThreadInner {
|
inner: IrqSafeSpinLock::new(ThreadInner {
|
||||||
signal_entry: 0,
|
signal_entry: 0,
|
||||||
@ -142,7 +146,7 @@ impl Thread {
|
|||||||
id,
|
id,
|
||||||
owner,
|
owner,
|
||||||
pending_wait: None,
|
pending_wait: None,
|
||||||
wait_flag: false,
|
wait_status: WaitStatus::Done,
|
||||||
state: State::Ready,
|
state: State::Ready,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@ -185,7 +189,7 @@ impl Thread {
|
|||||||
assert_eq!(src_lock.state, State::Running);
|
assert_eq!(src_lock.state, State::Running);
|
||||||
src_lock.state = State::Ready;
|
src_lock.state = State::Ready;
|
||||||
}
|
}
|
||||||
assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting);
|
// assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting);
|
||||||
dst_lock.state = State::Running;
|
dst_lock.state = State::Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +227,7 @@ impl Thread {
|
|||||||
let mut lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
// FIXME this is not cool
|
// FIXME this is not cool
|
||||||
lock.pending_wait = Some(unsafe { &*wait });
|
lock.pending_wait = Some(unsafe { &*wait });
|
||||||
lock.wait_flag = true;
|
lock.wait_status = WaitStatus::Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn waittid(tid: u32) -> Result<(), Errno> {
|
pub fn waittid(tid: u32) -> Result<(), Errno> {
|
||||||
@ -243,19 +247,19 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_wait_reached(&self) {
|
pub fn set_wait_status(&self, status: WaitStatus) {
|
||||||
let mut lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
lock.wait_flag = false;
|
lock.wait_status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_wait(&self) {
|
pub fn reset_wait(&self) {
|
||||||
let mut lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
lock.pending_wait = None;
|
lock.pending_wait = None;
|
||||||
|
lock.wait_status = WaitStatus::Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if process wait condition has not been reached
|
pub fn wait_status(&self) -> WaitStatus {
|
||||||
pub fn wait_flag(&self) -> bool {
|
self.inner.lock().wait_status
|
||||||
self.inner.lock().wait_flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switches current thread back from signal handler
|
/// Switches current thread back from signal handler
|
||||||
@ -291,8 +295,7 @@ impl Thread {
|
|||||||
lock.signal_stack = stack;
|
lock.signal_stack = stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switches process main thread to a signal handler
|
pub fn setup_signal(self: ThreadRef, signal: Signal, ttbr0: usize) {
|
||||||
pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) {
|
|
||||||
if self
|
if self
|
||||||
.signal_pending
|
.signal_pending
|
||||||
.compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed)
|
.compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed)
|
||||||
@ -305,7 +308,7 @@ impl Thread {
|
|||||||
if lock.signal_entry == 0 || lock.signal_stack == 0 {
|
if lock.signal_entry == 0 || lock.signal_stack == 0 {
|
||||||
drop(lock);
|
drop(lock);
|
||||||
Process::exit_thread(self, ExitCode::from(-1));
|
Process::exit_thread(self, ExitCode::from(-1));
|
||||||
panic!();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let signal_ctx = unsafe { &mut *self.signal_ctx.get() };
|
let signal_ctx = unsafe { &mut *self.signal_ctx.get() };
|
||||||
@ -318,7 +321,6 @@ impl Thread {
|
|||||||
lock.signal_stack,
|
lock.signal_stack,
|
||||||
ttbr0
|
ttbr0
|
||||||
);
|
);
|
||||||
assert_eq!(lock.state, State::Running);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
signal_ctx.setup_signal_entry(
|
signal_ctx.setup_signal_entry(
|
||||||
@ -329,13 +331,31 @@ impl Thread {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(lock);
|
}
|
||||||
|
|
||||||
|
/// Switches process main thread to a signal handler
|
||||||
|
pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) {
|
||||||
|
let src_ctx = self.ctx.get();
|
||||||
|
let signal_ctx = unsafe { &mut *self.signal_ctx.get() };
|
||||||
|
|
||||||
|
assert_eq!(self.state(), State::Running);
|
||||||
|
self.setup_signal(signal, ttbr0);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(&mut *src_ctx).switch(signal_ctx);
|
(&mut *src_ctx).switch(signal_ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_wait(&self, enqueue: bool) {
|
||||||
|
let mut lock = self.inner.lock();
|
||||||
|
let tid = lock.id;
|
||||||
|
let wait = lock.pending_wait.take();
|
||||||
|
drop(lock);
|
||||||
|
if let Some(wait) = wait {
|
||||||
|
wait.abort(tid, enqueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn terminate(&self, status: ExitCode) {
|
pub fn terminate(&self, status: ExitCode) {
|
||||||
let mut lock = self.inner.lock();
|
let mut lock = self.inner.lock();
|
||||||
lock.state = State::Finished;
|
lock.state = State::Finished;
|
||||||
@ -343,7 +363,7 @@ impl Thread {
|
|||||||
let wait = lock.pending_wait.take();
|
let wait = lock.pending_wait.take();
|
||||||
drop(lock);
|
drop(lock);
|
||||||
if let Some(wait) = wait {
|
if let Some(wait) = wait {
|
||||||
wait.abort(tid);
|
wait.abort(tid, false);
|
||||||
}
|
}
|
||||||
self.exit_status.init(status);
|
self.exit_status.init(status);
|
||||||
self.exit_wait.wakeup_all();
|
self.exit_wait.wakeup_all();
|
||||||
|
@ -12,6 +12,14 @@ use libsys::{error::Errno, stat::FdSet};
|
|||||||
/// waiting for some event to happen.
|
/// waiting for some event to happen.
|
||||||
pub struct Wait {
|
pub struct Wait {
|
||||||
queue: IrqSafeSpinLock<LinkedList<u32>>,
|
queue: IrqSafeSpinLock<LinkedList<u32>>,
|
||||||
|
name: &'static str
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||||
|
pub enum WaitStatus {
|
||||||
|
Pending,
|
||||||
|
Interrupted,
|
||||||
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Timeout {
|
struct Timeout {
|
||||||
@ -20,7 +28,7 @@ struct Timeout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TICK_LIST: IrqSafeSpinLock<LinkedList<Timeout>> = IrqSafeSpinLock::new(LinkedList::new());
|
static TICK_LIST: IrqSafeSpinLock<LinkedList<Timeout>> = IrqSafeSpinLock::new(LinkedList::new());
|
||||||
pub static WAIT_SELECT: Wait = Wait::new();
|
pub static WAIT_SELECT: Wait = Wait::new("select");
|
||||||
|
|
||||||
/// Checks for any timed out wait channels and interrupts them
|
/// Checks for any timed out wait channels and interrupts them
|
||||||
pub fn tick() {
|
pub fn tick() {
|
||||||
@ -42,7 +50,7 @@ pub fn tick() {
|
|||||||
/// Suspends current process for given duration
|
/// Suspends current process for given duration
|
||||||
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
|
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
|
||||||
// Dummy wait descriptor which will never receive notifications
|
// Dummy wait descriptor which will never receive notifications
|
||||||
static SLEEP_NOTIFY: Wait = Wait::new();
|
static SLEEP_NOTIFY: Wait = Wait::new("sleep");
|
||||||
let deadline = machine::local_timer().timestamp()? + timeout;
|
let deadline = machine::local_timer().timestamp()? + timeout;
|
||||||
match SLEEP_NOTIFY.wait(Some(deadline)) {
|
match SLEEP_NOTIFY.wait(Some(deadline)) {
|
||||||
Err(Errno::Interrupt) => {
|
Err(Errno::Interrupt) => {
|
||||||
@ -104,9 +112,39 @@ pub fn select(
|
|||||||
|
|
||||||
impl Wait {
|
impl Wait {
|
||||||
/// Constructs a new wait channel
|
/// Constructs a new wait channel
|
||||||
pub const fn new() -> Self {
|
pub const fn new(name: &'static str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue: IrqSafeSpinLock::new(LinkedList::new()),
|
queue: IrqSafeSpinLock::new(LinkedList::new()),
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn abort(&self, tid: u32, enqueue: bool) {
|
||||||
|
let mut queue = self.queue.lock();
|
||||||
|
let mut tick_lock = TICK_LIST.lock();
|
||||||
|
let mut cursor = tick_lock.cursor_front_mut();
|
||||||
|
while let Some(item) = cursor.current() {
|
||||||
|
if tid == item.tid {
|
||||||
|
cursor.remove_current();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
cursor.move_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cursor = queue.cursor_front_mut();
|
||||||
|
while let Some(item) = cursor.current() {
|
||||||
|
if tid == *item {
|
||||||
|
cursor.remove_current();
|
||||||
|
let thread = Thread::get(tid).unwrap();
|
||||||
|
thread.set_wait_status(WaitStatus::Interrupted);
|
||||||
|
if enqueue {
|
||||||
|
SCHED.enqueue(tid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
cursor.move_next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +167,7 @@ impl Wait {
|
|||||||
}
|
}
|
||||||
drop(tick_lock);
|
drop(tick_lock);
|
||||||
|
|
||||||
Thread::get(tid).unwrap().set_wait_reached();
|
Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done);
|
||||||
SCHED.enqueue(tid);
|
SCHED.enqueue(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,30 +187,6 @@ impl Wait {
|
|||||||
self.wakeup_some(1);
|
self.wakeup_some(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abort(&self, tid: u32) {
|
|
||||||
let mut queue = self.queue.lock();
|
|
||||||
let mut tick_lock = TICK_LIST.lock();
|
|
||||||
let mut cursor = tick_lock.cursor_front_mut();
|
|
||||||
while let Some(item) = cursor.current() {
|
|
||||||
if tid == item.tid {
|
|
||||||
cursor.remove_current();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cursor.move_next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cursor = queue.cursor_front_mut();
|
|
||||||
while let Some(item) = cursor.current() {
|
|
||||||
if tid == *item {
|
|
||||||
cursor.remove_current();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cursor.move_next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Suspends current process until event is signalled or
|
/// Suspends current process until event is signalled or
|
||||||
/// (optional) deadline is reached
|
/// (optional) deadline is reached
|
||||||
pub fn wait(&self, deadline: Option<Duration>) -> Result<(), Errno> {
|
pub fn wait(&self, deadline: Option<Duration>) -> Result<(), Errno> {
|
||||||
@ -191,9 +205,15 @@ impl Wait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if !thread.wait_flag() {
|
match thread.wait_status() {
|
||||||
return Ok(());
|
WaitStatus::Pending => {}
|
||||||
}
|
WaitStatus::Done => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
WaitStatus::Interrupted => {
|
||||||
|
return Err(Errno::Interrupt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
drop(queue_lock);
|
drop(queue_lock);
|
||||||
thread.enter_wait();
|
thread.enter_wait();
|
||||||
|
@ -52,6 +52,7 @@ fn find_at_node<T: DerefMut<Target = ProcessIo>>(
|
|||||||
|
|
||||||
/// Main system call dispatcher function
|
/// Main system call dispatcher function
|
||||||
pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||||
|
// debugln!("syscall {:?}", num);
|
||||||
match num {
|
match num {
|
||||||
// I/O
|
// I/O
|
||||||
SystemCall::Read => {
|
SystemCall::Read => {
|
||||||
@ -172,7 +173,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
if flags & (1 << 0) != 0 {
|
if flags & (1 << 0) != 0 {
|
||||||
Process::exit_thread(Thread::current(), status);
|
Process::exit_thread(Thread::current(), status);
|
||||||
} else {
|
} else {
|
||||||
Process::exit(status);
|
Process::current().exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@ -187,7 +188,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
*status = i32::from(exit);
|
*status = i32::from(exit);
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
e => e.map(|e| i32::from(e) as usize),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SystemCall::WaitTid => {
|
SystemCall::WaitTid => {
|
||||||
@ -200,7 +201,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SystemCall::GetPid => todo!(),
|
SystemCall::GetPid => Ok(Process::current().id().value() as usize),
|
||||||
SystemCall::GetTid => Ok(Thread::current().id() as usize),
|
SystemCall::GetTid => Ok(Thread::current().id() as usize),
|
||||||
SystemCall::Sleep => {
|
SystemCall::Sleep => {
|
||||||
let rem_buf = arg::option_buf_ref(args[1], size_of::<u64>() * 2)?;
|
let rem_buf = arg::option_buf_ref(args[1], size_of::<u64>() * 2)?;
|
||||||
@ -239,6 +240,68 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
|||||||
proc::switch();
|
proc::switch();
|
||||||
Ok(0)
|
Ok(0)
|
||||||
},
|
},
|
||||||
|
SystemCall::GetSid => {
|
||||||
|
// TODO handle kernel processes here?
|
||||||
|
let pid = args[0] as u32;
|
||||||
|
let current = Process::current();
|
||||||
|
let proc = if pid == 0 {
|
||||||
|
current
|
||||||
|
} else {
|
||||||
|
let pid = unsafe { Pid::from_raw(pid) };
|
||||||
|
let proc = Process::get(pid).ok_or(Errno::DoesNotExist)?;
|
||||||
|
if proc.sid() != current.sid() {
|
||||||
|
return Err(Errno::PermissionDenied)
|
||||||
|
}
|
||||||
|
proc
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(proc.sid().value() as usize)
|
||||||
|
},
|
||||||
|
SystemCall::GetPgid => {
|
||||||
|
// TODO handle kernel processes here?
|
||||||
|
let pid = args[0] as u32;
|
||||||
|
let current = Process::current();
|
||||||
|
let proc = if pid == 0 {
|
||||||
|
current
|
||||||
|
} else {
|
||||||
|
let pid = unsafe { Pid::from_raw(pid) };
|
||||||
|
Process::get(pid).ok_or(Errno::DoesNotExist)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(proc.pgid().value() as usize)
|
||||||
|
},
|
||||||
|
SystemCall::GetPpid => {
|
||||||
|
Ok(Process::current().ppid().unwrap().value() as usize)
|
||||||
|
},
|
||||||
|
SystemCall::SetSid => {
|
||||||
|
let proc = Process::current();
|
||||||
|
let mut io = proc.io.lock();
|
||||||
|
|
||||||
|
if let Some(ctty) = io.ctty() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
},
|
||||||
|
SystemCall::SetPgid => {
|
||||||
|
let pid = args[0] as u32;
|
||||||
|
let pgid = args[1] as u32;
|
||||||
|
|
||||||
|
let current = Process::current();
|
||||||
|
let proc = if pid == 0 {
|
||||||
|
current
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if pgid == 0 {
|
||||||
|
proc.set_pgid(proc.id());
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(proc.pgid().value() as usize)
|
||||||
|
},
|
||||||
|
|
||||||
// System
|
// System
|
||||||
SystemCall::GetCpuTime => {
|
SystemCall::GetCpuTime => {
|
||||||
|
@ -26,6 +26,11 @@ pub enum SystemCall {
|
|||||||
SignalReturn = 42,
|
SignalReturn = 42,
|
||||||
SendSignal = 43,
|
SendSignal = 43,
|
||||||
Yield = 44,
|
Yield = 44,
|
||||||
|
GetSid = 45,
|
||||||
|
GetPgid = 46,
|
||||||
|
GetPpid = 47,
|
||||||
|
SetSid = 48,
|
||||||
|
SetPgid = 49,
|
||||||
// System
|
// System
|
||||||
GetCpuTime = 64,
|
GetCpuTime = 64,
|
||||||
// Debugging
|
// Debugging
|
||||||
|
@ -251,14 +251,15 @@ pub fn sys_ioctl(
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn sys_ex_getcputime() -> Result<Duration, Errno> {
|
pub fn sys_ex_getcputime() -> Result<Duration, Errno> {
|
||||||
Errno::from_syscall(unsafe {
|
Errno::from_syscall(unsafe { syscall!(SystemCall::GetCpuTime) })
|
||||||
syscall!(SystemCall::GetCpuTime)
|
.map(|e| Duration::from_nanos(e as u64))
|
||||||
}).map(|e| Duration::from_nanos(e as u64))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> {
|
pub fn sys_ex_signal(entry: usize, stack: usize) -> Result<(), Errno> {
|
||||||
Errno::from_syscall_unit(unsafe { syscall!(SystemCall::SetSignalEntry, argn!(entry), argn!(stack)) })
|
Errno::from_syscall_unit(unsafe {
|
||||||
|
syscall!(SystemCall::SetSignalEntry, argn!(entry), argn!(stack))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -349,7 +350,22 @@ pub fn sys_faccessat(
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn sys_ex_gettid() -> u32 {
|
pub fn sys_ex_gettid() -> u32 {
|
||||||
unsafe {
|
unsafe { syscall!(SystemCall::GetTid) as u32 }
|
||||||
syscall!(SystemCall::GetTid) as u32
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_getpid() -> Pid {
|
||||||
|
unsafe { Pid::from_raw(syscall!(SystemCall::GetPid) as u32) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_getpgid(pid: Pid) -> Result<Pid, Errno> {
|
||||||
|
Errno::from_syscall(unsafe { syscall!(SystemCall::GetPgid, argn!(pid.value())) })
|
||||||
|
.map(|e| unsafe { Pid::from_raw(e as u32) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn sys_setpgid(pid: Pid, pgid: Pid) -> Result<Pid, Errno> {
|
||||||
|
Errno::from_syscall(unsafe { syscall!(SystemCall::SetPgid, argn!(pid.value()), argn!(pgid.value())) }).map(|e| unsafe { Pid::from_raw(e as u32) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use crate::error::Errno;
|
|||||||
pub enum IoctlCmd {
|
pub enum IoctlCmd {
|
||||||
TtySetAttributes = 1,
|
TtySetAttributes = 1,
|
||||||
TtyGetAttributes = 2,
|
TtyGetAttributes = 2,
|
||||||
|
TtySetPgrp = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u32> for IoctlCmd {
|
impl TryFrom<u32> for IoctlCmd {
|
||||||
@ -17,6 +18,7 @@ impl TryFrom<u32> for IoctlCmd {
|
|||||||
match u {
|
match u {
|
||||||
1 => Ok(Self::TtySetAttributes),
|
1 => Ok(Self::TtySetAttributes),
|
||||||
2 => Ok(Self::TtyGetAttributes),
|
2 => Ok(Self::TtyGetAttributes),
|
||||||
|
3 => Ok(Self::TtySetPgrp),
|
||||||
_ => Err(Errno::InvalidArgument)
|
_ => Err(Errno::InvalidArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
use libsys::{
|
use libsys::{
|
||||||
calls::sys_fstatat,
|
calls::{sys_fstatat, sys_ioctl},
|
||||||
stat::{FileDescriptor, Stat},
|
stat::{FileDescriptor, Stat},
|
||||||
|
ioctl::IoctlCmd,
|
||||||
|
error::Errno,
|
||||||
|
proc::Pid
|
||||||
};
|
};
|
||||||
|
use core::mem::size_of;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
@ -24,6 +28,14 @@ pub trait AsRawFd {
|
|||||||
fn as_raw_fd(&self) -> FileDescriptor;
|
fn as_raw_fd(&self) -> FileDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tcgetpgrp(fd: FileDescriptor) -> Result<Pid, Errno> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tcsetpgrp(fd: FileDescriptor, pgid: Pid) -> Result<(), Errno> {
|
||||||
|
sys_ioctl(fd, IoctlCmd::TtySetPgrp, &pgid as *const _ as usize, size_of::<Pid>()).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stat(pathname: &str) -> Result<Stat, Error> {
|
pub fn stat(pathname: &str) -> Result<Stat, Error> {
|
||||||
let mut buf = Stat::default();
|
let mut buf = Stat::default();
|
||||||
// TODO error handling
|
// TODO error handling
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pub use libsys::signal::{Signal, SignalDestination};
|
pub use libsys::signal::{Signal, SignalDestination};
|
||||||
pub use libsys::proc::ExitCode;
|
pub use libsys::proc::{self, ExitCode};
|
||||||
pub use libsys::termios;
|
pub use libsys::termios;
|
||||||
pub use libsys::abi;
|
pub use libsys::abi;
|
||||||
pub use libsys::calls::*;
|
pub use libsys::calls::*;
|
||||||
|
@ -125,7 +125,7 @@ fn main() -> i32 {
|
|||||||
|
|
||||||
// Test non-utf8 input fed into syscalls expecting strings
|
// Test non-utf8 input fed into syscalls expecting strings
|
||||||
// let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore);
|
// let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore);
|
||||||
for _ in 0..100 {
|
for _ in 0..10000 {
|
||||||
random_bytes(&mut buf);
|
random_bytes(&mut buf);
|
||||||
let mut stat = Stat::default();
|
let mut stat = Stat::default();
|
||||||
|
|
||||||
|
@ -6,19 +6,29 @@ extern crate libusr;
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::borrow::ToOwned;
|
use alloc::borrow::ToOwned;
|
||||||
use libusr::sys::{sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno};
|
|
||||||
use libusr::io::{self, Read};
|
use libusr::io::{self, Read};
|
||||||
|
use libusr::signal::{self, SignalHandler};
|
||||||
|
use libusr::sys::{
|
||||||
|
proc::Pid, sys_execve, sys_setpgid, sys_exit, sys_fork, sys_getpgid, sys_waitpid, Errno, ExitCode,
|
||||||
|
FileDescriptor, Signal,
|
||||||
|
};
|
||||||
|
|
||||||
fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
|
fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
|
||||||
let size = f.read(bytes)?;
|
let size = f.read(bytes)?;
|
||||||
Ok(if size == 0 {
|
Ok(if size == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(core::str::from_utf8(&bytes[..size]).unwrap().trim_end_matches('\n'))
|
Some(
|
||||||
|
core::str::from_utf8(&bytes[..size])
|
||||||
|
.unwrap()
|
||||||
|
.trim_end_matches('\n'),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execvp(cmd: &str) -> ! {
|
fn execvp(cmd: &str) -> ! {
|
||||||
|
let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap();
|
||||||
|
io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap();
|
||||||
sys_execve(&("/bin/".to_owned() + cmd)).unwrap();
|
sys_execve(&("/bin/".to_owned() + cmd)).unwrap();
|
||||||
sys_exit(ExitCode::from(-1));
|
sys_exit(ExitCode::from(-1));
|
||||||
}
|
}
|
||||||
@ -30,6 +40,8 @@ fn execute(line: &str) -> Result<ExitCode, Errno> {
|
|||||||
if let Some(pid) = unsafe { sys_fork()? } {
|
if let Some(pid) = unsafe { sys_fork()? } {
|
||||||
let mut status = 0;
|
let mut status = 0;
|
||||||
sys_waitpid(pid, &mut status)?;
|
sys_waitpid(pid, &mut status)?;
|
||||||
|
let pgid = sys_getpgid(unsafe { Pid::from_raw(0) }).unwrap();
|
||||||
|
io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap();
|
||||||
Ok(ExitCode::from(status))
|
Ok(ExitCode::from(status))
|
||||||
} else {
|
} else {
|
||||||
execvp(cmd);
|
execvp(cmd);
|
||||||
@ -41,18 +53,30 @@ fn main() -> i32 {
|
|||||||
let mut buf = [0; 256];
|
let mut buf = [0; 256];
|
||||||
let mut stdin = io::stdin();
|
let mut stdin = io::stdin();
|
||||||
|
|
||||||
|
signal::set_handler(Signal::Interrupt, SignalHandler::Ignore);
|
||||||
|
let pgid = sys_setpgid(unsafe { Pid::from_raw(0) }, unsafe { Pid::from_raw(0) }).unwrap();
|
||||||
|
io::tcsetpgrp(FileDescriptor::STDIN, pgid).unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("> ");
|
print!("> ");
|
||||||
let line = readline(&mut stdin, &mut buf).unwrap();
|
match readline(&mut stdin, &mut buf) {
|
||||||
if line.is_none() {
|
Ok(line) => {
|
||||||
break;
|
if line.is_none() {
|
||||||
}
|
break;
|
||||||
let line = line.unwrap().trim_start_matches(' ');
|
}
|
||||||
if line.is_empty() {
|
let line = line.unwrap().trim_start_matches(' ');
|
||||||
continue;
|
if line.is_empty() {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
execute(line).ok();
|
execute(line).ok();
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
println!("Interrupt!");
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user