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());
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user