From a7d89158cb3ff0e9ebeb2cc03db4fdb098cccd73 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 23 Nov 2021 14:16:37 +0200 Subject: [PATCH] feature: Ctrl+C signal to foreground pgid --- kernel/src/arch/aarch64/exception.rs | 6 +- kernel/src/arch/aarch64/irq/gic/mod.rs | 6 +- kernel/src/dev/tty.rs | 28 +++++++- kernel/src/init.rs | 1 + kernel/src/proc/io.rs | 13 +++- kernel/src/proc/process.rs | 94 ++++++++++++++++---------- kernel/src/proc/thread.rs | 62 +++++++++++------ kernel/src/proc/wait.rs | 82 +++++++++++++--------- kernel/src/syscall/mod.rs | 69 ++++++++++++++++++- libsys/src/abi.rs | 5 ++ libsys/src/calls.rs | 30 ++++++-- libsys/src/ioctl.rs | 2 + libusr/src/io/mod.rs | 14 +++- libusr/src/sys/mod.rs | 2 +- user/src/fuzzy/main.rs | 2 +- user/src/shell/main.rs | 46 ++++++++++--- 16 files changed, 340 insertions(+), 122 deletions(-) diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index e9cf661..7ba09f0 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -149,7 +149,11 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) { if sched::is_ready() { 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!( diff --git a/kernel/src/arch/aarch64/irq/gic/mod.rs b/kernel/src/arch/aarch64/irq/gic/mod.rs index c2c39c8..c5366f9 100644 --- a/kernel/src/arch/aarch64/irq/gic/mod.rs +++ b/kernel/src/arch/aarch64/irq/gic/mod.rs @@ -86,9 +86,7 @@ impl IntController for Gic { 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(); @@ -100,8 +98,6 @@ impl IntController for Gic { } } } - - gicc.clear_irq(irq_number as u32, ic); } fn register_handler( diff --git a/kernel/src/dev/tty.rs b/kernel/src/dev/tty.rs index 4ab8da4..b826644 100644 --- a/kernel/src/dev/tty.rs +++ b/kernel/src/dev/tty.rs @@ -1,10 +1,12 @@ //! Teletype (TTY) device facilities 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 libsys::error::Errno; use libsys::{ termios::{Termios, TermiosIflag, TermiosLflag, TermiosOflag}, + proc::Pid, + signal::Signal, ioctl::IoctlCmd }; use core::mem::size_of; @@ -16,6 +18,7 @@ struct CharRingInner { wr: usize, data: [u8; N], flags: u8, + fg_pgid: Option, } /// Ring buffer for TTYs @@ -54,6 +57,11 @@ pub trait TtyDevice: SerialDevice { *self.ring().config.lock() = src.clone(); Ok(size_of::()) }, + IoctlCmd::TtySetPgrp => { + let src = arg::struct_ref::(ptr)?; + self.ring().inner.lock().fg_pgid = Some(unsafe { Pid::from_raw(*src) }); + Ok(0) + }, _ => Err(Errno::InvalidArgument) } } @@ -110,6 +118,19 @@ pub trait TtyDevice: 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(); } @@ -232,14 +253,15 @@ impl CharRing { pub const fn new() -> Self { Self { inner: IrqSafeSpinLock::new(CharRingInner { + fg_pgid: None, rd: 0, wr: 0, data: [0; N], flags: 0, }), config: IrqSafeSpinLock::new(Termios::new()), - wait_read: Wait::new(), - wait_write: Wait::new(), + wait_read: Wait::new("tty_read"), + wait_write: Wait::new("tty_write"), } } diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 9744253..f390019 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -54,6 +54,7 @@ pub extern "C" fn init_fn(_arg: usize) -> ! { io.set_file(FileDescriptor::STDIN, stdin).unwrap(); io.set_file(FileDescriptor::STDOUT, stdout).unwrap(); io.set_file(FileDescriptor::STDERR, stderr).unwrap(); + io.set_ctty(tty_node); } drop(cfg); diff --git a/kernel/src/proc/io.rs b/kernel/src/proc/io.rs index f60301a..c42f60f 100644 --- a/kernel/src/proc/io.rs +++ b/kernel/src/proc/io.rs @@ -1,12 +1,13 @@ //! Process file descriptors and I/O context use alloc::collections::BTreeMap; 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. pub struct ProcessIo { ioctx: Option, files: BTreeMap, + ctty: Option, } impl ProcessIo { @@ -21,6 +22,15 @@ impl ProcessIo { 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 { + self.ctty.clone() + } + /// Returns [File] struct referred to by file descriptor `idx` pub fn file(&mut self, fd: FileDescriptor) -> Result { self.files.get(&u32::from(fd)).cloned().ok_or(Errno::InvalidFile) @@ -54,6 +64,7 @@ impl ProcessIo { Self { files: BTreeMap::new(), ioctx: None, + ctty: None, } } diff --git a/kernel/src/proc/process.rs b/kernel/src/proc/process.rs index e11f518..af18b48 100644 --- a/kernel/src/proc/process.rs +++ b/kernel/src/proc/process.rs @@ -16,6 +16,7 @@ use libsys::{ proc::{ExitCode, Pid}, signal::Signal, }; +use vfs::{VnodeRef, VnodeKind}; /// Wrapper type for a process struct reference pub type ProcessRef = Rc; @@ -33,6 +34,9 @@ struct ProcessInner { space: Option<&'static mut Space>, state: ProcessState, id: Pid, + pgid: Pid, + ppid: Option, + sid: Pid, exit: Option, threads: Vec, } @@ -56,6 +60,25 @@ impl Process { 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 { + self.inner.lock().ppid + } + + pub fn set_pgid(&self, pgid: Pid) { + self.inner.lock().pgid = pgid; + } + #[inline] pub fn current() -> ProcessRef { Thread::current().owner().unwrap() @@ -75,6 +98,9 @@ impl Process { let mut inner = ProcessInner { threads: Vec::new(), id, + pgid: id, + ppid: None, + sid: id, exit: None, space: None, state: ProcessState::Active, @@ -82,7 +108,7 @@ impl Process { inner.threads.push(thread.id()); let res = Rc::new(Self { - exit_wait: Wait::new(), + exit_wait: Wait::new("process_exit"), io: IrqSafeSpinLock::new(ProcessIo::new()), signal_state: AtomicU32::new(0), inner: IrqSafeSpinLock::new(inner), @@ -107,8 +133,11 @@ impl Process { /// Sets a pending signal for a process 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(); + drop(lock); // TODO check that `signal` is not a fault signal // it is illegal to call this function with @@ -116,14 +145,15 @@ impl Process { match main_thread.state() { ThreadState::Running => { - Process::enter_signal_on(lock, main_thread, signal); + main_thread.enter_signal(signal, ttbr0); } ThreadState::Waiting => { - // TODO abort whatever the process is waiting for - todo!() + main_thread.clone().setup_signal(signal, ttbr0); + main_thread.interrupt_wait(true); } ThreadState::Ready => { - todo!() + main_thread.clone().setup_signal(signal, ttbr0); + main_thread.interrupt_wait(false); } ThreadState::Finished => { // TODO report error back @@ -132,20 +162,11 @@ impl Process { } } - fn enter_signal_on( - mut inner: IrqSafeSpinLockGuard, - 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) { - let lock = self.inner.lock(); - Process::enter_signal_on(lock, thread, signal); + let mut lock = self.inner.lock(); + 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 { @@ -178,7 +199,7 @@ impl Process { threads.push(tid); let dst = Rc::new(Self { - exit_wait: Wait::new(), + exit_wait: Wait::new("process_exit"), io: IrqSafeSpinLock::new(src_io.fork()?), signal_state: AtomicU32::new(0), inner: IrqSafeSpinLock::new(ProcessInner { @@ -187,6 +208,9 @@ impl Process { space: Some(dst_space), state: ProcessState::Active, 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) } - // TODO a way to terminate a single thread? /// Terminates a process. - pub fn exit(status: ExitCode) { - unsafe { - asm!("msr daifclr, #0xF"); - } + pub fn exit(self: ProcessRef, status: ExitCode) { let thread = Thread::current(); - let process = thread.owner().unwrap(); - let mut lock = process.inner.lock(); + let mut lock = self.inner.lock(); + let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false); infoln!("Process {:?} is exiting: {:?}", lock.id, status); assert!(lock.exit.is_none()); @@ -214,11 +234,9 @@ impl Process { lock.state = ProcessState::Finished; for &tid in lock.threads.iter() { - debugln!("Dequeue {:?}", tid); Thread::get(tid).unwrap().terminate(status); SCHED.dequeue(tid); } - SCHED.debug(); if let Some(space) = lock.space.take() { unsafe { @@ -227,13 +245,16 @@ impl Process { } } - process.io.lock().handle_exit(); + self.io.lock().handle_exit(); drop(lock); - process.exit_wait.wakeup_all(); - SCHED.switch(true); - panic!("This code should never run"); + self.exit_wait.wakeup_all(); + + if is_running { + SCHED.switch(true); + panic!("This code should never run"); + } } pub fn exit_thread(thread: ThreadRef, status: ExitCode) { @@ -246,8 +267,8 @@ impl Process { if lock.threads.len() == 1 { // TODO call Process::exit instead? drop(lock); - Process::exit(status); - panic!(); + process.exit(status); + return; } lock.threads.retain(|&e| e != tid); @@ -291,7 +312,6 @@ impl Process { if let Some(r) = proc.collect() { // TODO drop the process struct itself PROCESSES.lock().remove(&proc.id()); - debugln!("pid {:?} has {} refs", proc.id(), Rc::strong_count(&proc)); return Ok(r); } @@ -327,6 +347,8 @@ impl Process { let r = processes.remove(&old_pid); assert!(r.is_some()); process_lock.id = new_pid; + process_lock.pgid = new_pid; + process_lock.sid = new_pid; let r = processes.insert(new_pid, proc.clone()); assert!(r.is_none()); } else { diff --git a/kernel/src/proc/thread.rs b/kernel/src/proc/thread.rs index 7c23763..fb653e6 100644 --- a/kernel/src/proc/thread.rs +++ b/kernel/src/proc/thread.rs @@ -1,5 +1,5 @@ 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::util::InitOnce; use alloc::rc::Rc; @@ -33,7 +33,7 @@ struct ThreadInner { state: State, owner: Option, pending_wait: Option<&'static Wait>, - wait_flag: bool, + wait_status: WaitStatus, signal_entry: usize, signal_stack: usize, } @@ -63,6 +63,10 @@ impl Thread { self.inner.lock().owner.and_then(Process::get) } + pub fn owner_id(&self) -> Option { + self.inner.lock().owner + } + /// Creates a new kernel process pub fn new_kernel( owner: Option, @@ -75,7 +79,7 @@ impl Thread { ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -83,7 +87,7 @@ impl Thread { id, owner, pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -106,7 +110,7 @@ impl Thread { ctx: UnsafeCell::new(Context::user(entry, arg, ttbr0, stack)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -114,7 +118,7 @@ impl Thread { id, owner: Some(owner), pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -134,7 +138,7 @@ impl Thread { ctx: UnsafeCell::new(Context::fork(frame, ttbr0)), signal_ctx: UnsafeCell::new(Context::empty()), signal_pending: AtomicU32::new(0), - exit_wait: Wait::new(), + exit_wait: Wait::new("thread_exit"), exit_status: InitOnce::new(), inner: IrqSafeSpinLock::new(ThreadInner { signal_entry: 0, @@ -142,7 +146,7 @@ impl Thread { id, owner, pending_wait: None, - wait_flag: false, + wait_status: WaitStatus::Done, state: State::Ready, }), }); @@ -185,7 +189,7 @@ impl Thread { assert_eq!(src_lock.state, State::Running); 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; } @@ -223,7 +227,7 @@ impl Thread { let mut lock = self.inner.lock(); // FIXME this is not cool lock.pending_wait = Some(unsafe { &*wait }); - lock.wait_flag = true; + lock.wait_status = WaitStatus::Pending; } 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(); - lock.wait_flag = false; + lock.wait_status = status; } pub fn reset_wait(&self) { let mut lock = self.inner.lock(); lock.pending_wait = None; + lock.wait_status = WaitStatus::Done; } - /// Returns `true` if process wait condition has not been reached - pub fn wait_flag(&self) -> bool { - self.inner.lock().wait_flag + pub fn wait_status(&self) -> WaitStatus { + self.inner.lock().wait_status } /// Switches current thread back from signal handler @@ -291,8 +295,7 @@ impl Thread { lock.signal_stack = stack; } - /// Switches process main thread to a signal handler - pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { + pub fn setup_signal(self: ThreadRef, signal: Signal, ttbr0: usize) { if self .signal_pending .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 { drop(lock); Process::exit_thread(self, ExitCode::from(-1)); - panic!(); + return; } let signal_ctx = unsafe { &mut *self.signal_ctx.get() }; @@ -318,7 +321,6 @@ impl Thread { lock.signal_stack, ttbr0 ); - assert_eq!(lock.state, State::Running); unsafe { 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 { (&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) { let mut lock = self.inner.lock(); lock.state = State::Finished; @@ -343,7 +363,7 @@ impl Thread { let wait = lock.pending_wait.take(); drop(lock); if let Some(wait) = wait { - wait.abort(tid); + wait.abort(tid, false); } self.exit_status.init(status); self.exit_wait.wakeup_all(); diff --git a/kernel/src/proc/wait.rs b/kernel/src/proc/wait.rs index 5885275..de19bd2 100644 --- a/kernel/src/proc/wait.rs +++ b/kernel/src/proc/wait.rs @@ -12,6 +12,14 @@ use libsys::{error::Errno, stat::FdSet}; /// waiting for some event to happen. pub struct Wait { queue: IrqSafeSpinLock>, + name: &'static str +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum WaitStatus { + Pending, + Interrupted, + Done, } struct Timeout { @@ -20,7 +28,7 @@ struct Timeout { } static TICK_LIST: IrqSafeSpinLock> = 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 pub fn tick() { @@ -42,7 +50,7 @@ pub fn tick() { /// Suspends current process for given duration pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> { // 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; match SLEEP_NOTIFY.wait(Some(deadline)) { Err(Errno::Interrupt) => { @@ -104,9 +112,39 @@ pub fn select( impl Wait { /// Constructs a new wait channel - pub const fn new() -> Self { + pub const fn new(name: &'static str) -> Self { Self { 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); - Thread::get(tid).unwrap().set_wait_reached(); + Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done); SCHED.enqueue(tid); } @@ -149,30 +187,6 @@ impl Wait { 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 /// (optional) deadline is reached pub fn wait(&self, deadline: Option) -> Result<(), Errno> { @@ -191,9 +205,15 @@ impl Wait { } loop { - if !thread.wait_flag() { - return Ok(()); - } + match thread.wait_status() { + WaitStatus::Pending => {} + WaitStatus::Done => { + return Ok(()); + } + WaitStatus::Interrupted => { + return Err(Errno::Interrupt); + } + }; drop(queue_lock); thread.enter_wait(); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 520547e..c3b8f45 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -52,6 +52,7 @@ fn find_at_node>( /// Main system call dispatcher function pub fn syscall(num: SystemCall, args: &[usize]) -> Result { + // debugln!("syscall {:?}", num); match num { // I/O SystemCall::Read => { @@ -172,7 +173,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { if flags & (1 << 0) != 0 { Process::exit_thread(Thread::current(), status); } else { - Process::exit(status); + Process::current().exit(status); } unreachable!(); @@ -187,7 +188,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { *status = i32::from(exit); Ok(0) } - _ => todo!(), + e => e.map(|e| i32::from(e) as usize), } }, SystemCall::WaitTid => { @@ -200,7 +201,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { _ => todo!(), } }, - SystemCall::GetPid => todo!(), + SystemCall::GetPid => Ok(Process::current().id().value() as usize), SystemCall::GetTid => Ok(Thread::current().id() as usize), SystemCall::Sleep => { let rem_buf = arg::option_buf_ref(args[1], size_of::() * 2)?; @@ -239,6 +240,68 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result { proc::switch(); 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 SystemCall::GetCpuTime => { diff --git a/libsys/src/abi.rs b/libsys/src/abi.rs index 59c9b36..fad27ff 100644 --- a/libsys/src/abi.rs +++ b/libsys/src/abi.rs @@ -26,6 +26,11 @@ pub enum SystemCall { SignalReturn = 42, SendSignal = 43, Yield = 44, + GetSid = 45, + GetPgid = 46, + GetPpid = 47, + SetSid = 48, + SetPgid = 49, // System GetCpuTime = 64, // Debugging diff --git a/libsys/src/calls.rs b/libsys/src/calls.rs index b5e13e7..98fdb53 100644 --- a/libsys/src/calls.rs +++ b/libsys/src/calls.rs @@ -251,14 +251,15 @@ pub fn sys_ioctl( #[inline(always)] pub fn sys_ex_getcputime() -> Result { - Errno::from_syscall(unsafe { - syscall!(SystemCall::GetCpuTime) - }).map(|e| Duration::from_nanos(e as u64)) + Errno::from_syscall(unsafe { syscall!(SystemCall::GetCpuTime) }) + .map(|e| Duration::from_nanos(e as u64)) } #[inline(always)] 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)] @@ -349,7 +350,22 @@ pub fn sys_faccessat( #[inline(always)] pub fn sys_ex_gettid() -> u32 { - unsafe { - syscall!(SystemCall::GetTid) as u32 - } + unsafe { 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 { + 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 { + Errno::from_syscall(unsafe { syscall!(SystemCall::SetPgid, argn!(pid.value()), argn!(pgid.value())) }).map(|e| unsafe { Pid::from_raw(e as u32) }) +} + diff --git a/libsys/src/ioctl.rs b/libsys/src/ioctl.rs index 9b8d484..91cb058 100644 --- a/libsys/src/ioctl.rs +++ b/libsys/src/ioctl.rs @@ -7,6 +7,7 @@ use crate::error::Errno; pub enum IoctlCmd { TtySetAttributes = 1, TtyGetAttributes = 2, + TtySetPgrp = 3, } impl TryFrom for IoctlCmd { @@ -17,6 +18,7 @@ impl TryFrom for IoctlCmd { match u { 1 => Ok(Self::TtySetAttributes), 2 => Ok(Self::TtyGetAttributes), + 3 => Ok(Self::TtySetPgrp), _ => Err(Errno::InvalidArgument) } } diff --git a/libusr/src/io/mod.rs b/libusr/src/io/mod.rs index f4c9ee3..6e2bf5f 100644 --- a/libusr/src/io/mod.rs +++ b/libusr/src/io/mod.rs @@ -1,7 +1,11 @@ use libsys::{ - calls::sys_fstatat, + calls::{sys_fstatat, sys_ioctl}, stat::{FileDescriptor, Stat}, + ioctl::IoctlCmd, + error::Errno, + proc::Pid }; +use core::mem::size_of; use core::fmt; mod error; @@ -24,6 +28,14 @@ pub trait AsRawFd { fn as_raw_fd(&self) -> FileDescriptor; } +pub fn tcgetpgrp(fd: FileDescriptor) -> Result { + todo!() +} + +pub fn tcsetpgrp(fd: FileDescriptor, pgid: Pid) -> Result<(), Errno> { + sys_ioctl(fd, IoctlCmd::TtySetPgrp, &pgid as *const _ as usize, size_of::()).map(|_| ()) +} + pub fn stat(pathname: &str) -> Result { let mut buf = Stat::default(); // TODO error handling diff --git a/libusr/src/sys/mod.rs b/libusr/src/sys/mod.rs index 9b43f6b..e6727f4 100644 --- a/libusr/src/sys/mod.rs +++ b/libusr/src/sys/mod.rs @@ -1,5 +1,5 @@ pub use libsys::signal::{Signal, SignalDestination}; -pub use libsys::proc::ExitCode; +pub use libsys::proc::{self, ExitCode}; pub use libsys::termios; pub use libsys::abi; pub use libsys::calls::*; diff --git a/user/src/fuzzy/main.rs b/user/src/fuzzy/main.rs index cfc7d4e..6b06d79 100644 --- a/user/src/fuzzy/main.rs +++ b/user/src/fuzzy/main.rs @@ -125,7 +125,7 @@ fn main() -> i32 { // Test non-utf8 input fed into syscalls expecting strings // let old_signal = signal::set_handler(Signal::InvalidSystemCall, SignalHandler::Ignore); - for _ in 0..100 { + for _ in 0..10000 { random_bytes(&mut buf); let mut stat = Stat::default(); diff --git a/user/src/shell/main.rs b/user/src/shell/main.rs index b2a835e..054c443 100644 --- a/user/src/shell/main.rs +++ b/user/src/shell/main.rs @@ -6,19 +6,29 @@ extern crate libusr; extern crate alloc; use alloc::borrow::ToOwned; -use libusr::sys::{sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno}; 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, io::Error> { let size = f.read(bytes)?; Ok(if size == 0 { None } 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) -> ! { + 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_exit(ExitCode::from(-1)); } @@ -30,6 +40,8 @@ fn execute(line: &str) -> Result { if let Some(pid) = unsafe { sys_fork()? } { let mut status = 0; 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)) } else { execvp(cmd); @@ -41,18 +53,30 @@ fn main() -> i32 { let mut buf = [0; 256]; 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 { print!("> "); - let line = readline(&mut stdin, &mut buf).unwrap(); - if line.is_none() { - break; - } - let line = line.unwrap().trim_start_matches(' '); - if line.is_empty() { - continue; - } + match readline(&mut stdin, &mut buf) { + Ok(line) => { + if line.is_none() { + break; + } + let line = line.unwrap().trim_start_matches(' '); + if line.is_empty() { + continue; + } - execute(line).ok(); + execute(line).ok(); + }, + Err(_) => { + println!("Interrupt!"); + continue; + }, + _ => panic!() + } } 0 }