Skip to content

Commit

Permalink
Fix more deadlocks on poweroff
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalmiel committed Oct 1, 2024
1 parent 4f79614 commit a7ff402
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ endif
debug: $(disk)
#qemu-system-x86_64 -drive format=raw,file=$(iso) -serial stdio -no-reboot -s -S -smp cpus=4 -no-shutdown -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=ck_net0 -device e1000,netdev=ck_net0,id=ck_nic0
#qemu-system-x86_64 -serial stdio -no-reboot -s -S -m 5811 -smp cpus=4 -no-shutdown -netdev user,id=mynet0,net=192.168.1.0/24,dhcpstart=192.168.1.128,hostfwd=tcp::4444-:80 -device e1000e,netdev=mynet0,id=ck_nic0 -drive format=raw,file=disk.img,if=none,id=test-img -device ich9-ahci,id=ahci -device ide-hd,drive=test-img,bus=ahci.0 -monitor /dev/stdout
qemu-system-x86_64 -serial stdio -no-reboot -s -S -m 5811 -smp cpus=4 -no-shutdown -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=hn0 -device e1000,netdev=hn0,id=nic1 -drive format=raw,file=disk.img,if=none,id=test-img -device ich9-ahci,id=ahci -device ide-hd,drive=test-img,bus=ahci.0 -audio driver=pipewire,model=hda -monitor /dev/stdout
qemu-system-x86_64 -serial stdio -no-reboot -s -S -m 5811 -smp cpus=4 -no-shutdown -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=hn0 -device e1000,netdev=hn0,id=nic1 -drive format=raw,file=disk.img,if=none,id=test-img -device ich9-ahci,id=ahci -device ide-hd,drive=test-img,bus=ahci.0 -audio driver=pipewire,model=hda -monitor /dev/stdout -enable-kvm

