diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/arch/x86_64/IDT.cpp index 0d9199f6e6..028fda2689 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/arch/x86_64/IDT.cpp @@ -138,7 +138,10 @@ namespace IDT extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, Kernel::InterruptStack& interrupt_stack, const Registers* regs) { - Kernel::Thread::current().save_sse(); + bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11; + + if (from_userspace) + Kernel::Thread::current().save_sse(); pid_t tid = Kernel::Scheduler::current_tid(); pid_t pid = tid ? Kernel::Process::current().pid() : 0; @@ -198,22 +201,23 @@ namespace IDT Kernel::panic("Unhandled exception"); } - switch (Kernel::Thread::current().state()) - { - case Kernel::Thread::State::Terminating: - ASSERT_NOT_REACHED(); - case Kernel::Thread::State::Terminated: + // Don't continue exection when terminated + if (Kernel::Thread::current().state() == Kernel::Thread::State::Terminated) Kernel::Scheduler::get().execute_current_thread(); - default: - break; + + if (from_userspace) + { + ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminating); + Kernel::Thread::current().load_sse(); } - - Kernel::Thread::current().load_sse(); } extern "C" void cpp_irq_handler(uint64_t irq, Kernel::InterruptStack& interrupt_stack) { - Kernel::Thread::current().save_sse(); + bool from_userspace = (interrupt_stack.cs & 0b11) & 0b11; + + if (from_userspace) + Kernel::Thread::current().save_sse(); if (Kernel::Scheduler::current_tid()) { @@ -239,17 +243,15 @@ namespace IDT Kernel::Scheduler::get().reschedule_if_idling(); - switch (Kernel::Thread::current().state()) - { - case Kernel::Thread::State::Terminating: - ASSERT_NOT_REACHED(); - case Kernel::Thread::State::Terminated: + // Don't continue exection when terminated + if (Kernel::Thread::current().state() == Kernel::Thread::State::Terminated) Kernel::Scheduler::get().execute_current_thread(); - default: - break; - } - Kernel::Thread::current().load_sse(); + if (from_userspace) + { + ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminating); + Kernel::Thread::current().load_sse(); + } } static void flush_idt() diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index d401f040b4..ca8f7518b5 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -43,7 +43,7 @@ namespace Kernel ~Process(); void cleanup_function(); - void exit(int status); + void exit(int status, int signal); void add_thread(Thread*); void on_thread_exit(Thread&); diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 1de1b3eac9..be83ca2a9b 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -116,7 +116,6 @@ namespace Kernel alignas(16) uint8_t m_sse_storage[512]; - friend class TerminateBlocker; friend class Scheduler; }; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 7add607c5e..b2b8845665 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace Kernel { @@ -178,17 +179,17 @@ namespace Kernel ASSERT_NOT_REACHED(); } - void Process::exit(int status) + void Process::exit(int status, int signal) { LockGuard _(m_lock); - m_exit_status.exit_code = status; + m_exit_status.exit_code = __WGENEXITCODE(status, signal); for (auto* thread : m_threads) thread->set_terminating(); } BAN::ErrorOr Process::sys_exit(int status) { - exit(status); + exit(status, 0); Thread::TerminateBlocker _(Thread::current()); ASSERT_NOT_REACHED(); } @@ -427,11 +428,8 @@ namespace Kernel int Process::block_until_exit() { - ASSERT(s_process_lock.is_locked()); ASSERT(this != &Process::current()); - s_process_lock.unlock(); - m_lock.lock(); m_exit_status.waiting++; while (!m_exit_status.exited) @@ -445,8 +443,6 @@ namespace Kernel m_exit_status.waiting--; m_lock.unlock(); - s_process_lock.lock(); - return ret; } @@ -458,10 +454,12 @@ namespace Kernel if (options) return BAN::Error::from_errno(EINVAL); - LockGuard _(s_process_lock); - for (auto* process : s_processes) - if (process->pid() == pid) - target = process; + { + LockGuard _(s_process_lock); + for (auto* process : s_processes) + if (process->pid() == pid) + target = process; + } if (target == nullptr) return BAN::Error::from_errno(ECHILD); @@ -580,7 +578,6 @@ namespace Kernel BAN::ErrorOr Process::sys_read(int fd, void* buffer, size_t count) { - Thread::TerminateBlocker blocker(Thread::current()); LockGuard _(m_lock); return TRY(m_open_file_descriptors.read(fd, buffer, count)); } diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index f83f2fcfc3..55406e5d48 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -21,6 +21,8 @@ namespace Kernel extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, InterruptStack& interrupt_stack) { + ASSERT((interrupt_stack.cs & 0b11) == 0b11); + Thread::current().set_return_rsp(interrupt_stack.rsp); Thread::current().set_return_rip(interrupt_stack.rip); @@ -175,16 +177,11 @@ namespace Kernel asm volatile("cli"); - switch (Thread::current().state()) - { - case Thread::State::Terminating: - ASSERT_NOT_REACHED(); - case Thread::State::Terminated: - Scheduler::get().execute_current_thread(); - default: - break; - } + // Don't continue exection when terminated + if (Kernel::Thread::current().state() == Kernel::Thread::State::Terminated) + Kernel::Scheduler::get().execute_current_thread(); + ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminating); Thread::current().load_sse(); if (ret.is_error()) diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 8b34c8b7c1..a1f0dc6a32 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -29,36 +29,32 @@ namespace Kernel Thread::TerminateBlocker::TerminateBlocker(Thread& thread) : m_thread(thread) { + CriticalScope _; + + if (m_thread.state() == State::Executing || m_thread.m_terminate_blockers > 0) { - CriticalScope _; - - if (m_thread.state() == State::Executing || m_thread.m_terminate_blockers > 0) - { - m_thread.m_terminate_blockers++; - return; - } - - if (m_thread.state() == State::Terminating && m_thread.m_terminate_blockers == 0) - m_thread.m_state = State::Terminated; + m_thread.m_terminate_blockers++; + return; } + if (m_thread.state() == State::Terminating && m_thread.m_terminate_blockers == 0) + m_thread.m_state = State::Terminated; + while (true) Scheduler::get().reschedule(); } Thread::TerminateBlocker::~TerminateBlocker() { - { - CriticalScope _; - - m_thread.m_terminate_blockers--; + CriticalScope _; - if (m_thread.state() == State::Executing || m_thread.m_terminate_blockers > 0) - return; + m_thread.m_terminate_blockers--; - if (m_thread.state() == State::Terminating && m_thread.m_terminate_blockers == 0) - m_thread.m_state = State::Terminated; - } + if (m_thread.state() == State::Executing || m_thread.m_terminate_blockers > 0) + return; + + if (m_thread.state() == State::Terminating && m_thread.m_terminate_blockers == 0) + m_thread.m_state = State::Terminated; while (true) Scheduler::get().reschedule(); @@ -299,11 +295,8 @@ namespace Kernel case SIGTRAP: case SIGXCPU: case SIGXFSZ: - { - auto message = BAN::String::formatted("killed by signal {}\n", signal); - (void)process().tty().write(0, message.data(), message.size()); - } - // fall through + process().exit(128 + signal, signal | 0x80); + break; // Abnormal termination of the process case SIGALRM: @@ -317,10 +310,8 @@ namespace Kernel case SIGPOLL: case SIGPROF: case SIGVTALRM: - { - process().exit(128 + signal); + process().exit(128 + signal, signal); break; - } // Ignore the signal case SIGCHLD: