feature: waitpid system call
This commit is contained in:
Generated
+7
-7
@@ -70,13 +70,6 @@ dependencies = [
|
||||
"unsafe_unwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "init"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libusr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
@@ -233,6 +226,13 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1230ec65f13e0f9b28d789da20d2d419511893ea9dac2c1f4ef67b8b14e5da80"
|
||||
|
||||
[[package]]
|
||||
name = "user"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libusr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfs"
|
||||
version = "0.1.0"
|
||||
|
||||
+1
-1
@@ -16,6 +16,6 @@ members = [
|
||||
"libcommon",
|
||||
"kernel",
|
||||
"libusr",
|
||||
"init",
|
||||
"user",
|
||||
"error"
|
||||
]
|
||||
|
||||
@@ -86,13 +86,14 @@ ifeq ($(MACH),orangepi3)
|
||||
endif
|
||||
|
||||
initrd:
|
||||
cd init && cargo build \
|
||||
cd user && cargo build \
|
||||
--target=../etc/$(ARCH)-osdev5.json \
|
||||
-Z build-std=core,alloc,compiler_builtins \
|
||||
$(CARGO_COMMON_OPTS)
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)
|
||||
echo This is a test file >$(O)/test.txt
|
||||
cd $(O) && tar cf initrd.img init test.txt
|
||||
mkdir -p $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
||||
cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
|
||||
ifeq ($(MACH),orangepi3)
|
||||
$(MKIMAGE) \
|
||||
-A arm64 \
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#![feature(asm)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
use libusr::sys::{FileMode, OpenFlags, Stat, AT_EMPTY_PATH, AT_FDCWD};
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let mut stat = Stat::default();
|
||||
let fd = unsafe {
|
||||
libusr::sys::sys_openat(
|
||||
AT_FDCWD,
|
||||
"/test.txt",
|
||||
FileMode::empty(),
|
||||
OpenFlags::O_RDONLY,
|
||||
)
|
||||
};
|
||||
println!("fd = {}", fd);
|
||||
let ret = unsafe { libusr::sys::sys_fstatat(fd, "", &mut stat, AT_EMPTY_PATH) };
|
||||
println!("{}, {:?}", ret, stat);
|
||||
|
||||
-1
|
||||
}
|
||||
@@ -76,6 +76,11 @@ impl ProcessIo {
|
||||
pub(super) fn handle_cloexec(&mut self) {
|
||||
self.files.retain(|_, entry| !entry.borrow().is_cloexec());
|
||||
}
|
||||
|
||||
pub(super) fn handle_exit(&mut self) {
|
||||
self.files.clear();
|
||||
self.ioctx.take();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProcessIo {
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::mem::{
|
||||
phys::{self, PageUsage},
|
||||
virt::{MapAttributes, Space},
|
||||
};
|
||||
use crate::proc::{ProcessIo, PROCESSES, SCHED};
|
||||
use crate::proc::{wait::Wait, ProcessIo, PROCESSES, SCHED};
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::UnsafeCell;
|
||||
@@ -54,6 +54,7 @@ struct ProcessInner {
|
||||
pub struct Process {
|
||||
ctx: UnsafeCell<Context>,
|
||||
inner: IrqSafeSpinLock<ProcessInner>,
|
||||
exit_wait: Wait,
|
||||
/// Process I/O context
|
||||
pub io: IrqSafeSpinLock<ProcessIo>,
|
||||
}
|
||||
@@ -70,6 +71,12 @@ impl From<()> for ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitCode> for i32 {
|
||||
fn from(f: ExitCode) -> Self {
|
||||
f.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Pid {
|
||||
/// Kernel idle process always has PID of zero
|
||||
pub const IDLE: Self = Self(Self::KERNEL_BIT);
|
||||
@@ -117,6 +124,10 @@ impl Pid {
|
||||
pub const fn value(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub const unsafe fn from_raw(num: u32) -> Self {
|
||||
Self(num)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Pid {
|
||||
@@ -139,6 +150,10 @@ impl Process {
|
||||
SCHED.current_process()
|
||||
}
|
||||
|
||||
pub fn get(pid: Pid) -> Option<ProcessRef> {
|
||||
PROCESSES.lock().get(&pid).cloned()
|
||||
}
|
||||
|
||||
/// Schedules an initial thread for execution
|
||||
///
|
||||
/// # Safety
|
||||
@@ -215,6 +230,7 @@ impl Process {
|
||||
let res = Rc::new(Self {
|
||||
ctx: UnsafeCell::new(Context::kernel(entry as usize, arg)),
|
||||
io: IrqSafeSpinLock::new(ProcessIo::new()),
|
||||
exit_wait: Wait::new(),
|
||||
inner: IrqSafeSpinLock::new(ProcessInner {
|
||||
id,
|
||||
exit: None,
|
||||
@@ -242,6 +258,7 @@ impl Process {
|
||||
let dst = Rc::new(Self {
|
||||
ctx: UnsafeCell::new(Context::fork(frame, dst_ttbr0)),
|
||||
io: IrqSafeSpinLock::new(src_io.fork()?),
|
||||
exit_wait: Wait::new(),
|
||||
inner: IrqSafeSpinLock::new(ProcessInner {
|
||||
id: dst_id,
|
||||
exit: None,
|
||||
@@ -267,9 +284,13 @@ impl Process {
|
||||
assert!(lock.exit.is_none());
|
||||
lock.exit = Some(status);
|
||||
lock.state = State::Finished;
|
||||
|
||||
self.io.lock().handle_exit();
|
||||
|
||||
SCHED.dequeue(lock.id);
|
||||
drop
|
||||
};
|
||||
self.exit_wait.wakeup_all();
|
||||
if drop {
|
||||
SCHED.switch(true);
|
||||
panic!("This code should never run");
|
||||
@@ -295,12 +316,13 @@ impl Process {
|
||||
.ok_or(Errno::DoesNotExist)?;
|
||||
|
||||
if let Some(r) = proc.collect() {
|
||||
// TODO drop the process struct itself
|
||||
PROCESSES.lock().remove(&proc.id());
|
||||
debugln!("r = {}", Rc::strong_count(&proc));
|
||||
debugln!("pid {} has {} refs", proc.id(), Rc::strong_count(&proc));
|
||||
return Ok(r);
|
||||
} else {
|
||||
cortex_a::asm::wfi();
|
||||
}
|
||||
|
||||
proc.exit_wait.wait(None)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
-19
@@ -62,31 +62,43 @@ impl Wait {
|
||||
}
|
||||
}
|
||||
|
||||
fn wakeup_some(&self, mut limit: usize) -> usize {
|
||||
// No IRQs will arrive now == safe to manipulate tick list
|
||||
let mut queue = self.queue.lock();
|
||||
let mut count = 0;
|
||||
while limit != 0 && !queue.is_empty() {
|
||||
let pid = queue.pop_front();
|
||||
if let Some(pid) = pid {
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if pid == item.pid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
drop(tick_lock);
|
||||
|
||||
proc::process(pid).set_wait_flag(false);
|
||||
SCHED.enqueue(pid);
|
||||
}
|
||||
|
||||
limit -= 1;
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/// Notifies all processes waiting for this event
|
||||
pub fn wakeup_all(&self) {
|
||||
todo!()
|
||||
self.wakeup_some(usize::MAX);
|
||||
}
|
||||
|
||||
/// Notifies a single process waiting for this event
|
||||
pub fn wakeup_one(&self) {
|
||||
// No IRQs will arrive now == safe to manipulate tick list
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let pid = self.queue.lock().pop_front();
|
||||
if let Some(pid) = pid {
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if pid == item.pid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
drop(tick_lock);
|
||||
|
||||
proc::process(pid).set_wait_flag(false);
|
||||
SCHED.enqueue(pid);
|
||||
}
|
||||
self.wakeup_some(1);
|
||||
}
|
||||
|
||||
/// Suspends current process until event is signalled or
|
||||
|
||||
@@ -122,6 +122,19 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
Process::execve(|space| elf::load_elf(space, file), 0).unwrap();
|
||||
panic!();
|
||||
}
|
||||
abi::SYS_WAITPID => {
|
||||
// TODO special "pid" values
|
||||
let pid = unsafe { Pid::from_raw(args[0] as u32) };
|
||||
let status = validate_user_ptr_struct::<i32>(args[1])?;
|
||||
|
||||
match Process::waitpid(pid) {
|
||||
Ok(exit) => {
|
||||
*status = i32::from(exit);
|
||||
Ok(0)
|
||||
},
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// Extra system calls
|
||||
abi::SYS_EX_DEBUG_TRACE => {
|
||||
|
||||
@@ -9,3 +9,4 @@ pub const SYS_FSTATAT: usize = 5;
|
||||
pub const SYS_CLOSE: usize = 6;
|
||||
pub const SYS_FORK: usize = 7;
|
||||
pub const SYS_EXECVE: usize = 8;
|
||||
pub const SYS_WAITPID: usize = 9;
|
||||
|
||||
+14
-1
@@ -55,7 +55,7 @@ macro_rules! argn {
|
||||
/// Pointer/base argument
|
||||
macro_rules! argp {
|
||||
($a:expr) => {
|
||||
$a as *mut core::ffi::c_void as usize
|
||||
$a as usize
|
||||
};
|
||||
}
|
||||
// /// Immutable pointer/base argument
|
||||
@@ -175,3 +175,16 @@ pub unsafe fn sys_execve(pathname: &str) -> i32 {
|
||||
argn!(pathname.len())
|
||||
) as i32
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// System call
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_waitpid(pid: u32, status: &mut i32) -> i32 {
|
||||
syscall!(
|
||||
abi::SYS_WAITPID,
|
||||
argn!(pid),
|
||||
argp!(status as *mut i32)
|
||||
) as i32
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
[package]
|
||||
name = "init"
|
||||
name = "user"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[bin]]
|
||||
name = "init"
|
||||
path = "src/init/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "shell"
|
||||
path = "src/shell/main.rs"
|
||||
|
||||
[dependencies]
|
||||
libusr = { path = "../libusr" }
|
||||
@@ -0,0 +1,26 @@
|
||||
#![feature(asm)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let pid = unsafe { libusr::sys::sys_fork() };
|
||||
if pid < 0 {
|
||||
eprintln!("fork() failed");
|
||||
return -1;
|
||||
} else if pid == 0 {
|
||||
return unsafe { libusr::sys::sys_execve("/bin/shell") };
|
||||
} else {
|
||||
let mut status = 0;
|
||||
let res = unsafe { libusr::sys::sys_waitpid(pid as u32, &mut status) };
|
||||
if res > 0 {
|
||||
println!("Process {} exited with status {}", pid, status);
|
||||
} else {
|
||||
eprintln!("waitpid() failed");
|
||||
}
|
||||
}
|
||||
loop {}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
fn readline(fd: i32, buf: &mut [u8]) -> Result<&str, ()> {
|
||||
let count = unsafe { libusr::sys::sys_read(fd, buf) };
|
||||
if count >= 0 {
|
||||
core::str::from_utf8(&buf[..count as usize]).map_err(|_| ())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let mut buf = [0; 512];
|
||||
loop {
|
||||
print!("> ");
|
||||
let line = readline(libusr::sys::STDIN_FILENO, &mut buf).unwrap();
|
||||
|
||||
println!(":: {:?}", line);
|
||||
|
||||
if line == "quit" || line == "exit" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user