gdb:
@rust-gdb "$(kernel)" -ex "target remote :1234"
Expand Down
10 changes: 6 additions & 4 deletions cykusz-rs/src/arch/x86_64/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ pub extern "C" fn fast_syscall_handler(sys_frame: &mut SyscallFrame, regs: &mut
let task = current_task_ref();
dbgln!(
syscall,
"syscall [task {}] {} {}, ret: 0x{:x}",
"syscall [task {}] {} {}, ret: 0x{:x} int: {}",
task.tid(),
regs.rax,
SYSCALL_STRING[regs.rax as usize],
sys_frame.rip
sys_frame.rip,
crate::kernel::int::is_enabled()
);

let res = crate::kernel::syscall::syscall_handler(
Expand All @@ -66,10 +67,11 @@ pub extern "C" fn fast_syscall_handler(sys_frame: &mut SyscallFrame, regs: &mut

dbgln!(
syscall,
"done syscall [task {}] {} = {:?}",
"done syscall [task {}] {} = {:?} int {}",
task.tid(),
SYSCALL_STRING[regs.rax as usize],
res
res,
crate::kernel::int::is_enabled()
);

crate::arch::signal::arch_sys_check_signals(res, sys_frame, regs);
Expand Down
6 changes: 6 additions & 0 deletions cykusz-rs/src/kernel/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ pub trait LockApi<'a, T: ?Sized + 'a> {
type Guard: LockGuard;

fn lock(&'a self) -> Self::Guard;
fn lock_debug(&'a self, _debug: usize) -> Self::Guard {
self.lock()
}
fn try_lock(&'a self) -> Option<Self::Guard>;
fn lock_irq(&'a self) -> Self::Guard;
fn lock_irq_debug(&'a self, _debug: usize) -> Self::Guard {
self.lock_irq()
}
fn try_lock_irq(&'a self) -> Option<Self::Guard>;
}
22 changes: 13 additions & 9 deletions cykusz-rs/src/kernel/sync/spin_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,17 @@ impl<T> Spin<T> {
l: M::new(user_data),
}
}
}

pub fn lock_debug(&self, id: usize) -> SpinGuard<T> {
impl<'a, T: ?Sized + 'a> LockApi<'a, T> for Spin<T> {
type Guard = SpinGuard<'a, T>;

fn lock_debug(&self, id: usize) -> SpinGuard<T> {
let notify = self.notify && crate::kernel::sync::maybe_preempt_disable();

logln!("l: - {}", id);
dbgln!(lock, "l: - {}", id);
let lock = self.l.lock();
logln!("l: + {}", id);
dbgln!(lock, "l: + {}", id);

SpinGuard {
g: Some(lock),
Expand All @@ -55,11 +59,13 @@ impl<T> Spin<T> {
}
}

pub fn lock_irq_debug(&self, id: usize) -> SpinGuard<T> {
fn lock_irq_debug(&self, id: usize) -> SpinGuard<T> {
let int_enabled = crate::kernel::int::is_enabled();
crate::kernel::int::disable();

dbgln!(lock, "l: - {}", id);
let lock = self.l.lock();
dbgln!(lock, "l: + {}", id);

SpinGuard {
g: Some(lock),
Expand All @@ -68,10 +74,6 @@ impl<T> Spin<T> {
debug: id,
}
}
}

impl<'a, T: ?Sized + 'a> LockApi<'a, T> for Spin<T> {
type Guard = SpinGuard<'a, T>;

fn lock(&'a self) -> Self::Guard {
let notify = self.notify && crate::kernel::sync::maybe_preempt_disable();
Expand Down Expand Up @@ -192,7 +194,9 @@ impl<'a, T: ?Sized> SpinGuard<'a, T> {
impl<'a, T: ?Sized> Drop for SpinGuard<'a, T> {
fn drop(&mut self) {
drop(self.g.take());
if self.debug > 0 {}
if self.debug > 0 {
dbgln!(lock, "l: D {}", self.debug)
}
if self.notify {
crate::kernel::sched::preempt_enable();
}
Expand Down
1 change: 1 addition & 0 deletions cykusz-rs/src/kernel/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fn conditional_enable_int(sys: usize) {
use syscall_defs::*;
match sys {
SYS_FUTEX_WAKE | SYS_FUTEX_WAIT | SYS_KILL | SYS_EXIT | SYS_EXIT_THREAD | SYS_EXEC => {
assert!(!crate::int::is_enabled());
return;
}
_ => {
Expand Down
72 changes: 38 additions & 34 deletions cykusz-rs/src/kernel/task/children_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl WaitPidEvents {
no_intr: bool,
mut cond: impl FnMut(&Task) -> bool,
) -> SignalResult<Option<(usize, syscall_defs::waitpid::Status)>> {
let mut res = (0, syscall_defs::waitpid::Status::Invalid(0));
let mut res = (0, syscall_defs::waitpid::Status::Invalid(0), None);

let mut wq_flags: WaitQueueFlags = if flags.nohang() {
WaitQueueFlags::NO_HANG
Expand All @@ -86,42 +86,46 @@ impl WaitPidEvents {
wq_flags.insert(WaitQueueFlags::NON_INTERRUPTIBLE);
}

let result = self.wq.wait_lock_for(wq_flags, &self.tasks, |l| {
let mut cur = l.tasks.front_mut();

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()))
&& cond(t)
{
res = (t.tid(), status);

if status.is_exited() || status.is_signaled() {
t.remove_from_parent();

if t.is_process_leader() {
if let Err(e) = sessions().remove_process(&t.me()) {
panic!("Failed to remove process from a session {:?}", e);
}
}
let found = self
.wq
.wait_lock_for(wq_flags, &self.tasks, |l| {
let mut cur = l.tasks.front_mut();

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()))
&& cond(t)
{
res = (t.tid(), status, Some(t.me()));

cur.remove();

return true;
} else {
cur.move_next();
}
}

!me.children().iter().any(&mut cond)
})?
.is_some();

cur.remove();
if found && !res.1.is_invalid() {
if res.1.is_exited() || res.1.is_signaled() {
let task = res.2.unwrap();
task.remove_from_parent();

return true;
} else {
cur.move_next();
if task.is_process_leader() {
if let Err(e) = sessions().remove_process(&task) {
panic!("Failed to remove process from a session {:?}", e);
}
}
}

!me.children().iter().any(&mut cond)
})?;

if result.is_some() && !res.1.is_invalid() {
return Ok(Some(res));
return Ok(Some((res.0, res.1)));
}

Ok(None)
Expand All @@ -132,18 +136,18 @@ impl WaitPidEvents {
me: &Task,
pid: usize,
tid: usize,
flags: syscall_defs::waitpid::WaitPidFlags,
flags: WaitPidFlags,
no_intr: bool,
) -> SignalResult<SyscallResult> {
let res = self.wait_on(me, flags, no_intr, |t| {
!t.is_process_leader() && pid == t.pid() && (t.tid() == tid || tid == 0)
});

return match res {
match res {
Ok(Some((tid, _st))) => Ok(Ok(tid)),
Ok(None) => Ok(Err(SyscallError::ECHILD)),
Err(e) => Err(e),
};
}
}

pub fn wait_pid(
Expand Down
22 changes: 17 additions & 5 deletions cykusz-rs/src/kernel/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,9 @@ impl Task {
}

pub fn remove_child(&self, child: &Task) {
let mut children = self.children.lock();

if child.sibling.is_linked() {
let mut children = self.children.lock();

let mut cur = unsafe { children.cursor_mut_from_ptr(child) };

child.set_parent(None);
Expand All @@ -313,10 +313,9 @@ impl Task {
}

pub fn add_child(&self, child: Arc<Task>) {
let mut children = self.children.lock();

child.set_parent(Some(self.me()));

let mut children = self.children.lock();
children.push_back(child);
}

Expand All @@ -337,7 +336,13 @@ impl Task {
pub fn migrate_children_to_init(&self) {
let parent = crate::kernel::init::init_task();

let mut children = self.children.lock_irq();
dbgln!(
task,
"migrate to init, interrupts: {}",
crate::kernel::int::is_enabled()
);

let mut children = self.children.lock();

let mut cursor = children.front_mut();

Expand All @@ -353,6 +358,13 @@ impl Task {
}
}

drop(children);
dbgln!(
task,
"migrate to init fini, interrupts: {}",
crate::kernel::int::is_enabled()
);

// Migrate already dead child processes not waited for by the parent
parent.children_events.migrate(&self.children_events);
}
Expand Down
47 changes: 43 additions & 4 deletions cykusz-rs/src/kernel/utils/wait_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,45 @@ impl WaitQueue {
Ok(Some(lock))
}

pub fn wait_lock_for_debug<'a, T, G: LockApi<'a, T>, F: FnMut(&mut G::Guard) -> bool>(
&self,
flags: WaitQueueFlags,
mtx: &'a G,
debug: usize,
mut cond: F,
) -> SignalResult<Option<G::Guard>> {
let irq = flags.contains(WaitQueueFlags::IRQ_DISABLE);
let mut lock = if irq {
mtx.lock_irq_debug(debug)
} else {
mtx.lock_debug(debug)
};

if cond(&mut lock) {
return Ok(Some(lock));
} else if flags.contains(WaitQueueFlags::NO_HANG) {
return Ok(None);
}

let task = current_task();

let _guard = WaitQueueGuard::new(self, &task);

while !cond(&mut lock) {
drop(lock);

Self::do_await_io(flags, &task)?;

lock = if irq {
mtx.lock_irq_debug(debug)
} else {
mtx.lock_debug(debug)
};
}

Ok(Some(lock))
}

pub fn wait_for<F: FnMut() -> bool>(
&self,
flags: WaitQueueFlags,
Expand Down Expand Up @@ -229,7 +268,7 @@ impl WaitQueue {

t.wake_up();

return true;
true
}

pub fn notify_group(&self, gid: usize) -> bool {
Expand All @@ -244,7 +283,7 @@ impl WaitQueue {
let mut res = false;

for i in 0..len {
let t = tasks[i].clone();
let t = &tasks[i];

if t.gid() == gid {
t.wake_up();
Expand All @@ -253,7 +292,7 @@ impl WaitQueue {
}
}

return res;
res
}

pub fn notify_all(&self) -> bool {
Expand All @@ -267,7 +306,7 @@ impl WaitQueue {
let mut res = false;

for i in 0..len {
let t = tasks[i].clone();
let t = &tasks[i];

t.wake_up();

Expand Down

0 comments on commit a7ff402

Please sign in to comment.