kernel+sh: Implement interruptible syscalls
This commit is contained in:
parent
71ff763dd9
commit
9f45026cc2
25
apps/sh.cpp
25
apps/sh.cpp
@ -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");
|
||||||
|
@ -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));
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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 };
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user