mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-23 01:32:14 -05:00
Kernel: Block a signal from being dispatched again until handler returns.
We don't handle nesting yet, but this is a step in the right direction.
This commit is contained in:
parent
b67d0a3632
commit
251293f2e1
Notes:
sideshowbarker
2024-07-19 15:33:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/251293f2e11
6 changed files with 110 additions and 69 deletions
|
@ -51,6 +51,8 @@ void BXVGADevice::set_register(word index, word data)
|
|||
|
||||
void BXVGADevice::set_resolution(int width, int height)
|
||||
{
|
||||
m_framebuffer_size = { width, height };
|
||||
|
||||
set_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
|
||||
set_register(VBE_DISPI_INDEX_XRES, (word)width);
|
||||
set_register(VBE_DISPI_INDEX_YRES, (word)height);
|
||||
|
|
|
@ -374,7 +374,7 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
|
|||
m_signal_stack_user_region = nullptr;
|
||||
m_display_framebuffer_region = nullptr;
|
||||
set_default_signal_dispositions();
|
||||
m_signal_mask = 0xffffffff;
|
||||
m_signal_mask = 0;
|
||||
m_pending_signals = 0;
|
||||
|
||||
for (int i = 0; i < m_fds.size(); ++i) {
|
||||
|
@ -778,13 +778,13 @@ void Process::send_signal(byte signal, Process* sender)
|
|||
|
||||
bool Process::has_unmasked_pending_signals() const
|
||||
{
|
||||
return m_pending_signals & m_signal_mask;
|
||||
return m_pending_signals & ~m_signal_mask;
|
||||
}
|
||||
|
||||
ShouldUnblockProcess Process::dispatch_one_pending_signal()
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
dword signal_candidates = m_pending_signals & m_signal_mask;
|
||||
dword signal_candidates = m_pending_signals & ~m_signal_mask;
|
||||
ASSERT(signal_candidates);
|
||||
|
||||
byte signal = 0;
|
||||
|
@ -854,7 +854,9 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
ASSERT_INTERRUPTS_DISABLED();
|
||||
ASSERT(signal < 32);
|
||||
|
||||
dbgprintf("dispatch_signal %s(%u) <- %u\n", name().characters(), pid(), signal);
|
||||
#ifdef SIGNAL_DEBUG
|
||||
kprintf("dispatch_signal %s(%u) <- %u\n", name().characters(), pid(), signal);
|
||||
#endif
|
||||
|
||||
auto& action = m_signal_action_data[signal];
|
||||
// FIXME: Implement SA_SIGINFO signal handlers.
|
||||
|
@ -890,10 +892,21 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
}
|
||||
|
||||
if (handler_laddr.as_ptr() == SIG_IGN) {
|
||||
dbgprintf("%s(%u) ignored signal %u\n", name().characters(), pid(), signal);
|
||||
#ifdef SIGNAL_DEBUG
|
||||
kprintf("%s(%u) ignored signal %u\n", name().characters(), pid(), signal);
|
||||
#endif
|
||||
return ShouldUnblockProcess::Yes;
|
||||
}
|
||||
|
||||
dword old_signal_mask = m_signal_mask;
|
||||
dword new_signal_mask = action.mask;
|
||||
if (action.flags & SA_NODEFER)
|
||||
new_signal_mask &= ~(1 << signal);
|
||||
else
|
||||
new_signal_mask |= 1 << signal;
|
||||
|
||||
m_signal_mask |= new_signal_mask;
|
||||
|
||||
Scheduler::prepare_to_modify_tss(*this);
|
||||
|
||||
word ret_cs = m_tss.cs;
|
||||
|
@ -902,11 +915,13 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
|
||||
bool interrupting_in_kernel = (ret_cs & 3) == 0;
|
||||
if (interrupting_in_kernel) {
|
||||
dbgprintf("dispatch_signal to %s(%u) in state=%s with return to %w:%x\n", name().characters(), pid(), to_string(state()), ret_cs, ret_eip);
|
||||
#ifdef SIGNAL_DEBUG
|
||||
kprintf("dispatch_signal to %s(%u) in state=%s with return to %w:%x\n", name().characters(), pid(), to_string(state()), ret_cs, ret_eip);
|
||||
#endif
|
||||
ASSERT(is_blocked());
|
||||
m_tss_to_resume_kernel = m_tss;
|
||||
#ifdef SIGNAL_DEBUG
|
||||
dbgprintf("resume tss pc: %w:%x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip);
|
||||
kprintf("resume tss pc: %w:%x\n", m_tss_to_resume_kernel.cs, m_tss_to_resume_kernel.eip);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -917,33 +932,31 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
m_signal_stack_user_region = allocate_region(LinearAddress(), default_userspace_stack_size, "signal stack (user)");
|
||||
ASSERT(m_signal_stack_user_region);
|
||||
m_signal_stack_kernel_region = allocate_region(LinearAddress(), default_userspace_stack_size, "signal stack (kernel)");
|
||||
ASSERT(m_signal_stack_user_region);
|
||||
ASSERT(m_signal_stack_kernel_region);
|
||||
}
|
||||
m_tss.ss = 0x23;
|
||||
m_tss.esp = m_signal_stack_user_region->laddr().offset(default_userspace_stack_size).get() & 0xfffffff8;
|
||||
m_tss.esp = m_signal_stack_user_region->laddr().offset(default_userspace_stack_size).get();
|
||||
m_tss.ss0 = 0x10;
|
||||
m_tss.esp0 = m_signal_stack_kernel_region->laddr().offset(default_userspace_stack_size).get() & 0xfffffff8;
|
||||
push_value_on_stack(ret_eflags);
|
||||
push_value_on_stack(ret_cs);
|
||||
push_value_on_stack(ret_eip);
|
||||
m_tss.esp0 = m_signal_stack_kernel_region->laddr().offset(default_userspace_stack_size).get();
|
||||
} else {
|
||||
push_value_on_stack(ret_cs);
|
||||
push_value_on_stack(ret_eip);
|
||||
push_value_on_stack(ret_eflags);
|
||||
|
||||
// PUSHA
|
||||
dword old_esp = m_tss.esp;
|
||||
push_value_on_stack(m_tss.eax);
|
||||
push_value_on_stack(m_tss.ecx);
|
||||
push_value_on_stack(m_tss.edx);
|
||||
push_value_on_stack(m_tss.ebx);
|
||||
push_value_on_stack(old_esp);
|
||||
push_value_on_stack(m_tss.ebp);
|
||||
push_value_on_stack(m_tss.esi);
|
||||
push_value_on_stack(m_tss.edi);
|
||||
}
|
||||
|
||||
// PUSHA
|
||||
dword old_esp = m_tss.esp;
|
||||
push_value_on_stack(m_tss.eax);
|
||||
push_value_on_stack(m_tss.ecx);
|
||||
push_value_on_stack(m_tss.edx);
|
||||
push_value_on_stack(m_tss.ebx);
|
||||
push_value_on_stack(old_esp);
|
||||
push_value_on_stack(m_tss.ebp);
|
||||
push_value_on_stack(m_tss.esi);
|
||||
push_value_on_stack(m_tss.edi);
|
||||
// PUSH old_signal_mask
|
||||
push_value_on_stack(old_signal_mask);
|
||||
|
||||
m_tss.eax = (dword)signal;
|
||||
m_tss.cs = 0x1b;
|
||||
m_tss.ds = 0x23;
|
||||
m_tss.es = 0x23;
|
||||
|
@ -957,6 +970,12 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "signal_trampoline", true, true);
|
||||
m_return_to_ring3_from_signal_trampoline = region->laddr();
|
||||
byte* code_ptr = m_return_to_ring3_from_signal_trampoline.as_ptr();
|
||||
*code_ptr++ = 0x5a; // pop edx
|
||||
*code_ptr++ = 0xb8; // mov eax, <dword>
|
||||
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
|
||||
code_ptr += sizeof(dword);
|
||||
*code_ptr++ = 0xcd; // int 0x82
|
||||
*code_ptr++ = 0x82;
|
||||
*code_ptr++ = 0x61; // popa
|
||||
*code_ptr++ = 0x9d; // popf
|
||||
*code_ptr++ = 0xc3; // ret
|
||||
|
@ -964,7 +983,12 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
*code_ptr++ = 0x0b;
|
||||
|
||||
m_return_to_ring0_from_signal_trampoline = LinearAddress((dword)code_ptr);
|
||||
*code_ptr++ = 0x61; // popa
|
||||
*code_ptr++ = 0x5a; // pop edx
|
||||
*code_ptr++ = 0xb8; // mov eax, <dword>
|
||||
*(dword*)code_ptr = Syscall::SC_restore_signal_mask;
|
||||
code_ptr += sizeof(dword);
|
||||
*code_ptr++ = 0xcd; // int 0x82
|
||||
*code_ptr++ = 0x82;
|
||||
*code_ptr++ = 0xb8; // mov eax, <dword>
|
||||
*(dword*)code_ptr = Syscall::SC_sigreturn;
|
||||
code_ptr += sizeof(dword);
|
||||
|
@ -972,12 +996,11 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
*code_ptr++ = 0x82;
|
||||
*code_ptr++ = 0x0f; // ud2
|
||||
*code_ptr++ = 0x0b;
|
||||
|
||||
// FIXME: For !SA_NODEFER, maybe we could do something like emitting an int 0x80 syscall here that
|
||||
// unmasks the signal so it can be received again? I guess then I would need one trampoline
|
||||
// per signal number if it's hard-coded, but it's just a few bytes per each.
|
||||
}
|
||||
|
||||
// FIXME: Should we worry about the stack being 16 byte aligned when entering a signal handler?
|
||||
push_value_on_stack(signal);
|
||||
|
||||
if (interrupting_in_kernel)
|
||||
push_value_on_stack(m_return_to_ring0_from_signal_trampoline.get());
|
||||
else
|
||||
|
@ -987,19 +1010,25 @@ ShouldUnblockProcess Process::dispatch_signal(byte signal)
|
|||
set_state(Skip1SchedulerPass);
|
||||
|
||||
#ifdef SIGNAL_DEBUG
|
||||
dbgprintf("signal: Okay, %s(%u) {%s} has been primed with signal handler %w:%x\n", name().characters(), pid(), to_string(state()), m_tss.cs, m_tss.eip);
|
||||
kprintf("signal: Okay, %s(%u) {%s} has been primed with signal handler %w:%x\n", name().characters(), pid(), to_string(state()), m_tss.cs, m_tss.eip);
|
||||
#endif
|
||||
return ShouldUnblockProcess::Yes;
|
||||
}
|
||||
|
||||
int Process::sys$restore_signal_mask(dword mask)
|
||||
{
|
||||
m_signal_mask = mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Process::sys$sigreturn()
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
Scheduler::prepare_to_modify_tss(*this);
|
||||
m_tss = m_tss_to_resume_kernel;
|
||||
#ifdef SIGNAL_DEBUG
|
||||
dbgprintf("sys$sigreturn in %s(%u)\n", name().characters(), pid());
|
||||
dbgprintf(" -> resuming execution at %w:%x\n", m_tss.cs, m_tss.eip);
|
||||
kprintf("sys$sigreturn in %s(%u)\n", name().characters(), pid());
|
||||
kprintf(" -> resuming execution at %w:%x\n", m_tss.cs, m_tss.eip);
|
||||
#endif
|
||||
set_state(Skip1SchedulerPass);
|
||||
Scheduler::yield();
|
||||
|
@ -2638,3 +2667,41 @@ void* Process::sys$get_shared_buffer(int shared_buffer_id)
|
|||
#endif
|
||||
return shared_buffer.retain(*this);
|
||||
}
|
||||
|
||||
const char* to_string(Process::State state)
|
||||
{
|
||||
switch (state) {
|
||||
case Process::Invalid: return "Invalid";
|
||||
case Process::Runnable: return "Runnable";
|
||||
case Process::Running: return "Running";
|
||||
case Process::Dying: return "Dying";
|
||||
case Process::Dead: return "Dead";
|
||||
case Process::Stopped: return "Stopped";
|
||||
case Process::Skip1SchedulerPass: return "Skip1";
|
||||
case Process::Skip0SchedulerPasses: return "Skip0";
|
||||
case Process::BlockedSleep: return "Sleep";
|
||||
case Process::BlockedWait: return "Wait";
|
||||
case Process::BlockedRead: return "Read";
|
||||
case Process::BlockedWrite: return "Write";
|
||||
case Process::BlockedSignal: return "Signal";
|
||||
case Process::BlockedSelect: return "Select";
|
||||
case Process::BlockedLurking: return "Lurking";
|
||||
case Process::BlockedConnect: return "Connect";
|
||||
case Process::BeingInspected: return "Inspect";
|
||||
}
|
||||
kprintf("to_string(Process::State): Invalid state: %u\n", state);
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* to_string(Process::Priority priority)
|
||||
{
|
||||
switch (priority) {
|
||||
case Process::LowPriority: return "Low";
|
||||
case Process::NormalPriority: return "Normal";
|
||||
case Process::HighPriority: return "High";
|
||||
}
|
||||
kprintf("to_string(Process::Priority): Invalid priority: %u\n", priority);
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -227,6 +227,7 @@ public:
|
|||
int sys$listen(int sockfd, int backlog);
|
||||
int sys$accept(int sockfd, sockaddr*, socklen_t*);
|
||||
int sys$connect(int sockfd, const sockaddr*, socklen_t);
|
||||
int sys$restore_signal_mask(dword mask);
|
||||
|
||||
int sys$create_shared_buffer(pid_t peer_pid, size_t, void** buffer);
|
||||
void* sys$get_shared_buffer(int shared_buffer_id);
|
||||
|
@ -365,7 +366,7 @@ private:
|
|||
size_t m_max_open_file_descriptors { 16 };
|
||||
SignalActionData m_signal_action_data[32];
|
||||
dword m_pending_signals { 0 };
|
||||
dword m_signal_mask { 0xffffffff };
|
||||
dword m_signal_mask { 0 };
|
||||
RetainPtr<Socket> m_blocked_connecting_socket;
|
||||
|
||||
byte m_termination_status { 0 };
|
||||
|
@ -439,41 +440,8 @@ private:
|
|||
Process::State m_original_state { Process::Invalid };
|
||||
};
|
||||
|
||||
static inline const char* to_string(Process::State state)
|
||||
{
|
||||
switch (state) {
|
||||
case Process::Invalid: return "Invalid";
|
||||
case Process::Runnable: return "Runnable";
|
||||
case Process::Running: return "Running";
|
||||
case Process::Dying: return "Dying";
|
||||
case Process::Dead: return "Dead";
|
||||
case Process::Stopped: return "Stopped";
|
||||
case Process::Skip1SchedulerPass: return "Skip1";
|
||||
case Process::Skip0SchedulerPasses: return "Skip0";
|
||||
case Process::BlockedSleep: return "Sleep";
|
||||
case Process::BlockedWait: return "Wait";
|
||||
case Process::BlockedRead: return "Read";
|
||||
case Process::BlockedWrite: return "Write";
|
||||
case Process::BlockedSignal: return "Signal";
|
||||
case Process::BlockedSelect: return "Select";
|
||||
case Process::BlockedLurking: return "Lurking";
|
||||
case Process::BlockedConnect: return "Connect";
|
||||
case Process::BeingInspected: return "Inspect";
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline const char* to_string(Process::Priority state)
|
||||
{
|
||||
switch (state) {
|
||||
case Process::LowPriority: return "Low";
|
||||
case Process::NormalPriority: return "Normal";
|
||||
case Process::HighPriority: return "High";
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
extern const char* to_string(Process::State);
|
||||
extern const char* to_string(Process::Priority);
|
||||
|
||||
extern void block(Process::State);
|
||||
extern void sleep(dword ticks);
|
||||
|
|
|
@ -221,6 +221,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->sys$release_shared_buffer((int)arg1);
|
||||
case Syscall::SC_chown:
|
||||
return current->sys$chown((const char*)arg1, (uid_t)arg2, (gid_t)arg3);
|
||||
case Syscall::SC_restore_signal_mask:
|
||||
return current->sys$restore_signal_mask((dword)arg1);
|
||||
default:
|
||||
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
__ENUMERATE_SYSCALL(chown) \
|
||||
__ENUMERATE_SYSCALL(fchmod) \
|
||||
__ENUMERATE_SYSCALL(symlink) \
|
||||
__ENUMERATE_SYSCALL(restore_signal_mask) \
|
||||
|
||||
|
||||
namespace Syscall {
|
||||
|
|
|
@ -249,6 +249,7 @@ struct sigaction {
|
|||
#define SA_NOCLDSTOP 1
|
||||
#define SA_NOCLDWAIT 2
|
||||
#define SA_SIGINFO 4
|
||||
#define SA_NODEFER 0x40000000
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
|
|
Loading…
Reference in a new issue