kernel+sh: Implement interruptible syscalls

This commit is contained in:
apio 2023-07-12 13:48:43 +02:00
parent 71ff763dd9
commit 9f45026cc2
Signed by: apio
GPG Key ID: B8A7D06E42258954
7 changed files with 77 additions and 10 deletions

View File

@ -31,6 +31,11 @@ static Result<void> execute_command(StringView command)
return os::Process::exec(args[0].view(), args.slice());
}
// Do nothing, but we need a handler so read() returns EINTR.
static void sigint_handler(int)
{
}
struct utsname g_sysinfo;
const char* hostname = "";
@ -41,7 +46,6 @@ Result<int> luna_main(int argc, char** argv)
{
StringView path;
StringView command;
bool interactive { false };
SharedPtr<File> input_file;
@ -54,17 +58,15 @@ Result<int> luna_main(int argc, char** argv)
if (!command.is_empty()) TRY(execute_command(command));
if (path == "-")
{
input_file = File::standard_input();
interactive = true;
}
if (path == "-") { input_file = File::standard_input(); }
else
{
input_file = TRY(File::open(path, File::ReadOnly));
input_file->set_close_on_exec();
}
bool interactive = isatty(input_file->fd());
if (interactive)
{
// Set up everything to form a prompt.
@ -77,6 +79,8 @@ Result<int> luna_main(int argc, char** argv)
if (pw) { username = pw->pw_name; }
else { username = getenv("USER"); }
endpwent();
signal(SIGINT, sigint_handler);
}
while (1)
@ -87,7 +91,14 @@ Result<int> luna_main(int argc, char** argv)
os::print("%s@%s:%s%c ", username, hostname, cwd.chars(), prompt_end);
}
auto cmd = TRY(input_file->read_line());
auto maybe_cmd = input_file->read_line();
if (maybe_cmd.has_error())
{
if (maybe_cmd.error() == EINTR) continue;
return maybe_cmd.release_error();
}
auto cmd = maybe_cmd.release_value();
if (cmd.is_empty())
{
if (interactive) puts("exit");

View File

@ -10,7 +10,7 @@
#include <luna/SafeArithmetic.h>
#include <sys/types.h>
Result<u64> sys_read(Registers*, SyscallArgs args)
Result<u64> sys_read(Registers* regs, SyscallArgs args)
{
int fd = (int)args[0];
u8* buf = (u8*)args[1];
@ -31,6 +31,13 @@ Result<u64> sys_read(Registers*, SyscallArgs args)
if (descriptor.should_block()) kernel_sleep(10);
else
return err(EAGAIN);
if (current->interrupted)
{
kdbgln("signal: read interrupted by signal");
if (current->will_invoke_signal_handler()) return err(EINTR);
current->process_pending_signals(regs);
}
}
usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size));

View File

@ -11,5 +11,7 @@ Result<u64> sys_usleep(Registers*, SyscallArgs args)
kernel_sleep(us / 1000);
return 0;
auto* current = Scheduler::current();
return current->sleep_ticks_left;
}

View File

@ -1,9 +1,10 @@
#include "Log.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/waitpid.h>
Result<u64> sys_waitpid(Registers*, SyscallArgs args)
Result<u64> sys_waitpid(Registers* regs, SyscallArgs args)
{
pid_t pid = (pid_t)args[0];
int* status_ptr = (int*)args[1];
@ -21,7 +22,16 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
if (options & WNOHANG) return err(EAGAIN);
wait_for_child:
if (thread->state != ThreadState::Exited) kernel_wait(pid);
if (current->interrupted)
{
kdbgln("signal: waitpid interrupted by signal");
if (current->will_invoke_signal_handler()) return err(EINTR);
current->process_pending_signals(regs);
goto wait_for_child;
}
check(thread->state == ThreadState::Exited);
}
else if (pid == -1)
@ -33,7 +43,16 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
{
if (options & WNOHANG) return err(EAGAIN);
wait_for_any_child:
kernel_wait(pid);
if (current->interrupted)
{
kdbgln("signal: waitpid interrupted by signal");
if (current->will_invoke_signal_handler()) return err(EINTR);
current->process_pending_signals(regs);
goto wait_for_any_child;
}
check(current->child_being_waited_for.value_or(-1) != -1);
thread = TRY(Result<Thread*>::from_option(Scheduler::find_by_pid(*current->child_being_waited_for), ESRCH));

View File

@ -135,6 +135,7 @@ namespace Scheduler
thread->state = ThreadState::None;
thread->is_kernel = false;
thread->id = 1;
thread->pgid = 1;
thread->name = name;
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };

View File

@ -133,6 +133,7 @@ static constexpr DefaultSignalAction default_actions[] = {
void Thread::process_pending_signals(Registers* current_regs)
{
interrupted = false;
for (int i = 0; i < NSIG; i++)
{
int signo = i + 1;
@ -175,10 +176,33 @@ void Thread::process_pending_signals(Registers* current_regs)
}
}
bool Thread::will_invoke_signal_handler()
{
for (int i = 0; i < NSIG; i++)
{
if (pending_signals & (1 << i))
{
int signo = i + 1;
if (signo != SIGKILL && signo != SIGSTOP && signal_mask & (1 << i)) continue;
auto handler = signal_handlers[i];
if (handler.sa_handler == SIG_IGN || handler.sa_handler == SIG_DFL) return false;
if (signo == SIGKILL || signo == SIGSTOP) return false;
return true;
}
}
return false;
}
void Thread::send_signal(int signo)
{
check(signo > 0 && signo <= NSIG);
pending_signals |= 1 << (signo - 1);
if (state == ThreadState::Waiting || state == ThreadState::Sleeping)
{
interrupted = true;
wake_up();
}
}
bool FileDescriptor::should_append()

View File

@ -84,6 +84,7 @@ struct Thread : public LinkedListNode<Thread>
struct sigaction signal_handlers[NSIG];
sigset_t signal_mask { 0 };
sigset_t pending_signals { 0 };
bool interrupted { false };
FPData fp_data;
@ -139,6 +140,8 @@ struct Thread : public LinkedListNode<Thread>
void process_pending_signals(Registers* current_regs);
bool will_invoke_signal_handler();
bool deliver_signal(int signo, Registers* current_regs);
void sigreturn(Registers* current_regs);