forked from Bananymous/banan-os
Kernel: Implement process stopping and continuing
This commit is contained in:
parent
56684e753b
commit
791a541381
|
@ -188,6 +188,9 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
|
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
|
||||||
|
|
||||||
|
void set_stopped(bool stopped, int signal);
|
||||||
|
void wait_while_stopped();
|
||||||
|
|
||||||
static BAN::ErrorOr<void> kill(pid_t pid, int signal);
|
static BAN::ErrorOr<void> kill(pid_t pid, int signal);
|
||||||
BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
|
BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
|
||||||
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
|
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
|
||||||
|
@ -299,12 +302,11 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ChildExitStatus
|
struct ChildWaitStatus
|
||||||
{
|
{
|
||||||
pid_t pid { 0 };
|
pid_t pid { 0 };
|
||||||
pid_t pgrp { 0 };
|
pid_t pgrp { 0 };
|
||||||
int exit_code { 0 };
|
BAN::Optional<int> status;
|
||||||
bool exited { false };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Credentials m_credentials;
|
Credentials m_credentials;
|
||||||
|
@ -320,6 +322,9 @@ namespace Kernel
|
||||||
|
|
||||||
mutable Mutex m_process_lock;
|
mutable Mutex m_process_lock;
|
||||||
|
|
||||||
|
BAN::Atomic<bool> m_stopped { false };
|
||||||
|
ThreadBlocker m_stop_blocker;
|
||||||
|
|
||||||
VirtualFileSystem::File m_working_directory;
|
VirtualFileSystem::File m_working_directory;
|
||||||
VirtualFileSystem::File m_root_file;
|
VirtualFileSystem::File m_root_file;
|
||||||
|
|
||||||
|
@ -344,8 +349,9 @@ namespace Kernel
|
||||||
BAN::Vector<BAN::String> m_environ;
|
BAN::Vector<BAN::String> m_environ;
|
||||||
BAN::String m_executable;
|
BAN::String m_executable;
|
||||||
|
|
||||||
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
|
BAN::Vector<ChildWaitStatus> m_child_wait_statuses;
|
||||||
ThreadBlocker m_child_exit_blocker;
|
SpinLock m_child_wait_lock;
|
||||||
|
ThreadBlocker m_child_wait_blocker;
|
||||||
|
|
||||||
BAN::Atomic<bool> m_is_exiting { false };
|
BAN::Atomic<bool> m_is_exiting { false };
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||||
|
|
||||||
// Returns true, if thread is going to trigger signal
|
// Returns true, if thread is going to trigger signal
|
||||||
bool is_interrupted_by_signal() const;
|
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
||||||
|
|
||||||
// Returns true if pending signal can be added to thread
|
// Returns true if pending signal can be added to thread
|
||||||
bool can_add_signal_to_execute() const;
|
bool can_add_signal_to_execute() const;
|
||||||
|
@ -63,6 +63,13 @@ namespace Kernel
|
||||||
void add_signal(int signal);
|
void add_signal(int signal);
|
||||||
void set_suspend_signal_mask(uint64_t sigmask);
|
void set_suspend_signal_mask(uint64_t sigmask);
|
||||||
|
|
||||||
|
static bool is_stopping_signal(int signal);
|
||||||
|
static bool is_continuing_signal(int signal);
|
||||||
|
static bool is_terminating_signal(int signal);
|
||||||
|
static bool is_abnormal_terminating_signal(int signal);
|
||||||
|
static bool is_realtime_signal(int signal);
|
||||||
|
bool will_exit_because_of_signal() const;
|
||||||
|
|
||||||
BAN::ErrorOr<void> sigaltstack(const stack_t* ss, stack_t* oss);
|
BAN::ErrorOr<void> sigaltstack(const stack_t* ss, stack_t* oss);
|
||||||
|
|
||||||
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
|
// blocks current thread and returns either on unblock, eintr, spuriously or after timeout
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/InterruptController.h>
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||||
#include <kernel/Memory/FileBackedRegion.h>
|
#include <kernel/Memory/FileBackedRegion.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/MemoryBackedRegion.h>
|
#include <kernel/Memory/MemoryBackedRegion.h>
|
||||||
|
@ -295,21 +296,20 @@ namespace Kernel
|
||||||
|
|
||||||
if (parent_process)
|
if (parent_process)
|
||||||
{
|
{
|
||||||
LockGuard _(parent_process->m_process_lock);
|
SpinLockGuard _(parent_process->m_child_wait_lock);
|
||||||
|
|
||||||
for (auto& child : parent_process->m_child_exit_statuses)
|
for (auto& child : parent_process->m_child_wait_statuses)
|
||||||
{
|
{
|
||||||
if (child.pid != pid())
|
if (child.pid != pid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
child.exit_code = __WGENEXITCODE(status, signal);
|
child.status = __WGENEXITCODE(status, signal);
|
||||||
child.exited = true;
|
|
||||||
|
|
||||||
parent_process->add_pending_signal(SIGCHLD);
|
parent_process->add_pending_signal(SIGCHLD);
|
||||||
if (!parent_process->m_threads.empty())
|
if (!parent_process->m_threads.empty())
|
||||||
Processor::scheduler().unblock_thread(parent_process->m_threads.front());
|
Processor::scheduler().unblock_thread(parent_process->m_threads.front());
|
||||||
|
|
||||||
parent_process->m_child_exit_blocker.unblock();
|
parent_process->m_child_wait_blocker.unblock();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -588,8 +588,11 @@ namespace Kernel
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
ChildExitStatus* child_exit_status = nullptr;
|
ChildWaitStatus* child_exit_status = nullptr;
|
||||||
for (auto& child : m_child_exit_statuses)
|
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_child_wait_lock);
|
||||||
|
for (auto& child : m_child_wait_statuses)
|
||||||
{
|
{
|
||||||
if (child.pid != 0)
|
if (child.pid != 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -598,8 +601,9 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
if (child_exit_status == nullptr)
|
if (child_exit_status == nullptr)
|
||||||
{
|
{
|
||||||
TRY(m_child_exit_statuses.emplace_back());
|
TRY(m_child_wait_statuses.emplace_back());
|
||||||
child_exit_status = &m_child_exit_statuses.back();
|
child_exit_status = &m_child_wait_statuses.back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto working_directory = TRY(m_working_directory.clone());
|
auto working_directory = TRY(m_working_directory.clone());
|
||||||
|
@ -794,7 +798,7 @@ namespace Kernel
|
||||||
// FIXME: Add WCONTINUED and WUNTRACED when stopped/continued processes are added
|
// FIXME: Add WCONTINUED and WUNTRACED when stopped/continued processes are added
|
||||||
|
|
||||||
const auto pid_matches =
|
const auto pid_matches =
|
||||||
[&](const ChildExitStatus& child)
|
[&](const ChildWaitStatus& child)
|
||||||
{
|
{
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
return true;
|
return true;
|
||||||
|
@ -805,47 +809,67 @@ namespace Kernel
|
||||||
return child.pid == pid;
|
return child.pid == pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
pid_t child_pid = 0;
|
||||||
|
int child_status = 0;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
|
||||||
pid_t exited_pid = 0;
|
|
||||||
int exit_code = 0;
|
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto& child : m_child_exit_statuses)
|
|
||||||
|
SpinLockGuard sguard(m_child_wait_lock);
|
||||||
|
|
||||||
|
for (auto& child : m_child_wait_statuses)
|
||||||
{
|
{
|
||||||
if (!pid_matches(child))
|
if (!pid_matches(child))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
if (!child.exited)
|
if (!child.status.has_value())
|
||||||
continue;
|
continue;
|
||||||
exited_pid = child.pid;
|
|
||||||
exit_code = child.exit_code;
|
const int status = child.status.value();
|
||||||
child = {};
|
|
||||||
|
bool should_report = false;
|
||||||
|
if (WIFSTOPPED(status))
|
||||||
|
should_report = !!(options & WUNTRACED);
|
||||||
|
else if (WIFCONTINUED(status))
|
||||||
|
should_report = !!(options & WCONTINUED);
|
||||||
|
else
|
||||||
|
should_report = true;
|
||||||
|
|
||||||
|
if (!should_report)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
child_pid = child.pid;
|
||||||
|
child_status = status;
|
||||||
|
child.status = {};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (child_pid != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
return BAN::Error::from_errno(ECHILD);
|
return BAN::Error::from_errno(ECHILD);
|
||||||
}
|
|
||||||
|
|
||||||
if (exited_pid != 0)
|
|
||||||
{
|
|
||||||
if (stat_loc)
|
|
||||||
{
|
|
||||||
TRY(validate_pointer_access(stat_loc, sizeof(stat_loc), true));
|
|
||||||
*stat_loc = exit_code;
|
|
||||||
}
|
|
||||||
remove_pending_signal(SIGCHLD);
|
|
||||||
return exited_pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options & WNOHANG)
|
if (options & WNOHANG)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
TRY(Thread::current().block_or_eintr_indefinite(m_child_exit_blocker, &m_process_lock));
|
SpinLockGuardAsMutex smutex(sguard);
|
||||||
|
TRY(Thread::current().block_or_eintr_indefinite(m_child_wait_blocker, &smutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
|
if (stat_loc)
|
||||||
|
{
|
||||||
|
TRY(validate_pointer_access(stat_loc, sizeof(stat_loc), true));
|
||||||
|
*stat_loc = child_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_pending_signal(SIGCHLD);
|
||||||
|
return child_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_sleep(int seconds)
|
BAN::ErrorOr<long> Process::sys_sleep(int seconds)
|
||||||
|
@ -2583,6 +2607,69 @@ namespace Kernel
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Process::set_stopped(bool stopped, int signal)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_signal_lock);
|
||||||
|
|
||||||
|
Process* parent = nullptr;
|
||||||
|
|
||||||
|
for_each_process(
|
||||||
|
[&parent, this](Process& process) -> BAN::Iteration
|
||||||
|
{
|
||||||
|
if (process.pid() != m_parent)
|
||||||
|
return BAN::Iteration::Continue;
|
||||||
|
parent = &process;
|
||||||
|
return BAN::Iteration::Break;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parent != nullptr)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
SpinLockGuard _(parent->m_child_wait_lock);
|
||||||
|
|
||||||
|
for (auto& child : parent->m_child_wait_statuses)
|
||||||
|
{
|
||||||
|
if (child.pid != pid())
|
||||||
|
continue;
|
||||||
|
if (!child.status.has_value() || WIFCONTINUED(*child.status) || WIFSTOPPED(*child.status))
|
||||||
|
child.status = stopped
|
||||||
|
? __WGENSTOPCODE(signal)
|
||||||
|
: __WGENCONTCODE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->m_child_wait_blocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(m_signal_handlers[SIGCHLD].sa_flags & SA_NOCLDSTOP))
|
||||||
|
{
|
||||||
|
parent->add_pending_signal(SIGCHLD);
|
||||||
|
if (!parent->m_threads.empty())
|
||||||
|
Processor::scheduler().unblock_thread(parent->m_threads.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stopped = stopped;
|
||||||
|
m_stop_blocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::wait_while_stopped()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (Thread::current().will_exit_because_of_signal())
|
||||||
|
Thread::current().handle_signal();
|
||||||
|
|
||||||
|
SpinLockGuard guard(m_signal_lock);
|
||||||
|
if (!m_stopped)
|
||||||
|
break;
|
||||||
|
|
||||||
|
SpinLockGuardAsMutex smutex(guard);
|
||||||
|
m_stop_blocker.block_indefinite(&smutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::kill(pid_t pid, int signal)
|
BAN::ErrorOr<void> Process::kill(pid_t pid, int signal)
|
||||||
{
|
{
|
||||||
if (pid == 0 || pid == -1)
|
if (pid == 0 || pid == -1)
|
||||||
|
@ -2594,19 +2681,27 @@ namespace Kernel
|
||||||
for_each_process(
|
for_each_process(
|
||||||
[&](Process& process)
|
[&](Process& process)
|
||||||
{
|
{
|
||||||
if (pid == process.pid() || -pid == process.pgrp())
|
if (pid != process.pid() && -pid != process.pgrp())
|
||||||
{
|
return BAN::Iteration::Continue;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
if (signal)
|
|
||||||
|
if (signal == 0)
|
||||||
|
;
|
||||||
|
// NOTE: stopped signals go through thread's signal handling code
|
||||||
|
// because for example SIGTSTP can be ignored
|
||||||
|
else if (Thread::is_continuing_signal(signal))
|
||||||
|
process.set_stopped(false, signal);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
process.add_pending_signal(signal);
|
process.add_pending_signal(signal);
|
||||||
if (!process.m_threads.empty())
|
if (!process.m_threads.empty())
|
||||||
Processor::scheduler().unblock_thread(process.m_threads.front());
|
Processor::scheduler().unblock_thread(process.m_threads.front());
|
||||||
|
process.m_stop_blocker.unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pid > 0) ? BAN::Iteration::Break : BAN::Iteration::Continue;
|
return (pid > 0) ? BAN::Iteration::Break : BAN::Iteration::Continue;
|
||||||
}
|
}
|
||||||
return BAN::Iteration::Continue;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
|
@ -2623,8 +2718,17 @@ namespace Kernel
|
||||||
|
|
||||||
if (pid == m_pid)
|
if (pid == m_pid)
|
||||||
{
|
{
|
||||||
if (signal)
|
if (signal == 0)
|
||||||
|
;
|
||||||
|
// NOTE: stopped signals go through thread's signal handling code
|
||||||
|
// because for example SIGTSTP can be ignored
|
||||||
|
else if (Thread::is_continuing_signal(signal))
|
||||||
|
set_stopped(false, signal);
|
||||||
|
else
|
||||||
|
{
|
||||||
add_pending_signal(signal);
|
add_pending_signal(signal);
|
||||||
|
m_stop_blocker.unblock();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace Kernel
|
||||||
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
|
|
||||||
|
Process::current().wait_while_stopped();
|
||||||
|
|
||||||
BAN::ErrorOr<long> ret = BAN::Error::from_errno(ENOSYS);
|
BAN::ErrorOr<long> ret = BAN::Error::from_errno(ENOSYS);
|
||||||
|
|
||||||
const char* process_path = Process::current().name();
|
const char* process_path = Process::current().name();
|
||||||
|
@ -92,6 +94,8 @@ namespace Kernel
|
||||||
if (ret.is_error() && ret.error().is_kernel_error())
|
if (ret.is_error() && ret.error().is_kernel_error())
|
||||||
Kernel::panic("Kernel error while returning to userspace {}", ret.error());
|
Kernel::panic("Kernel error while returning to userspace {}", ret.error());
|
||||||
|
|
||||||
|
Process::current().wait_while_stopped();
|
||||||
|
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
auto& current_thread = Thread::current();
|
auto& current_thread = Thread::current();
|
||||||
|
|
|
@ -69,6 +69,77 @@ namespace Kernel
|
||||||
s_default_sse_storage_initialized = true;
|
s_default_sse_storage_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Thread::is_stopping_signal(int signal)
|
||||||
|
{
|
||||||
|
switch(signal)
|
||||||
|
{
|
||||||
|
case SIGSTOP:
|
||||||
|
case SIGTSTP:
|
||||||
|
case SIGTTIN:
|
||||||
|
case SIGTTOU:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::is_continuing_signal(int signal)
|
||||||
|
{
|
||||||
|
switch(signal)
|
||||||
|
{
|
||||||
|
case SIGCONT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::is_terminating_signal(int signal)
|
||||||
|
{
|
||||||
|
switch (signal)
|
||||||
|
{
|
||||||
|
case SIGALRM:
|
||||||
|
case SIGHUP:
|
||||||
|
case SIGINT:
|
||||||
|
case SIGKILL:
|
||||||
|
case SIGPIPE:
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGUSR1:
|
||||||
|
case SIGUSR2:
|
||||||
|
case SIGPOLL:
|
||||||
|
case SIGPROF:
|
||||||
|
case SIGVTALRM:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::is_abnormal_terminating_signal(int signal)
|
||||||
|
{
|
||||||
|
switch (signal)
|
||||||
|
{
|
||||||
|
case SIGABRT:
|
||||||
|
case SIGBUS:
|
||||||
|
case SIGFPE:
|
||||||
|
case SIGILL:
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGSEGV:
|
||||||
|
case SIGSYS:
|
||||||
|
case SIGTRAP:
|
||||||
|
case SIGXCPU:
|
||||||
|
case SIGXFSZ:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::is_realtime_signal(int signal)
|
||||||
|
{
|
||||||
|
return SIGRTMIN <= signal && signal <= SIGRTMAX;
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_default_ignored_signal(int signal)
|
static bool is_default_ignored_signal(int signal)
|
||||||
{
|
{
|
||||||
switch (signal)
|
switch (signal)
|
||||||
|
@ -79,7 +150,7 @@ namespace Kernel
|
||||||
case SIGCANCEL:
|
case SIGCANCEL:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return Thread::is_realtime_signal(signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,7 +529,7 @@ namespace Kernel
|
||||||
memset(&m_interrupt_registers, 0, sizeof(InterruptRegisters));
|
memset(&m_interrupt_registers, 0, sizeof(InterruptRegisters));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::is_interrupted_by_signal() const
|
bool Thread::is_interrupted_by_signal(bool skip_stop_and_cont) const
|
||||||
{
|
{
|
||||||
if (!is_userspace() || m_state != State::Executing)
|
if (!is_userspace() || m_state != State::Executing)
|
||||||
return false;
|
return false;
|
||||||
|
@ -472,6 +543,8 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (!(signals & ((uint64_t)1 << i)))
|
if (!(signals & ((uint64_t)1 << i)))
|
||||||
continue;
|
continue;
|
||||||
|
if (skip_stop_and_cont && (is_stopping_signal(i) || is_continuing_signal(i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
vaddr_t signal_handler;
|
vaddr_t signal_handler;
|
||||||
{
|
{
|
||||||
|
@ -501,13 +574,23 @@ namespace Kernel
|
||||||
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
|
return interrupt_stack.ip == (uintptr_t)signal_trampoline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Thread::will_exit_because_of_signal() const
|
||||||
|
{
|
||||||
|
const uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask();
|
||||||
|
const uint64_t signals = full_pending_mask & ~m_signal_block_mask;
|
||||||
|
for (size_t sig = _SIGMIN; sig <= _SIGMAX; sig++)
|
||||||
|
if (signals & (static_cast<uint64_t>(1) << sig))
|
||||||
|
if (is_terminating_signal(sig) || is_abnormal_terminating_signal(sig))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Thread::handle_signal(int signal)
|
bool Thread::handle_signal(int signal)
|
||||||
{
|
{
|
||||||
ASSERT(&Thread::current() == this);
|
ASSERT(&Thread::current() == this);
|
||||||
ASSERT(is_userspace());
|
ASSERT(is_userspace());
|
||||||
|
|
||||||
auto state = m_signal_lock.lock();
|
auto state = m_signal_lock.lock();
|
||||||
ASSERT(state == InterruptState::Disabled);
|
|
||||||
|
|
||||||
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
auto& interrupt_stack = *reinterpret_cast<InterruptStack*>(kernel_stack_top() - sizeof(InterruptStack));
|
||||||
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
|
ASSERT(GDT::is_user_segment(interrupt_stack.cs));
|
||||||
|
@ -613,51 +696,30 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (signal)
|
if (is_abnormal_terminating_signal(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:
|
|
||||||
process().exit(128 + signal, signal | 0x80);
|
process().exit(128 + signal, signal | 0x80);
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
// Abnormal termination of the process
|
else if (is_terminating_signal(signal))
|
||||||
case SIGALRM:
|
{
|
||||||
case SIGHUP:
|
|
||||||
case SIGINT:
|
|
||||||
case SIGKILL:
|
|
||||||
case SIGPIPE:
|
|
||||||
case SIGTERM:
|
|
||||||
case SIGUSR1:
|
|
||||||
case SIGUSR2:
|
|
||||||
case SIGPOLL:
|
|
||||||
case SIGPROF:
|
|
||||||
case SIGVTALRM:
|
|
||||||
process().exit(128 + signal, signal);
|
process().exit(128 + signal, signal);
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
else if (is_stopping_signal(signal))
|
||||||
|
{
|
||||||
|
process().set_stopped(true, signal);
|
||||||
|
}
|
||||||
|
else if (is_continuing_signal(signal))
|
||||||
|
{
|
||||||
|
process().set_stopped(false, signal);
|
||||||
|
}
|
||||||
|
else if (is_default_ignored_signal(signal))
|
||||||
|
{
|
||||||
|
|
||||||
// Stop the process:
|
}
|
||||||
case SIGSTOP:
|
else
|
||||||
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();
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (is_default_ignored_signal(signal))
|
|
||||||
break;
|
|
||||||
panic("Executing unhandled signal {}", signal);
|
panic("Executing unhandled signal {}", signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,20 +801,20 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> Thread::sleep_or_eintr_ns(uint64_t ns)
|
BAN::ErrorOr<void> Thread::sleep_or_eintr_ns(uint64_t ns)
|
||||||
{
|
{
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
SystemTimer::get().sleep_ns(ns);
|
SystemTimer::get().sleep_ns(ns);
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(ThreadBlocker& thread_blocker, BaseMutex* mutex)
|
BAN::ErrorOr<void> Thread::block_or_eintr_indefinite(ThreadBlocker& thread_blocker, BaseMutex* mutex)
|
||||||
{
|
{
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
thread_blocker.block_indefinite(mutex);
|
thread_blocker.block_indefinite(mutex);
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -765,10 +827,10 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> Thread::block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout, BaseMutex* mutex)
|
BAN::ErrorOr<void> Thread::block_or_eintr_or_waketime_ns(ThreadBlocker& thread_blocker, uint64_t wake_time_ns, bool etimedout, BaseMutex* mutex)
|
||||||
{
|
{
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
thread_blocker.block_with_wake_time_ns(wake_time_ns, mutex);
|
thread_blocker.block_with_wake_time_ns(wake_time_ns, mutex);
|
||||||
if (is_interrupted_by_signal())
|
if (is_interrupted_by_signal(true))
|
||||||
return BAN::Error::from_errno(EINTR);
|
return BAN::Error::from_errno(EINTR);
|
||||||
if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ns)
|
if (etimedout && SystemTimer::get().ms_since_boot() >= wake_time_ns)
|
||||||
return BAN::Error::from_errno(ETIMEDOUT);
|
return BAN::Error::from_errno(ETIMEDOUT);
|
||||||
|
|
|
@ -24,10 +24,13 @@ __BEGIN_DECLS
|
||||||
#define WSTOPSIG(status) WEXITSTATUS(status)
|
#define WSTOPSIG(status) WEXITSTATUS(status)
|
||||||
#define WTERMSIG(status) ((status) & 0x7F)
|
#define WTERMSIG(status) ((status) & 0x7F)
|
||||||
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
||||||
#define WIFSIGNALED(status) (((status) & 0x7F) > 0 && ((status) & 0x7F) < 0x7F)
|
#define WIFSIGNALED(status) (((status) & 0x7F) > 0 && ((status) & 0x7F) < 0x7E)
|
||||||
#define WIFSTOPPED(status) (((status) & 0xFF) == 0x7F)
|
#define WIFSTOPPED(status) (((status) & 0x7F) == 0x7F)
|
||||||
|
#define WIFCONTINUED(status) (((status) & 0x7F) == 0x7E)
|
||||||
|
|
||||||
#define __WGENEXITCODE(ret, sig) (((ret) << 8) | (sig))
|
#define __WGENEXITCODE(ret, sig) (((ret) << 8) | (sig))
|
||||||
|
#define __WGENSTOPCODE(sig) (((sig) << 8) | 0x7F)
|
||||||
|
#define __WGENCONTCODE() ( 0x7E)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue