diff --git a/apps/sh.cpp b/apps/sh.cpp index 6bca57cf..9d5bb3a2 100644 --- a/apps/sh.cpp +++ b/apps/sh.cpp @@ -31,6 +31,11 @@ static Result 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 luna_main(int argc, char** argv) { StringView path; StringView command; - bool interactive { false }; SharedPtr input_file; @@ -54,17 +58,15 @@ Result 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 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 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"); diff --git a/kernel/src/sys/file.cpp b/kernel/src/sys/file.cpp index 36e4153e..058d05f0 100644 --- a/kernel/src/sys/file.cpp +++ b/kernel/src/sys/file.cpp @@ -10,7 +10,7 @@ #include #include -Result sys_read(Registers*, SyscallArgs args) +Result sys_read(Registers* regs, SyscallArgs args) { int fd = (int)args[0]; u8* buf = (u8*)args[1]; @@ -31,6 +31,13 @@ Result 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)); diff --git a/kernel/src/sys/usleep.cpp b/kernel/src/sys/usleep.cpp index dbf853ae..06d1a1d4 100644 --- a/kernel/src/sys/usleep.cpp +++ b/kernel/src/sys/usleep.cpp @@ -11,5 +11,7 @@ Result sys_usleep(Registers*, SyscallArgs args) kernel_sleep(us / 1000); - return 0; + auto* current = Scheduler::current(); + + return current->sleep_ticks_left; } diff --git a/kernel/src/sys/waitpid.cpp b/kernel/src/sys/waitpid.cpp index 92220a0e..66834693 100644 --- a/kernel/src/sys/waitpid.cpp +++ b/kernel/src/sys/waitpid.cpp @@ -1,9 +1,10 @@ +#include "Log.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include -Result sys_waitpid(Registers*, SyscallArgs args) +Result sys_waitpid(Registers* regs, SyscallArgs args) { pid_t pid = (pid_t)args[0]; int* status_ptr = (int*)args[1]; @@ -21,7 +22,16 @@ Result 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 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::from_option(Scheduler::find_by_pid(*current->child_being_waited_for), ESRCH)); diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index e033d1b2..84686d23 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -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 }; diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp index 838fbbe6..5d21a1d9 100644 --- a/kernel/src/thread/Thread.cpp +++ b/kernel/src/thread/Thread.cpp @@ -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() diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index de69bbc6..a9639d4c 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -84,6 +84,7 @@ struct Thread : public LinkedListNode 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 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);