kernel+libc: Implement pause() and sigsuspend()
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
92ab403687
commit
b619f717c8
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user