feature: Ctrl+C signal to foreground pgid

This commit is contained in:
Mark Poliakov 2021-11-23 14:16:37 +02:00
parent 349418ed36
commit a7d89158cb
16 changed files with 340 additions and 122 deletions

View File

@ -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!(

View File

@ -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(

View File

@ -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"),
} }
} }

View File

@ -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);

View File

@ -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,
} }
} }

View File

@ -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 {

View File

@ -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();

View File

@ -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();

View File

@ -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 => {

View File

@ -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

View File

@ -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) })
}

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -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::*;

View File

@ -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();

View File

@ -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
} }