kernel+libc: Implement pause() and sigsuspend()
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-12-04 20:26:01 +01:00
parent 92ab403687
commit b619f717c8
Signed by: apio
GPG Key ID: B8A7D06E42258954
8 changed files with 73 additions and 6 deletions

View File

@ -9,7 +9,7 @@
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
_e(truncate) _e(ftruncate) _e(utimensat) _e(setitimer) _e(pledge) _e(memstat) \
_e(setsid) _e(getsid) _e(getgroups) _e(setgroups)
_e(setsid) _e(getsid) _e(getgroups) _e(setgroups) _e(pause) _e(sigsuspend)
enum Syscalls
{

View File

@ -50,19 +50,22 @@ load_tr:
extern switch_task
; Create a new artificial stack frame simulating an IRQ, saving all the callee-saved registers and triggering a task switch.
; As we know this function was called directly using the SysV ABI, instead of arbitrarily interrupting any function at any point,
; we can trash some of the caller-saved registers to save state (in this case RDI and RCX).
global kernel_yield
kernel_yield:
mov rdi, [rsp] ; return address is now in RDI
mov rcx, rsp ; save current RSP
mov rdi, [rsp] ; return address is now in RDI (caller-saved)
mov rcx, rsp ; save current RSP in RCX (caller-saved)
add rcx, 8 ; skip over the return address
mov eax, ss
push rax ; SS
push rcx ; RSP
push rcx ; RSP (saved in RCX)
pushfq ; RFLAGS
mov eax, cs
push rax ; CS
push rdi ; RIP
push rdi ; RIP (return address previously on stack, saved to RDI)
sub rsp, 24

View File

@ -148,3 +148,49 @@ Result<u64> sys_sigprocmask(Registers*, SyscallArgs args)
return 0;
}
Result<u64> sys_pause(Registers* regs, SyscallArgs)
{
auto* current = Scheduler::current();
while (1)
{
kernel_wait_for_event();
if (current->interrupted)
{
if (current->will_ignore_pending_signal())
{
current->process_pending_signals(regs);
continue;
}
return err(EINTR);
}
}
}
Result<u64> sys_sigsuspend(Registers* regs, SyscallArgs args)
{
const sigset_t* set = (const sigset_t*)args[0];
auto* current = Scheduler::current();
sigset_t kset;
if (!MemoryManager::copy_from_user_typed(set, &kset)) return err(EFAULT);
sigset_t oldset = current->signal_mask.value();
current->signal_mask = kset;
while (1)
{
kernel_wait_for_event();
if (current->interrupted)
{
if (current->will_ignore_pending_signal())
{
current->process_pending_signals(regs);
continue;
}
current->signal_mask = oldset;
return err(EINTR);
}
}
}

View File

@ -193,7 +193,7 @@ void Thread::process_pending_signals(Registers* current_regs)
}
}
// If we fail to deliver the signal (usually because there's not enough space on the stack), execute the
// default action.
// default action. FIXME: Should this be changed?
if (!deliver_signal(signo, current_regs)) goto default_signal;
return;
}

View File

@ -48,6 +48,9 @@ extern "C"
/* Check if a signal is in set.*/
int sigismember(const sigset_t* set, int signo);
/* Change the signal mask temporarily and wait for a signal to arrive. */
int sigsuspend(const sigset_t* set);
#ifdef __cplusplus
}
#endif

View File

@ -208,6 +208,9 @@ extern "C"
/* Get this process's list of supplementary groups. */
int getgroups(int size, gid_t* list);
/* Wait for a signal to arrive. */
int pause(void);
#ifdef __cplusplus
}
#endif

View File

@ -88,4 +88,10 @@ extern "C"
return (*set & (1 << (signo - 1))) > 0;
}
int sigsuspend(const sigset_t* set)
{
long rc = syscall(SYS_sigsuspend, set);
__errno_return(rc, int);
}
}

View File

@ -551,4 +551,10 @@ extern "C"
long rc = syscall(SYS_getgroups, size, list);
__errno_return(rc, int);
}
int pause()
{
long rc = syscall(SYS_pause);
__errno_return(rc, int);
}
}