Kernel: Userspace signal handlers are now called one at a time
I added a syscall for telling the kernel when signal execution has finished. We should send a random hash or id to the signal trampoline that we would include in the syscall, so validity of signal exit can be confirmed.
This commit is contained in:
parent
7391d91317
commit
adb14ba373
|
@ -46,6 +46,7 @@ set(KERNEL_SOURCES
|
|||
kernel/Scheduler.cpp
|
||||
kernel/Semaphore.cpp
|
||||
kernel/Serial.cpp
|
||||
kernel/Signal.cpp
|
||||
kernel/SpinLock.cpp
|
||||
kernel/SSP.cpp
|
||||
kernel/Storage/ATABus.cpp
|
||||
|
|
|
@ -24,6 +24,9 @@ signal_trampoline:
|
|||
movq 120(%rsp), %rax
|
||||
call *%rax
|
||||
|
||||
movq 128(%rsp), %rdi
|
||||
call signal_done
|
||||
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace Kernel
|
|||
void setup_exec();
|
||||
|
||||
bool has_signal_to_execute() const;
|
||||
void set_signal_done(int signal);
|
||||
void handle_next_signal();
|
||||
void handle_signal(int signal, uintptr_t& return_rsp, uintptr_t& return_rip);
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <kernel/Syscall.h>
|
||||
|
||||
extern "C" __attribute__((section(".userspace")))
|
||||
void signal_done(int signal)
|
||||
{
|
||||
Kernel::syscall(SYS_SIGNAL_DONE, signal);
|
||||
}
|
|
@ -22,6 +22,12 @@ namespace Kernel
|
|||
{
|
||||
Thread::current().set_in_syscall(true);
|
||||
|
||||
if (syscall == SYS_SIGNAL_DONE)
|
||||
{
|
||||
Thread::current().set_signal_done((int)arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile("sti");
|
||||
|
||||
(void)arg1;
|
||||
|
@ -149,6 +155,9 @@ namespace Kernel
|
|||
case SYS_SIGNAL:
|
||||
ret = Process::current().sys_signal((int)arg1, (void (*)(int))arg2);
|
||||
break;
|
||||
case SYS_SIGNAL_DONE:
|
||||
// Handled above
|
||||
ASSERT_NOT_REACHED();
|
||||
default:
|
||||
dwarnln("Unknown syscall {}", syscall);
|
||||
break;
|
||||
|
|
|
@ -150,6 +150,19 @@ namespace Kernel
|
|||
return !m_signal_queue.empty() && !m_handling_signal;
|
||||
}
|
||||
|
||||
void Thread::set_signal_done(int signal)
|
||||
{
|
||||
ASSERT(!interrupts_enabled());
|
||||
if (!m_handling_signal)
|
||||
derrorln("set_signal_done called while not handling singal");
|
||||
else if (m_signal_queue.empty())
|
||||
derrorln("set_signal_done called and there are no signals in queue");
|
||||
else if (m_signal_queue.front() != signal)
|
||||
derrorln("set_signal_done called with wrong signal");
|
||||
else
|
||||
m_signal_queue.pop();
|
||||
}
|
||||
|
||||
void Thread::handle_next_signal()
|
||||
{
|
||||
ASSERT(!interrupts_enabled());
|
||||
|
@ -167,8 +180,6 @@ namespace Kernel
|
|||
|
||||
vaddr_t signal_handler = process().m_signal_handlers[signal];
|
||||
|
||||
m_handling_signal = true;
|
||||
|
||||
// Skip masked and ignored signals
|
||||
if (m_signal_mask & (1ull << signal))
|
||||
;
|
||||
|
@ -176,13 +187,15 @@ namespace Kernel
|
|||
;
|
||||
else if (signal_handler != (vaddr_t)SIG_DFL)
|
||||
{
|
||||
// call userspace signal handlers
|
||||
// FIXME: signal trampoline should take a hash etc
|
||||
// to only allow marking signals done from it
|
||||
m_handling_signal = true;
|
||||
write_to_stack(return_rsp, return_rip);
|
||||
write_to_stack(return_rsp, signal);
|
||||
write_to_stack(return_rsp, signal_handler);
|
||||
return_rip = (uintptr_t)signal_trampoline;
|
||||
|
||||
// FIXME: we should only mark this signal as done when
|
||||
// handler returns
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,7 +254,6 @@ namespace Kernel
|
|||
}
|
||||
|
||||
m_signal_queue.pop();
|
||||
m_handling_signal = false;
|
||||
}
|
||||
|
||||
void Thread::validate_stack() const
|
||||
|
|
|
@ -44,6 +44,7 @@ __BEGIN_DECLS
|
|||
#define SYS_RAISE 37
|
||||
#define SYS_KILL 38
|
||||
#define SYS_SIGNAL 39
|
||||
#define SYS_SIGNAL_DONE 40
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -286,6 +286,9 @@ long syscall(long syscall, ...)
|
|||
ret = Kernel::syscall(SYS_SIGNAL, signal, (uintptr_t)handler);
|
||||
break;
|
||||
}
|
||||
case SYS_SIGNAL_DONE:
|
||||
// Should not be called by an user
|
||||
// fall through
|
||||
default:
|
||||
puts("LibC: Unhandeled syscall");
|
||||
ret = -ENOSYS;
|
||||
|
|
|
@ -281,6 +281,39 @@ int execute_command(BAN::Vector<BAN::String>& args)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
else if (args.front() == "signal-test"sv)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
if (signal(SIGSEGV, [](int) { printf("SIGSEGV\n"); }) == SIG_ERR)
|
||||
{
|
||||
perror("signal");
|
||||
exit(1);
|
||||
}
|
||||
printf("child\n");
|
||||
for (;;);
|
||||
}
|
||||
if (pid == -1)
|
||||
{
|
||||
perror("fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
if (kill(pid, SIGSEGV) == -1)
|
||||
{
|
||||
perror("kill");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
if (kill(pid, SIGTERM) == -1)
|
||||
{
|
||||
perror("kill");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (args.front() == "cd"sv)
|
||||
{
|
||||
if (args.size() > 2)
|
||||
|
|
Loading…
Reference in New Issue