From 067f9d3526ad8e9be885ec22423f6940137c03dc Mon Sep 17 00:00:00 2001 From: Rafal Mielniczuk Date: Fri, 27 Sep 2024 20:53:02 +0100 Subject: [PATCH] fix occasional hang on poweroff --- cykusz-rs/src/arch/x86_64/syscall.rs | 12 ++- cykusz-rs/src/kernel/sched/round_robin.rs | 6 +- cykusz-rs/src/kernel/sched/task_container.rs | 7 ++ cykusz-rs/src/kernel/task/children_events.rs | 20 +++-- cykusz-rs/src/kernel/task/mod.rs | 94 +++++++++++++------- disk-scripts/fsck_disk_fix.sh | 6 +- disk-scripts/install_os.sh | 2 +- 7 files changed, 100 insertions(+), 47 deletions(-) diff --git a/cykusz-rs/src/arch/x86_64/syscall.rs b/cykusz-rs/src/arch/x86_64/syscall.rs index 82db3aac..4b965a1a 100644 --- a/cykusz-rs/src/arch/x86_64/syscall.rs +++ b/cykusz-rs/src/arch/x86_64/syscall.rs @@ -50,9 +50,11 @@ pub extern "C" fn fast_syscall_handler(sys_frame: &mut SyscallFrame, regs: &mut } } else { //logln!("syscall {:?} {:?}", regs, sys_frame); + let task = current_task_ref(); dbgln!( syscall, - "syscall {} {}, ret: 0x{:x}", + "syscall [task {}] {} {}, ret: 0x{:x}", + task.tid(), regs.rax, SYSCALL_STRING[regs.rax as usize], sys_frame.rip @@ -62,7 +64,13 @@ pub extern "C" fn fast_syscall_handler(sys_frame: &mut SyscallFrame, regs: &mut regs.rax, regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9, ); - dbgln!(syscall, "done syscall {} = {:?}", regs.rax, res); + dbgln!( + syscall, + "done syscall [task {}] {} = {:?}", + task.tid(), + SYSCALL_STRING[regs.rax as usize], + res + ); crate::arch::signal::arch_sys_check_signals(res, sys_frame, regs); } diff --git a/cykusz-rs/src/kernel/sched/round_robin.rs b/cykusz-rs/src/kernel/sched/round_robin.rs index 0550b3d8..809fca58 100644 --- a/cykusz-rs/src/kernel/sched/round_robin.rs +++ b/cykusz-rs/src/kernel/sched/round_robin.rs @@ -324,13 +324,17 @@ impl Queues { if let Some(task) = cursor.remove() { self.push_runnable_front(task, true); } + } else { + // if process was not stopped, wake it up in case it has some pending signals to process + self.wake(task, _lock) } } fn exit(&mut self, status: syscall_defs::waitpid::Status, lock: SpinGuard<()>) -> ! { let current = get_current(); - logln!( + dbgln!( + task, "exit tid: {}, sc: {}, wc: {}, st: {:?}", current.tid(), Arc::strong_count(current), diff --git a/cykusz-rs/src/kernel/sched/task_container.rs b/cykusz-rs/src/kernel/sched/task_container.rs index d2d1d259..81fefacf 100644 --- a/cykusz-rs/src/kernel/sched/task_container.rs +++ b/cykusz-rs/src/kernel/sched/task_container.rs @@ -1,6 +1,7 @@ use crate::kernel::sync::{LockApi, Spin}; use crate::kernel::task::Task; use alloc::sync::Arc; +use syscall_defs::signal::SigProcMask; pub struct TaskContainer { tasks: Spin>>, @@ -31,6 +32,12 @@ impl TaskContainer { pub fn close_all_tasks(&self) { let init = crate::kernel::init::init_task(); + init.signals().set_mask( + SigProcMask::Set, + Some(syscall_defs::signal::SIGCHLD as u64), + None, + ); + init.terminate_children(); let tasks = self.tasks.lock(); diff --git a/cykusz-rs/src/kernel/task/children_events.rs b/cykusz-rs/src/kernel/task/children_events.rs index 331196cd..38d6e546 100644 --- a/cykusz-rs/src/kernel/task/children_events.rs +++ b/cykusz-rs/src/kernel/task/children_events.rs @@ -91,6 +91,7 @@ impl WaitPidEvents { while let Some(t) = cur.get() { let status = t.waitpid_status(); + dbgln!(waitpid, "checking task {} = {:?}", t.tid(), status); if ((flags.exited() && (status.is_exited() || status.is_signaled())) || (flags.continued() && status.is_continued()) || (flags.stopped() && status.is_stopped())) @@ -123,7 +124,7 @@ impl WaitPidEvents { return Ok(Some(res)); } - return Ok(None); + Ok(None) } pub fn wait_thread( @@ -152,7 +153,7 @@ impl WaitPidEvents { status: &mut syscall_defs::waitpid::Status, flags: WaitPidFlags, ) -> SignalResult { - logln4!("{} waitpid {} {:?}", me.tid(), pid, flags); + dbgln!(waitpid, "{} waitpid {} {:?}", me.tid(), pid, flags); let ret = self.wait_on(me, flags, false, |t| { if !t.is_process_leader() { false @@ -165,9 +166,16 @@ impl WaitPidEvents { } } }); - logln4!("{} waitpid {} {:?} = {:?}", me.tid(), pid, flags, ret); - - return match ret { + dbgln!( + waitpid, + "{} waitpid {} {:?} = {:?}", + me.tid(), + pid, + flags, + ret + ); + + match ret { Ok(Some((tid, st))) => { *status = st; @@ -175,6 +183,6 @@ impl WaitPidEvents { } Ok(None) => Ok(Err(SyscallError::ECHILD)), Err(e) => Err(e), - }; + } } } diff --git a/cykusz-rs/src/kernel/task/mod.rs b/cykusz-rs/src/kernel/task/mod.rs index ae4012a9..48e28f85 100644 --- a/cykusz-rs/src/kernel/task/mod.rs +++ b/cykusz-rs/src/kernel/task/mod.rs @@ -14,7 +14,7 @@ use crate::arch::mm::VirtAddr; use crate::arch::task::Task as ArchTask; use crate::kernel::fs::dirent::DirEntryItem; use crate::kernel::fs::root_dentry; -use crate::kernel::sched::{new_task_tid, SleepFlags}; +use crate::kernel::sched::{current_task_ref, new_task_tid, SleepFlags}; use crate::kernel::signal::{SignalResult, Signals, KSIGSTOPTHR}; use crate::kernel::sync::{LockApi, RwSpin, Spin, SpinGuard}; use crate::kernel::task::children_events::WaitPidEvents; @@ -591,39 +591,56 @@ impl Task { } pub fn terminate_children(&self) { - for c in self - .children() - .iter() - .filter(|t| t.pid() != self.pid() && t.state() != TaskState::Unused) - { - dbgln!( - poweroff, - "sigkill to {} {}", - c.pid(), - if let Some(e) = c.exe() { - e.full_path() - } else { - String::new() - } - ); - c.signal(syscall_defs::signal::SIGKILL); - } + 'outer: loop { + for c in self + .children() + .iter() + .filter(|t| t.pid() != self.pid() && t.state() != TaskState::Unused) + { + dbgln!( + poweroff, + "sigkill to {} {}", + c.pid(), + if let Some(e) = c.exe() { + e.full_path() + } else { + String::new() + } + ); + c.signal(syscall_defs::signal::SIGKILL); + } - loop { - match self.wait_pid( - -1, - &mut syscall_defs::waitpid::Status::Invalid(0), - syscall_defs::waitpid::WaitPidFlags::all(), - ) { - Ok(Err(SyscallError::ECHILD)) => { - break; - } - Ok(Ok(pid)) => { - dbgln!(poweroff, "terminated child pid: {}", pid); - } - Err(_) => continue, - Ok(Err(e)) => { - panic!("Unexpected error from wait_pid {:?}", e); + 'inner: loop { + let mut status = syscall_defs::waitpid::Status::Invalid(0); + match self.wait_pid(-1, &mut status, syscall_defs::waitpid::WaitPidFlags::EXITED) { + Ok(Err(SyscallError::ECHILD)) => { + dbgln!(poweroff, "got ECHILD"); + break 'outer; + } + Ok(Ok(pid)) => { + dbgln!( + poweroff, + "terminated child pid: {} status: {:?}", + pid, + status + ); + } + Err(e) => { + dbgln!( + poweroff, + "got signal error {:?}, pending: {:#x} has_children: {}", + e, + self.signals().pending(), + !self.children.lock().is_empty() + ); + + if !self.children.lock().is_empty() { + break 'inner; + } + } + Ok(Err(e)) => { + panic!("Unexpected error from wait_pid {:?}", e); + } } } } @@ -773,7 +790,13 @@ impl Task { } pub fn signal(&self, sig: usize) -> bool { - logln5!("signal {} sig: {}", self.pid(), sig); + dbgln!( + signal, + "{}: signal {} sig: {}", + current_task_ref().tid(), + self.pid(), + sig + ); if self.state() != TaskState::Unused { self.do_signal(sig, false) } else { @@ -801,6 +824,7 @@ impl Task { parent.children_events.add_zombie(self.me()); if self.is_process_leader() { + dbgln!(waitpid, "signal zombie SIGCHILD by {}", self.tid()); parent.signal(SIGCHLD); } } @@ -811,6 +835,7 @@ impl Task { parent.children_events.add_continued(self.me()); if self.is_process_leader() { + dbgln!(waitpid, "signal cont SIGCHILD by {}", self.tid()); parent.signal(SIGCHLD); } } @@ -822,6 +847,7 @@ impl Task { parent.children_events.add_stopped(self.me()); if self.is_process_leader() { + dbgln!(waitpid, "signal stop SIGCHILD by {}", self.tid()); parent.signal(SIGCHLD); } } diff --git a/disk-scripts/fsck_disk_fix.sh b/disk-scripts/fsck_disk_fix.sh index 13fda7c7..53b65f34 100755 --- a/disk-scripts/fsck_disk_fix.sh +++ b/disk-scripts/fsck_disk_fix.sh @@ -5,8 +5,8 @@ set -e losetup -D losetup -P /dev/loop0 disk.img -sudo -u $USER fsck.ext2 /dev/loop0p1 -f -v -p -sudo -u $USER fsck.ext2 /dev/loop0p2 -f -v -p -sudo -u $USER fsck.ext2 /dev/loop0p3 -f -v -p +sudo -u $USER fsck.ext2 /dev/loop0p1 -f -v +sudo -u $USER fsck.ext2 /dev/loop0p2 -f -v +sudo -u $USER fsck.ext2 /dev/loop0p3 -f -v losetup -D diff --git a/disk-scripts/install_os.sh b/disk-scripts/install_os.sh index 69c5e3d5..9c232aab 100755 --- a/disk-scripts/install_os.sh +++ b/disk-scripts/install_os.sh @@ -32,7 +32,7 @@ fi sudo umount mnt PROGS="test testcpp hello stack nyancat ttytest fork poweroff stat fbdoom doom1.wad open_sleep" -RUST_PROGS="init shell mount umount unixsocket-server unixsocket-client forktest mprotecttest, playwav" +RUST_PROGS="init shell mount umount unixsocket-server unixsocket-client forktest mprotecttest playwav" sudo mount /dev/loop0p2 mnt sudo chown -R $USER:$USER mnt