feature: waitpid system call

This commit is contained in:
2021-11-05 15:24:10 +02:00
parent 41706c5676
commit 92b517bcd4
13 changed files with 169 additions and 63 deletions
Generated
+7 -7
View File
@@ -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
View File
@@ -16,6 +16,6 @@ members = [
"libcommon",
"kernel",
"libusr",
"init",
"user",
"error"
]
+5 -4
View File
@@ -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 \
-26
View File
@@ -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
}
+5
View File
@@ -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 {
+26 -4
View File
@@ -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
View File
@@ -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
+13
View File
@@ -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 => {
+1
View File
@@ -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
View File
@@ -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
}
+9 -1
View File
@@ -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" }
+26
View File
@@ -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 {}
}
+31
View File
@@ -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;
}