diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 21ea3055..2dd291a7 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -158,10 +158,6 @@ namespace Kernel userspace_info_t m_userspace_info; ExitStatus m_exit_status; - vaddr_t m_signal_handlers[_SIGMAX + 1] { }; - uint64_t m_signal_mask { (1ull << SIGCHLD) | (1ull << SIGURG) }; - static_assert(_SIGMAX < 64); - BAN::UniqPtr m_page_table; BAN::RefPtr m_tty; }; diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 64c993c7..8e5dc5c1 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -1,10 +1,12 @@ #pragma once +#include #include #include #include #include +#include #include namespace Kernel @@ -35,6 +37,8 @@ namespace Kernel BAN::ErrorOr clone(Process*, uintptr_t rsp, uintptr_t rip); void setup_exec(); + void handle_signal(int signal, uintptr_t& return_rsp, uintptr_t& return_rip); + pid_t tid() const { return m_tid; } void set_rsp(uintptr_t rsp) { m_rsp = rsp; validate_stack(); } @@ -83,6 +87,12 @@ namespace Kernel bool m_in_syscall { false }; bool m_is_userspace { false }; + BAN::CircularQueue m_signal_queue; + vaddr_t m_signal_handlers[_SIGMAX + 1] { }; + uint64_t m_signal_mask { (1ull << SIGCHLD) | (1ull << SIGURG) }; + static_assert(_SIGMAX < 64); + + friend class Process; friend class Scheduler; }; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 25ac48de..0c761714 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -15,8 +15,6 @@ #include #include -extern "C" void signal_trampoline(); - namespace Kernel { @@ -795,81 +793,8 @@ namespace Kernel { if (signal < _SIGMIN || signal > _SIGMAX) return BAN::Error::from_errno(EINVAL); - - ASSERT(&Process::current() == this); - - // Skip masked (ignored) signals - if (m_signal_mask & (1ull << signal)) - return 0; - - LockGuard lock_guard(m_lock); - if (m_signal_handlers[signal]) - { - asm volatile("cli"); - - uintptr_t* return_rsp_ptr = (uintptr_t*)return_rsp; - *--return_rsp_ptr = return_rip; - *--return_rsp_ptr = signal; - *--return_rsp_ptr = m_signal_handlers[signal]; - - return_rsp = (uintptr_t)return_rsp_ptr; - return_rip = (uintptr_t)signal_trampoline; - } - else - { - switch (signal) - { - // Abnormal termination of the process with additional actions. - case SIGABRT: - case SIGBUS: - case SIGFPE: - case SIGILL: - case SIGQUIT: - case SIGSEGV: - case SIGSYS: - case SIGTRAP: - case SIGXCPU: - case SIGXFSZ: - // TODO: additional actions - // fall through - - // Abnormal termination of the process - case SIGALRM: - case SIGHUP: - case SIGINT: - case SIGKILL: - case SIGPIPE: - case SIGTERM: - case SIGUSR1: - case SIGUSR2: - case SIGPOLL: - case SIGPROF: - case SIGVTALRM: - { - auto message = BAN::String::formatted("killed by signal {}\n", signal); - (void)m_tty->write(0, message.data(), message.size()); - lock_guard.~LockGuard(); - exit(128 + signal); - ASSERT_NOT_REACHED(); - } - - // Ignore the signal - case SIGCHLD: - case SIGURG: - break; - - // Stop the process: - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - ASSERT_NOT_REACHED(); - - // Continue the process, if it is stopped; otherwise, ignore the signal. - case SIGCONT: - ASSERT_NOT_REACHED(); - } - } - + ASSERT(m_threads.size() == 1); + Thread::current().handle_signal(signal, return_rsp, return_rip); return 0; } diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 60faf591..571692df 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -7,17 +7,23 @@ #include #include + namespace Kernel { extern "C" void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv, char** envp); extern "C" uintptr_t read_rip(); - template + extern "C" void signal_trampoline(); + + template static void write_to_stack(uintptr_t& rsp, const T& value) { - rsp -= size; - memcpy((void*)rsp, (void*)&value, size); + rsp -= sizeof(uintptr_t); + if constexpr(sizeof(T) < sizeof(uintptr_t)) + *(uintptr_t*)rsp = (uintptr_t)value; + else + memcpy((void*)rsp, (void*)&value, sizeof(uintptr_t)); } static pid_t s_next_tid = 1; @@ -36,9 +42,9 @@ namespace Kernel thread->m_rip = (uintptr_t)entry; // Initialize stack for returning - write_to_stack(thread->m_rsp, thread); - write_to_stack(thread->m_rsp, &Thread::on_exit); - write_to_stack(thread->m_rsp, data); + write_to_stack(thread->m_rsp, thread); + write_to_stack(thread->m_rsp, &Thread::on_exit); + write_to_stack(thread->m_rsp, data); thread_deleter.disable(); @@ -131,12 +137,88 @@ namespace Kernel { // FIXME: don't use PageTableScope PageTableScope _(m_process->page_table()); - write_to_stack(m_rsp, this); - write_to_stack(m_rsp, &Thread::on_exit); - write_to_stack(m_rsp, nullptr); + write_to_stack(m_rsp, this); + write_to_stack(m_rsp, &Thread::on_exit); + write_to_stack(m_rsp, nullptr); } } + void Thread::handle_signal(int signal, uintptr_t& return_rsp, uintptr_t& return_rip) + { + ASSERT(signal >= _SIGMIN && signal <= _SIGMAX); + ASSERT(&Thread::current() == this); + + // Skip masked (ignored) signals + if (m_signal_mask & (1ull << signal)) + return; + + if (m_signal_handlers[signal]) + { + asm volatile("cli"); + write_to_stack(return_rsp, return_rip); + write_to_stack(return_rsp, signal); + write_to_stack(return_rsp, m_signal_handlers[signal]); + return_rip = (uintptr_t)signal_trampoline; + } + else + { + switch (signal) + { + // Abnormal termination of the process with additional actions. + case SIGABRT: + case SIGBUS: + case SIGFPE: + case SIGILL: + case SIGQUIT: + case SIGSEGV: + case SIGSYS: + case SIGTRAP: + case SIGXCPU: + case SIGXFSZ: + // TODO: additional actions + // fall through + + // Abnormal termination of the process + case SIGALRM: + case SIGHUP: + case SIGINT: + case SIGKILL: + case SIGPIPE: + case SIGTERM: + case SIGUSR1: + case SIGUSR2: + case SIGPOLL: + case SIGPROF: + case SIGVTALRM: + { + auto message = BAN::String::formatted("killed by signal {}\n", signal); + (void)process().tty().write(0, message.data(), message.size()); + process().exit(128 + signal); + ASSERT_NOT_REACHED(); + } + + // Ignore the signal + case SIGCHLD: + case SIGURG: + break; + + // Stop the process: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + ASSERT_NOT_REACHED(); + + // Continue the process, if it is stopped; otherwise, ignore the signal. + case SIGCONT: + ASSERT_NOT_REACHED(); + } + } + + asm volatile("cli"); + if (!m_signal_queue.empty() && m_signal_queue.front() == signal) + m_signal_queue.pop(); + } + void Thread::validate_stack() const { if (stack_base() <= m_rsp && m_rsp <= stack_base() + stack_size())