proc: better handling of process groups + shell interrupts
This commit is contained in:
parent
ae09849fda
commit
2dc162d1a0
@ -17,7 +17,10 @@ use libk_mm_interface::{
|
|||||||
process::ProcessAddressSpaceManager,
|
process::ProcessAddressSpaceManager,
|
||||||
table::{MapAttributes, TableAllocator},
|
table::{MapAttributes, TableAllocator},
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::{error::Error, process::Signal};
|
use yggdrasil_abi::{
|
||||||
|
error::Error,
|
||||||
|
process::{ProcessGroupId, Signal},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct ArchitectureImpl;
|
pub struct ArchitectureImpl;
|
||||||
|
|
||||||
@ -171,6 +174,6 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator> TaskContext<K, PA>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "Rust" fn __signal_process_group(_group_id: u32, _signal: Signal) {
|
extern "Rust" fn __signal_process_group(_group_id: ProcessGroupId, _signal: Signal) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use yggdrasil_abi::{
|
|||||||
DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
DeviceRequest, TerminalInputOptions, TerminalLineOptions, TerminalOptions,
|
||||||
TerminalOutputOptions, TerminalSize,
|
TerminalOutputOptions, TerminalSize,
|
||||||
},
|
},
|
||||||
process::{ProcessId, Signal},
|
process::{ProcessGroupId, Signal},
|
||||||
};
|
};
|
||||||
|
|
||||||
const CAPACITY: usize = 8192;
|
const CAPACITY: usize = 8192;
|
||||||
@ -38,7 +38,7 @@ struct PtyMasterToSlaveHalf {
|
|||||||
// Actual data to be read by the slave
|
// Actual data to be read by the slave
|
||||||
buffer: IrqSafeSpinlock<MasterToSlaveBuffer>,
|
buffer: IrqSafeSpinlock<MasterToSlaveBuffer>,
|
||||||
ready_ring: LossyRingQueue<u8>,
|
ready_ring: LossyRingQueue<u8>,
|
||||||
signal_pgroup: IrqSafeRwLock<Option<ProcessId>>,
|
signal_pgroup: IrqSafeRwLock<Option<ProcessGroupId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pseudo-terminal shared device
|
/// Pseudo-terminal shared device
|
||||||
|
@ -18,7 +18,7 @@ use yggdrasil_abi::{
|
|||||||
io::SeekFrom,
|
io::SeekFrom,
|
||||||
pass::{Place, Placer},
|
pass::{Place, Placer},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::ProgramArgumentInner,
|
process::{ProcessGroupId, ProgramArgumentInner},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -170,6 +170,7 @@ fn setup_context(
|
|||||||
|
|
||||||
fn setup_binary<S, PM, IO>(
|
fn setup_binary<S, PM, IO>(
|
||||||
name: S,
|
name: S,
|
||||||
|
group_id: ProcessGroupId,
|
||||||
parent: Option<Weak<ProcessImpl<PM, IO>>>,
|
parent: Option<Weak<ProcessImpl<PM, IO>>>,
|
||||||
space: ProcessAddressSpace,
|
space: ProcessAddressSpace,
|
||||||
image: ProcessImage,
|
image: ProcessImage,
|
||||||
@ -182,8 +183,14 @@ where
|
|||||||
IO: ProcessIo,
|
IO: ProcessIo,
|
||||||
{
|
{
|
||||||
let context = setup_context(&space, &image, args, envs)?;
|
let context = setup_context(&space, &image, args, envs)?;
|
||||||
let (process, main) =
|
let (process, main) = ProcessImpl::new_with_main(
|
||||||
ProcessImpl::new_with_main(name, parent, Arc::new(space), context, Some(image));
|
name,
|
||||||
|
group_id,
|
||||||
|
parent,
|
||||||
|
Arc::new(space),
|
||||||
|
context,
|
||||||
|
Some(image),
|
||||||
|
);
|
||||||
Ok((process, main))
|
Ok((process, main))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +244,7 @@ fn xxx_load_program<PS: ProgramLoadSource, P: AsRef<Path>>(
|
|||||||
/// Loads a program from given `path`
|
/// Loads a program from given `path`
|
||||||
pub fn load<PS, P, PM, IO>(
|
pub fn load<PS, P, PM, IO>(
|
||||||
source: &mut PS,
|
source: &mut PS,
|
||||||
|
group_id: ProcessGroupId,
|
||||||
parent: Option<Weak<ProcessImpl<PM, IO>>>,
|
parent: Option<Weak<ProcessImpl<PM, IO>>>,
|
||||||
path: P,
|
path: P,
|
||||||
args: &[&str],
|
args: &[&str],
|
||||||
@ -254,7 +262,7 @@ where
|
|||||||
|
|
||||||
let space = ProcessAddressSpace::new()?;
|
let space = ProcessAddressSpace::new()?;
|
||||||
let (image, args, envs) = xxx_load_program(&space, source, path, args, envs)?;
|
let (image, args, envs) = xxx_load_program(&space, source, path, args, envs)?;
|
||||||
setup_binary(path.display(), parent, space, image, &args, &envs)
|
setup_binary(path.display(), group_id, parent, space, image, &args, &envs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_into<P, PM, IO>(
|
pub fn load_into<P, PM, IO>(
|
||||||
|
@ -16,10 +16,10 @@ use kernel_arch::{Architecture, ArchitectureImpl, KernelTableManagerImpl};
|
|||||||
use libk_mm::phys::GlobalPhysicalAllocator;
|
use libk_mm::phys::GlobalPhysicalAllocator;
|
||||||
|
|
||||||
pub(crate) mod api {
|
pub(crate) mod api {
|
||||||
use yggdrasil_abi::process::{ProcessId, Signal};
|
use yggdrasil_abi::process::{ProcessGroupId, Signal};
|
||||||
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
pub fn __signal_process_group(group_id: ProcessId, signal: Signal);
|
pub fn __signal_process_group(group_id: ProcessGroupId, signal: Signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ pub type TaskContextImpl =
|
|||||||
use sched::CpuQueue;
|
use sched::CpuQueue;
|
||||||
pub use types::{AtomicThreadState, ThreadAffinity, ThreadId, ThreadState};
|
pub use types::{AtomicThreadState, ThreadAffinity, ThreadId, ThreadState};
|
||||||
|
|
||||||
use yggdrasil_abi::process::{ProcessId, Signal};
|
use yggdrasil_abi::process::{ProcessGroupId, Signal};
|
||||||
|
|
||||||
/// Returns local CPU index
|
/// Returns local CPU index
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -53,6 +53,6 @@ pub fn cpu_count() -> usize {
|
|||||||
ArchitectureImpl::cpu_count()
|
ArchitectureImpl::cpu_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signal_process_group(group_id: ProcessId, signal: Signal) {
|
pub fn signal_process_group(group_id: ProcessGroupId, signal: Signal) {
|
||||||
unsafe { __signal_process_group(group_id, signal) }
|
unsafe { __signal_process_group(group_id, signal) }
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::{
|
||||||
|
marker::PhantomData,
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
use abi_lib::SyscallRegister;
|
use abi_lib::SyscallRegister;
|
||||||
use alloc::{
|
use alloc::{
|
||||||
@ -19,7 +22,7 @@ use libk_util::{
|
|||||||
};
|
};
|
||||||
use yggdrasil_abi::{
|
use yggdrasil_abi::{
|
||||||
error::Error,
|
error::Error,
|
||||||
process::{ExitCode, ProcessId, Signal, ThreadSpawnOptions},
|
process::{ExitCode, ProcessGroupId, ProcessId, Signal, ThreadSpawnOptions},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -69,7 +72,7 @@ pub struct ProcessImage {
|
|||||||
|
|
||||||
pub struct ProcessInner<IO: ProcessIo> {
|
pub struct ProcessInner<IO: ProcessIo> {
|
||||||
session_id: ProcessId,
|
session_id: ProcessId,
|
||||||
group_id: ProcessId,
|
group_id: ProcessGroupId,
|
||||||
|
|
||||||
session_terminal: Option<Arc<IO::Node>>,
|
session_terminal: Option<Arc<IO::Node>>,
|
||||||
threads: Vec<Arc<Thread>>,
|
threads: Vec<Arc<Thread>>,
|
||||||
@ -140,6 +143,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
/// Creates a new process with given main thread
|
/// Creates a new process with given main thread
|
||||||
pub fn new_with_main<S: Into<String>>(
|
pub fn new_with_main<S: Into<String>>(
|
||||||
name: S,
|
name: S,
|
||||||
|
group_id: ProcessGroupId,
|
||||||
parent: Option<Weak<Self>>,
|
parent: Option<Weak<Self>>,
|
||||||
space: Arc<ProcessAddressSpace>,
|
space: Arc<ProcessAddressSpace>,
|
||||||
context: TaskContextImpl,
|
context: TaskContextImpl,
|
||||||
@ -153,7 +157,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
id,
|
id,
|
||||||
parent,
|
parent,
|
||||||
|
|
||||||
inner: IrqSafeRwLock::new(ProcessInner::new(id, Some(space.clone()), image)),
|
inner: IrqSafeRwLock::new(ProcessInner::new(id, group_id, Some(space.clone()), image)),
|
||||||
|
|
||||||
exit: OneTimeEvent::new(),
|
exit: OneTimeEvent::new(),
|
||||||
io: IrqSafeSpinlock::new(IO::new()),
|
io: IrqSafeSpinlock::new(IO::new()),
|
||||||
@ -170,6 +174,13 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
(process, thread)
|
(process, thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_group() -> ProcessGroupId {
|
||||||
|
static ID: AtomicU32 = AtomicU32::new(1);
|
||||||
|
let id = ID.fetch_add(1, Ordering::AcqRel);
|
||||||
|
|
||||||
|
unsafe { ProcessGroupId::from_raw(id) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawns a new child thread within the process
|
/// Spawns a new child thread within the process
|
||||||
pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> {
|
pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
@ -216,6 +227,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
|
|
||||||
let (new_process, new_main) = Self::new_with_main(
|
let (new_process, new_main) = Self::new_with_main(
|
||||||
self.name(),
|
self.name(),
|
||||||
|
self.group_id(),
|
||||||
Some(Arc::downgrade(self)),
|
Some(Arc::downgrade(self)),
|
||||||
Arc::new(new_space),
|
Arc::new(new_space),
|
||||||
new_context,
|
new_context,
|
||||||
@ -282,7 +294,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the process group ID of the process
|
/// Returns the process group ID of the process
|
||||||
pub fn group_id(&self) -> ProcessId {
|
pub fn group_id(&self) -> ProcessGroupId {
|
||||||
self.inner.read().group_id
|
self.inner.read().group_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +304,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the process's group ID
|
/// Changes the process's group ID
|
||||||
pub fn set_group_id(&self, id: ProcessId) {
|
pub fn set_group_id(&self, id: ProcessGroupId) {
|
||||||
self.inner.write().group_id = id;
|
self.inner.write().group_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +371,7 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Raises a signal for the specified process group
|
/// Raises a signal for the specified process group
|
||||||
pub fn signal_group(group_id: ProcessId, signal: Signal) {
|
pub fn signal_group(group_id: ProcessGroupId, signal: Signal) {
|
||||||
PM::for_each(|_, proc| {
|
PM::for_each(|_, proc| {
|
||||||
let inner = proc.inner.read();
|
let inner = proc.inner.read();
|
||||||
if !proc.has_exited() && inner.group_id == group_id {
|
if !proc.has_exited() && inner.group_id == group_id {
|
||||||
@ -397,12 +409,13 @@ impl<PM: ProcessManager<Process = Self>, IO: ProcessIo> ProcessImpl<PM, IO> {
|
|||||||
impl<IO: ProcessIo> ProcessInner<IO> {
|
impl<IO: ProcessIo> ProcessInner<IO> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: ProcessId,
|
id: ProcessId,
|
||||||
|
group_id: ProcessGroupId,
|
||||||
space: Option<Arc<ProcessAddressSpace>>,
|
space: Option<Arc<ProcessAddressSpace>>,
|
||||||
image: Option<ProcessImage>,
|
image: Option<ProcessImage>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
session_id: id,
|
session_id: id,
|
||||||
group_id: id,
|
group_id,
|
||||||
session_terminal: None,
|
session_terminal: None,
|
||||||
threads: Vec::new(),
|
threads: Vec::new(),
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use core::{
|
|||||||
use abi::{
|
use abi::{
|
||||||
error::Error,
|
error::Error,
|
||||||
io::{TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions},
|
io::{TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions},
|
||||||
process::{ProcessId, Signal},
|
process::{ProcessGroupId, Signal},
|
||||||
};
|
};
|
||||||
use device_api::serial::SerialDevice;
|
use device_api::serial::SerialDevice;
|
||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
@ -83,7 +83,7 @@ impl TerminalRing {
|
|||||||
|
|
||||||
struct TtyContextInner {
|
struct TtyContextInner {
|
||||||
config: TerminalOptions,
|
config: TerminalOptions,
|
||||||
process_group: Option<ProcessId>,
|
process_group: Option<ProcessGroupId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the context of a terminal device
|
/// Represents the context of a terminal device
|
||||||
@ -99,7 +99,7 @@ pub trait TtyDevice: SerialDevice {
|
|||||||
fn context(&self) -> &TtyContext;
|
fn context(&self) -> &TtyContext;
|
||||||
|
|
||||||
/// Sets the process group to which signals from this terminal should be delivered
|
/// Sets the process group to which signals from this terminal should be delivered
|
||||||
fn set_signal_group(&self, id: ProcessId) {
|
fn set_signal_group(&self, id: ProcessGroupId) {
|
||||||
self.context().inner.lock().process_group.replace(id);
|
self.context().inner.lock().process_group.replace(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use vfs::{impls::FnSymlink, IoContext, NodeRef};
|
|||||||
use crate::{
|
use crate::{
|
||||||
fs::{FileBlockAllocator, INITRD_DATA},
|
fs::{FileBlockAllocator, INITRD_DATA},
|
||||||
proc::{self, random},
|
proc::{self, random},
|
||||||
task::process::ProcessManagerImpl,
|
task::process::{ProcessImpl, ProcessManagerImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn setup_root() -> Result<NodeRef, Error> {
|
fn setup_root() -> Result<NodeRef, Error> {
|
||||||
@ -67,8 +67,9 @@ pub fn kinit() -> Result<(), Error> {
|
|||||||
let mut ioctx = IoContext::new(root);
|
let mut ioctx = IoContext::new(root);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
let group_id = ProcessImpl::create_group();
|
||||||
let (user_init, user_init_main) =
|
let (user_init, user_init_main) =
|
||||||
proc::load_binary(&mut ioctx, None, "/init", &["/init", "xxx"], &[])?;
|
proc::load_binary(&mut ioctx, group_id, None, "/init", &["/init", "xxx"], &[])?;
|
||||||
|
|
||||||
let mut io = user_init.io.lock();
|
let mut io = user_init.io.lock();
|
||||||
io.set_ioctx(ioctx);
|
io.set_ioctx(ioctx);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Internal management for processes
|
//! Internal management for processes
|
||||||
|
|
||||||
use abi::{error::Error, path::Path};
|
use abi::{error::Error, path::Path, process::ProcessGroupId};
|
||||||
use alloc::sync::{Arc, Weak};
|
use alloc::sync::{Arc, Weak};
|
||||||
use libk_thread::thread::Thread;
|
use libk_thread::thread::Thread;
|
||||||
use vfs::IoContext;
|
use vfs::IoContext;
|
||||||
@ -14,10 +14,11 @@ pub mod random;
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn load_binary<P: AsRef<Path>>(
|
pub fn load_binary<P: AsRef<Path>>(
|
||||||
ioctx: &mut IoContext,
|
ioctx: &mut IoContext,
|
||||||
|
group_id: ProcessGroupId,
|
||||||
parent: Option<Weak<ProcessImpl>>,
|
parent: Option<Weak<ProcessImpl>>,
|
||||||
path: P,
|
path: P,
|
||||||
args: &[&str],
|
args: &[&str],
|
||||||
envs: &[&str],
|
envs: &[&str],
|
||||||
) -> Result<(Arc<ProcessImpl>, Arc<Thread>), Error> {
|
) -> Result<(Arc<ProcessImpl>, Arc<Thread>), Error> {
|
||||||
libk_thread::binary::load(ioctx, parent, path, args, envs)
|
libk_thread::binary::load(ioctx, group_id, parent, path, args, envs)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ mod impls {
|
|||||||
};
|
};
|
||||||
use abi::{
|
use abi::{
|
||||||
io::ChannelPublisherId,
|
io::ChannelPublisherId,
|
||||||
process::{ExecveOptions, ProcessId, SpawnOption},
|
process::{ExecveOptions, ProcessGroupId, ProcessId, SpawnOption},
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, sync::Arc};
|
use alloc::{boxed::Box, sync::Arc};
|
||||||
use libk::{block, runtime};
|
use libk::{block, runtime};
|
||||||
@ -81,7 +81,7 @@ mod impls {
|
|||||||
debug::LogLevel,
|
debug::LogLevel,
|
||||||
fs,
|
fs,
|
||||||
proc::{self, random},
|
proc::{self, random},
|
||||||
task::process::ProcessManagerImpl,
|
task::process::{ProcessImpl, ProcessManagerImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{run_with_io, run_with_io_at};
|
use super::{run_with_io, run_with_io_at};
|
||||||
@ -175,6 +175,18 @@ mod impls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process/thread management
|
// Process/thread management
|
||||||
|
pub(crate) fn create_process_group() -> ProcessGroupId {
|
||||||
|
let id = ProcessImpl::create_group();
|
||||||
|
log::info!("CREATED PROCESS GROUP {}", id);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_process_group_id() -> ProcessGroupId {
|
||||||
|
let thread = Thread::current();
|
||||||
|
let process = thread.process::<ProcessManagerImpl>();
|
||||||
|
process.group_id()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn exit_process(code: ExitCode) -> ! {
|
pub(crate) fn exit_process(code: ExitCode) -> ! {
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
thread.exit_process::<ProcessManagerImpl>(code)
|
thread.exit_process::<ProcessManagerImpl>(code)
|
||||||
@ -188,6 +200,7 @@ mod impls {
|
|||||||
// Setup a new process from the file
|
// Setup a new process from the file
|
||||||
let (child_process, child_main) = proc::load_binary(
|
let (child_process, child_main) = proc::load_binary(
|
||||||
io.ioctx_mut(),
|
io.ioctx_mut(),
|
||||||
|
process.group_id(),
|
||||||
Some(Arc::downgrade(&process)),
|
Some(Arc::downgrade(&process)),
|
||||||
options.program,
|
options.program,
|
||||||
options.arguments,
|
options.arguments,
|
||||||
@ -213,7 +226,7 @@ mod impls {
|
|||||||
}
|
}
|
||||||
&SpawnOption::SetProcessGroup(pgroup) => {
|
&SpawnOption::SetProcessGroup(pgroup) => {
|
||||||
let pgroup = if pgroup.into_raw() == 0 {
|
let pgroup = if pgroup.into_raw() == 0 {
|
||||||
child_process.id()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
pgroup
|
pgroup
|
||||||
};
|
};
|
||||||
@ -261,11 +274,10 @@ mod impls {
|
|||||||
process.id()
|
process.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn nanosleep(duration: &Duration) {
|
pub(crate) fn nanosleep(duration: &Duration) -> Result<(), Error> {
|
||||||
block! {
|
block! {
|
||||||
runtime::sleep(*duration).await
|
runtime::sleep(*duration).await
|
||||||
}
|
}
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_signal_entry(ip: usize, sp: usize) {
|
pub(crate) fn set_signal_entry(ip: usize, sp: usize) {
|
||||||
@ -311,8 +323,10 @@ mod impls {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let group_id = ProcessImpl::create_group();
|
||||||
|
|
||||||
process.set_session_id(process.id());
|
process.set_session_id(process.id());
|
||||||
process.set_group_id(process.id());
|
process.set_group_id(group_id);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Process data structures
|
//! Process data structures
|
||||||
|
|
||||||
use abi::process::{ProcessId, Signal};
|
use abi::process::{ProcessGroupId, ProcessId, Signal};
|
||||||
use alloc::{collections::BTreeMap, sync::Arc};
|
use alloc::{collections::BTreeMap, sync::Arc};
|
||||||
use libk_thread::process::{Process, ProcessManager};
|
use libk_thread::process::{Process, ProcessManager};
|
||||||
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
||||||
@ -40,6 +40,6 @@ impl ProcessManager for ProcessManagerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn __signal_process_group(group_id: ProcessId, signal: Signal) {
|
fn __signal_process_group(group_id: ProcessGroupId, signal: Signal) {
|
||||||
ProcessImpl::signal_group(group_id, signal)
|
ProcessImpl::signal_group(group_id, signal)
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,15 @@ syscall map_memory(hint: Option<NonZeroUsize>, len: usize, source: &MappingSourc
|
|||||||
syscall unmap_memory(address: usize, len: usize) -> Result<()>;
|
syscall unmap_memory(address: usize, len: usize) -> Result<()>;
|
||||||
|
|
||||||
// Process/thread management
|
// Process/thread management
|
||||||
|
syscall create_process_group() -> ProcessGroupId;
|
||||||
|
syscall get_process_group_id() -> ProcessGroupId;
|
||||||
|
|
||||||
syscall exit_process(code: ExitCode) -> !;
|
syscall exit_process(code: ExitCode) -> !;
|
||||||
syscall spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId>;
|
syscall spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId>;
|
||||||
syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>;
|
syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>;
|
||||||
syscall get_pid() -> ProcessId;
|
syscall get_pid() -> ProcessId;
|
||||||
|
|
||||||
syscall nanosleep(dur: &Duration);
|
syscall nanosleep(dur: &Duration) -> Result<()>;
|
||||||
|
|
||||||
syscall exit_signal(frame: &SignalEntryData) -> !;
|
syscall exit_signal(frame: &SignalEntryData) -> !;
|
||||||
syscall set_signal_entry(ip: usize, sp: usize);
|
syscall set_signal_entry(ip: usize, sp: usize);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use crate::generated::ProcessId;
|
use crate::generated::ProcessGroupId;
|
||||||
|
|
||||||
use super::terminal;
|
use super::terminal;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ pub enum DeviceRequest {
|
|||||||
/// Return the terminal's size
|
/// Return the terminal's size
|
||||||
GetTerminalSize(MaybeUninit<terminal::TerminalSize>),
|
GetTerminalSize(MaybeUninit<terminal::TerminalSize>),
|
||||||
/// Sets a foreground process group ID for the terminal
|
/// Sets a foreground process group ID for the terminal
|
||||||
SetTerminalGroup(ProcessId),
|
SetTerminalGroup(ProcessGroupId),
|
||||||
/// "Acquires" ownership of the device, preventing others from accessing it
|
/// "Acquires" ownership of the device, preventing others from accessing it
|
||||||
AcquireDevice,
|
AcquireDevice,
|
||||||
/// "Releases" ownership of the device
|
/// "Releases" ownership of the device
|
||||||
|
@ -10,7 +10,8 @@ use crate::{
|
|||||||
mod exit;
|
mod exit;
|
||||||
|
|
||||||
pub use crate::generated::{
|
pub use crate::generated::{
|
||||||
ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions, ThreadId, ThreadSpawnOptions,
|
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions, ThreadId,
|
||||||
|
ThreadSpawnOptions,
|
||||||
};
|
};
|
||||||
pub use exit::ExitCode;
|
pub use exit::ExitCode;
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ pub enum SpawnOption {
|
|||||||
child: RawFd,
|
child: RawFd,
|
||||||
},
|
},
|
||||||
/// The new process should be placed in the specified group
|
/// The new process should be placed in the specified group
|
||||||
SetProcessGroup(ProcessId),
|
SetProcessGroup(ProcessGroupId),
|
||||||
/// Gain terminal control for the given FD
|
/// Gain terminal control for the given FD
|
||||||
GainTerminal(RawFd),
|
GainTerminal(RawFd),
|
||||||
}
|
}
|
||||||
@ -70,3 +71,9 @@ impl fmt::Display for ProcessId {
|
|||||||
write!(f, "<Process {}>", self.0)
|
write!(f, "<Process {}>", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ProcessGroupId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "<Process group {}>", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Process management data types
|
//! Process management data types
|
||||||
|
|
||||||
pub use abi::process::{
|
pub use abi::process::{
|
||||||
ExecveOptions, ExitCode, MutexOperation, ProcessId, ProcessInfoElement, ProgramArgumentInner,
|
ExecveOptions, ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessInfoElement,
|
||||||
Signal, SignalEntryData, SpawnOption, SpawnOptions, ThreadId, ThreadSpawnOptions,
|
ProgramArgumentInner, Signal, SignalEntryData, SpawnOption, SpawnOptions, ThreadId,
|
||||||
|
ThreadSpawnOptions,
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,9 @@ mod generated {
|
|||||||
},
|
},
|
||||||
mem::MappingSource,
|
mem::MappingSource,
|
||||||
net::SocketType,
|
net::SocketType,
|
||||||
process::{ExecveOptions, ProcessId, Signal, SignalEntryData, SpawnOptions},
|
process::{
|
||||||
|
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions,
|
||||||
|
},
|
||||||
SyscallFunction,
|
SyscallFunction,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![cfg_attr(not(unix), feature(yggdrasil_os))]
|
#![cfg_attr(not(unix), feature(yggdrasil_os, rustc_private))]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -7,7 +7,7 @@ use std::{
|
|||||||
io::{self, stdin, stdout, BufRead, BufReader, Stdin, Write},
|
io::{self, stdin, stdout, BufRead, BufReader, Stdin, Write},
|
||||||
os::fd::{FromRawFd, IntoRawFd, OwnedFd},
|
os::fd::{FromRawFd, IntoRawFd, OwnedFd},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::{ExitCode, Stdio},
|
process::{Child, ExitCode, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
@ -36,6 +36,22 @@ pub enum Outcome {
|
|||||||
ExitShell(ExitCode),
|
ExitShell(ExitCode),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PipelineElement<'a> {
|
||||||
|
pub command: &'a str,
|
||||||
|
pub args: &'a [String],
|
||||||
|
pub input: Stdio,
|
||||||
|
pub output: Stdio,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pipeline<'a> {
|
||||||
|
pub elements: Vec<PipelineElement<'a>>,
|
||||||
|
pub env: &'a HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SpawnedPipeline {
|
||||||
|
pub children: Vec<Child>,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
Interactive(Stdin),
|
Interactive(Stdin),
|
||||||
File(BufReader<File>),
|
File(BufReader<File>),
|
||||||
@ -95,7 +111,6 @@ pub fn exec(
|
|||||||
|
|
||||||
let mut inputs = vec![];
|
let mut inputs = vec![];
|
||||||
let mut outputs = vec![];
|
let mut outputs = vec![];
|
||||||
let mut children = vec![];
|
|
||||||
let mut pipe_fds = vec![];
|
let mut pipe_fds = vec![];
|
||||||
|
|
||||||
inputs.push(Stdio::inherit());
|
inputs.push(Stdio::inherit());
|
||||||
@ -118,31 +133,39 @@ pub fn exec(
|
|||||||
assert_eq!(inputs.len(), outputs.len());
|
assert_eq!(inputs.len(), outputs.len());
|
||||||
assert_eq!(inputs.len(), pipeline.len());
|
assert_eq!(inputs.len(), pipeline.len());
|
||||||
|
|
||||||
|
let mut elements = vec![];
|
||||||
let ios = inputs.drain(..).zip(outputs.drain(..));
|
let ios = inputs.drain(..).zip(outputs.drain(..));
|
||||||
|
|
||||||
for (command, (input, output)) in pipeline.iter().zip(ios) {
|
for (command, (input, output)) in pipeline.iter().zip(ios) {
|
||||||
let (cmd, args) = command.words.split_first().unwrap();
|
let (cmd, args) = command.words.split_first().unwrap();
|
||||||
|
|
||||||
let child = sys::exec_binary(interactive, cmd, args, env, input, output)?;
|
let element = PipelineElement {
|
||||||
|
command: cmd,
|
||||||
|
args,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
};
|
||||||
|
|
||||||
children.push(child);
|
elements.push(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pipeline = Pipeline { elements, env };
|
||||||
|
let pipeline = sys::spawn_pipeline(interactive, pipeline)?;
|
||||||
|
|
||||||
drop(pipe_fds);
|
drop(pipe_fds);
|
||||||
|
|
||||||
for mut child in children.drain(..) {
|
let status = sys::wait_for_pipeline(interactive, pipeline)?;
|
||||||
let status = child.wait()?;
|
|
||||||
|
|
||||||
if !status.success() {
|
Ok(status)
|
||||||
return Ok(Outcome::from(status));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Outcome::ok())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitCode> {
|
fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitCode> {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
|
||||||
|
if input.is_interactive() {
|
||||||
|
sys::init_signal_handler();
|
||||||
|
}
|
||||||
|
|
||||||
let code = loop {
|
let code = loop {
|
||||||
line.clear();
|
line.clear();
|
||||||
|
|
||||||
@ -171,8 +194,7 @@ fn run(mut input: Input, vars: &mut HashMap<String, String>) -> io::Result<ExitC
|
|||||||
}
|
}
|
||||||
Ok(Outcome::Exited(code)) => code % 256,
|
Ok(Outcome::Exited(code)) => code % 256,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// TODO stringify the command back
|
eprintln!("{}: {}", line, e);
|
||||||
eprintln!("<command>: {}", e);
|
|
||||||
127
|
127
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,41 +1,76 @@
|
|||||||
use std::os::yggdrasil::io::pipe;
|
use std::os::yggdrasil::{
|
||||||
|
io::{
|
||||||
|
device::{DeviceRequest, FdDeviceRequest},
|
||||||
|
pipe,
|
||||||
|
},
|
||||||
|
process::{self, CommandExt, ExitStatusExt, ProcessGroupId},
|
||||||
|
signal::{set_signal_handler, Signal, SignalHandler},
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
io::{self, stdin},
|
||||||
io,
|
|
||||||
os::fd::OwnedFd,
|
os::fd::OwnedFd,
|
||||||
process::{Child, Command, ExitStatus, Stdio},
|
process::{Command, ExitStatus},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Outcome;
|
use crate::{Outcome, Pipeline, SpawnedPipeline};
|
||||||
|
|
||||||
pub struct Pipe {
|
pub struct Pipe {
|
||||||
pub read: OwnedFd,
|
pub read: OwnedFd,
|
||||||
pub write: OwnedFd,
|
pub write: OwnedFd,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec_binary(
|
fn set_terminal_group(group_id: ProcessGroupId) -> Result<(), io::Error> {
|
||||||
|
unsafe { stdin().device_request(&mut DeviceRequest::SetTerminalGroup(group_id)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_pipeline(
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
binary: &str,
|
pipeline: Pipeline<'_>,
|
||||||
args: &[String],
|
) -> Result<SpawnedPipeline, io::Error> {
|
||||||
env: &HashMap<String, String>,
|
let group_id = process::create_process_group();
|
||||||
input: Stdio,
|
|
||||||
output: Stdio,
|
|
||||||
) -> Result<Child, io::Error> {
|
|
||||||
use std::os::yggdrasil::process::CommandExt;
|
|
||||||
let mut command = Command::new(binary);
|
|
||||||
let mut command = command
|
|
||||||
.args(args)
|
|
||||||
.envs(env.iter())
|
|
||||||
.stdin(input)
|
|
||||||
.stdout(output);
|
|
||||||
|
|
||||||
if interactive {
|
if interactive {
|
||||||
unsafe {
|
set_terminal_group(group_id)?;
|
||||||
command = command.process_group_raw(0);
|
}
|
||||||
|
|
||||||
|
let mut children = vec![];
|
||||||
|
for element in pipeline.elements {
|
||||||
|
let mut command = Command::new(element.command);
|
||||||
|
command
|
||||||
|
.args(element.args)
|
||||||
|
.envs(pipeline.env.iter())
|
||||||
|
.stdin(element.input)
|
||||||
|
.stdout(element.output)
|
||||||
|
.process_group(group_id);
|
||||||
|
|
||||||
|
children.push(command.spawn()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SpawnedPipeline { children })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_for_pipeline(
|
||||||
|
interactive: bool,
|
||||||
|
mut pipeline: SpawnedPipeline,
|
||||||
|
) -> Result<Outcome, io::Error> {
|
||||||
|
let self_group_id = process::group_id();
|
||||||
|
|
||||||
|
for mut child in pipeline.children.drain(..) {
|
||||||
|
let status = child.wait()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
if interactive {
|
||||||
|
set_terminal_group(self_group_id).ok();
|
||||||
|
}
|
||||||
|
return Ok(Outcome::from(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
command.spawn()
|
if interactive {
|
||||||
|
set_terminal_group(self_group_id).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Outcome::ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_pipe() -> Result<Pipe, io::Error> {
|
pub fn create_pipe() -> Result<Pipe, io::Error> {
|
||||||
@ -43,10 +78,16 @@ pub fn create_pipe() -> Result<Pipe, io::Error> {
|
|||||||
Ok(Pipe { read, write })
|
Ok(Pipe { read, write })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn signal_handler(_sig: Signal) {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_signal_handler() {
|
||||||
|
set_signal_handler(Signal::Interrupted, SignalHandler::Function(signal_handler));
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ExitStatus> for Outcome {
|
impl From<ExitStatus> for Outcome {
|
||||||
fn from(value: ExitStatus) -> Self {
|
fn from(value: ExitStatus) -> Self {
|
||||||
use std::os::yggdrasil::process::ExitStatusExt;
|
|
||||||
|
|
||||||
if let Some(code) = value.code() {
|
if let Some(code) = value.code() {
|
||||||
Self::Exited(code)
|
Self::Exited(code)
|
||||||
} else if let Some(sig) = value.signal() {
|
} else if let Some(sig) = value.signal() {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
fs::File,
|
io::{self, stdout, Read, Stdout, Write},
|
||||||
io::{self, stdout, BufReader, Read, Stdout, Write},
|
|
||||||
path::Path,
|
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn cat_file<P: AsRef<Path>>(stdout: &mut Stdout, path: P) -> io::Result<()> {
|
use sysutils::Input;
|
||||||
|
|
||||||
|
fn cat_file(stdout: &mut Stdout, path: &str) -> io::Result<()> {
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
let mut reader = BufReader::new(File::open(path)?);
|
let mut reader = Input::open_str(path)?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let count = reader.read(&mut buf)?;
|
let count = reader.read(&mut buf)?;
|
||||||
@ -25,11 +25,20 @@ fn main() -> ExitCode {
|
|||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
let mut exit = ExitCode::SUCCESS;
|
let mut exit = ExitCode::SUCCESS;
|
||||||
|
|
||||||
for arg in env::args().skip(1) {
|
let args = env::args().skip(1);
|
||||||
if let Err(error) = cat_file(&mut stdout, &arg) {
|
|
||||||
eprintln!("{}: {}", arg, error);
|
if args.len() == 0 {
|
||||||
|
if let Err(error) = cat_file(&mut stdout, "-") {
|
||||||
|
eprintln!("{}: {}", "<stdin>", error);
|
||||||
exit = ExitCode::FAILURE;
|
exit = ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for arg in env::args().skip(1) {
|
||||||
|
if let Err(error) = cat_file(&mut stdout, &arg) {
|
||||||
|
eprintln!("{}: {}", arg, error);
|
||||||
|
exit = ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit
|
exit
|
||||||
|
@ -70,9 +70,9 @@ fn main() -> ExitCode {
|
|||||||
|
|
||||||
// "Attach" the terminal
|
// "Attach" the terminal
|
||||||
unsafe {
|
unsafe {
|
||||||
let pid = std::os::yggdrasil::process::id_ext();
|
let group_id = std::os::yggdrasil::process::group_id();
|
||||||
stdin()
|
stdin()
|
||||||
.device_request(&mut DeviceRequest::SetTerminalGroup(pid))
|
.device_request(&mut DeviceRequest::SetTerminalGroup(group_id))
|
||||||
.expect("Could not attach the terminal");
|
.expect("Could not attach the terminal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use std::{
|
|||||||
os::{
|
os::{
|
||||||
fd::{AsRawFd, FromRawFd, RawFd},
|
fd::{AsRawFd, FromRawFd, RawFd},
|
||||||
yggdrasil::{
|
yggdrasil::{
|
||||||
|
self,
|
||||||
io::{
|
io::{
|
||||||
device::{DeviceRequest, FdDeviceRequest},
|
device::{DeviceRequest, FdDeviceRequest},
|
||||||
poll::PollChannel,
|
poll::PollChannel,
|
||||||
@ -262,13 +263,14 @@ impl<'a> Terminal<'a> {
|
|||||||
poll.add(pty_master_fd)?;
|
poll.add(pty_master_fd)?;
|
||||||
|
|
||||||
let pty_slave_fd = pty_slave.as_raw_fd();
|
let pty_slave_fd = pty_slave.as_raw_fd();
|
||||||
|
let group_id = yggdrasil::process::create_process_group();
|
||||||
let shell = unsafe {
|
let shell = unsafe {
|
||||||
Command::new("/bin/sh")
|
Command::new("/bin/sh")
|
||||||
.arg("-l")
|
.arg("-l")
|
||||||
.stdin(Stdio::from_raw_fd(pty_slave_fd))
|
.stdin(Stdio::from_raw_fd(pty_slave_fd))
|
||||||
.stdout(Stdio::from_raw_fd(pty_slave_fd))
|
.stdout(Stdio::from_raw_fd(pty_slave_fd))
|
||||||
.stderr(Stdio::from_raw_fd(pty_slave_fd))
|
.stderr(Stdio::from_raw_fd(pty_slave_fd))
|
||||||
.process_group_raw(0)
|
.process_group(group_id)
|
||||||
.gain_terminal(0)
|
.gain_terminal(0)
|
||||||
.spawn()?
|
.spawn()?
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user