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()); 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; struct utsname g_sysinfo;
const char* hostname = ""; const char* hostname = "";
@ -41,7 +46,6 @@ Result<int> luna_main(int argc, char** argv)
{ {
StringView path; StringView path;
StringView command; StringView command;
bool interactive { false };
SharedPtr<File> input_file; 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 (!command.is_empty()) TRY(execute_command(command));
if (path == "-") if (path == "-") { input_file = File::standard_input(); }
{
input_file = File::standard_input();
interactive = true;
}
else else
{ {
input_file = TRY(File::open(path, File::ReadOnly)); input_file = TRY(File::open(path, File::ReadOnly));
input_file->set_close_on_exec(); input_file->set_close_on_exec();
} }
bool interactive = isatty(input_file->fd());
if (interactive) if (interactive)
{ {
// Set up everything to form a prompt. // 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; } if (pw) { username = pw->pw_name; }
else { username = getenv("USER"); } else { username = getenv("USER"); }
endpwent(); endpwent();
signal(SIGINT, sigint_handler);
} }
while (1) 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); 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 (cmd.is_empty())
{ {
if (interactive) puts("exit"); if (interactive) puts("exit");

View File

@ -10,7 +10,7 @@
#include <luna/SafeArithmetic.h> #include <luna/SafeArithmetic.h>
#include <sys/types.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]; int fd = (int)args[0];
u8* buf = (u8*)args[1]; u8* buf = (u8*)args[1];
@ -31,6 +31,13 @@ Result<u64> sys_read(Registers*, SyscallArgs args)
if (descriptor.should_block()) kernel_sleep(10); if (descriptor.should_block()) kernel_sleep(10);
else else
return err(EAGAIN); 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)); 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); 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 "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
#include <bits/waitpid.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]; pid_t pid = (pid_t)args[0];
int* status_ptr = (int*)args[1]; int* status_ptr = (int*)args[1];
@ -21,7 +22,16 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
if (options & WNOHANG) return err(EAGAIN); if (options & WNOHANG) return err(EAGAIN);
wait_for_child:
if (thread->state != ThreadState::Exited) kernel_wait(pid); 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); check(thread->state == ThreadState::Exited);
} }
else if (pid == -1) else if (pid == -1)
@ -33,7 +43,16 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
{ {
if (options & WNOHANG) return err(EAGAIN); if (options & WNOHANG) return err(EAGAIN);
wait_for_any_child:
kernel_wait(pid); 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); 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)); 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->state = ThreadState::None;
thread->is_kernel = false; thread->is_kernel = false;
thread->id = 1; thread->id = 1;
thread->pgid = 1;
thread->name = name; thread->name = name;
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 }; 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) void Thread::process_pending_signals(Registers* current_regs)
{ {
interrupted = false;
for (int i = 0; i < NSIG; i++) for (int i = 0; i < NSIG; i++)
{ {
int signo = i + 1; 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) void Thread::send_signal(int signo)
{ {
check(signo > 0 && signo <= NSIG); check(signo > 0 && signo <= NSIG);
pending_signals |= 1 << (signo - 1); pending_signals |= 1 << (signo - 1);
if (state == ThreadState::Waiting || state == ThreadState::Sleeping)
{
interrupted = true;
wake_up();
}
} }
bool FileDescriptor::should_append() bool FileDescriptor::should_append()

View File

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