diff options
Diffstat (limited to 'lib/mlibc/sysdeps/managarm/generic/signals.cpp')
-rw-r--r-- | lib/mlibc/sysdeps/managarm/generic/signals.cpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/mlibc/sysdeps/managarm/generic/signals.cpp b/lib/mlibc/sysdeps/managarm/generic/signals.cpp new file mode 100644 index 0000000..486f3d4 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/signals.cpp @@ -0,0 +1,139 @@ +#include <bits/ensure.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <hel.h> +#include <hel-syscalls.h> + +#include <mlibc/debug.hpp> +#include <mlibc/allocator.hpp> +#include <mlibc/posix-pipe.hpp> +#include <mlibc/all-sysdeps.hpp> +#include <posix.frigg_bragi.hpp> + +#include <bragi/helpers-frigg.hpp> +#include <helix/ipc-structs.hpp> + +#include <protocols/posix/supercalls.hpp> + +extern "C" void __mlibc_signal_restore(); + +namespace mlibc { + +int sys_sigprocmask(int how, const sigset_t *set, sigset_t *retrieve) { + // This implementation is inherently signal-safe. + uint64_t former, unused; + if(set) { + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, how, *set, &former, &unused)); + }else{ + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, 0, 0, &former, &unused)); + } + if(retrieve) + *retrieve = former; + return 0; +} + +int sys_sigaction(int number, const struct sigaction *__restrict action, + struct sigaction *__restrict saved_action) { + SignalGuard sguard; + + // TODO: Respect restorer. __ensure(!(action->sa_flags & SA_RESTORER)); + + managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SIG_ACTION); + req.set_sig_number(number); + if(action) { + req.set_mode(1); + req.set_flags(action->sa_flags); + req.set_sig_mask(action->sa_mask); + if(action->sa_flags & SA_SIGINFO) { + req.set_sig_handler(reinterpret_cast<uintptr_t>(action->sa_sigaction)); + }else{ + req.set_sig_handler(reinterpret_cast<uintptr_t>(action->sa_handler)); + } + req.set_sig_restorer(reinterpret_cast<uintptr_t>(&__mlibc_signal_restore)); + } else { + req.set_mode(0); + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::posix::Errors::ILLEGAL_REQUEST) { + // This is only returned for servers, not for normal userspace. + return ENOSYS; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + + if(saved_action) { + saved_action->sa_flags = resp.flags(); + saved_action->sa_mask = resp.sig_mask(); + if(resp.flags() & SA_SIGINFO) { + saved_action->sa_sigaction = + reinterpret_cast<void (*)(int, siginfo_t *, void *)>(resp.sig_handler()); + }else{ + saved_action->sa_handler = reinterpret_cast<void (*)(int)>(resp.sig_handler()); + } + // TODO: saved_action->sa_restorer = resp.sig_restorer; + } + return 0; +} + +int sys_kill(int pid, int number) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2(kHelObserveSuperCall + posix::superSigKill, pid, number)); + return 0; +} + +int sys_tgkill(int, int tid, int number) { + return sys_kill(tid, number); +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + HelWord out; + + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2_1(kHelObserveSuperCall + posix::superSigAltStack, + reinterpret_cast<HelWord>(ss), + reinterpret_cast<HelWord>(oss), + &out)); + + return out; +} + +int sys_sigsuspend(const sigset_t *set) { + //SignalGuard sguard; + uint64_t former, seq, unused; + + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, *set, &former, &seq)); + HEL_CHECK(helSyscall1(kHelObserveSuperCall + posix::superSigSuspend, seq)); + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, former, &unused, &unused)); + + return EINTR; +} + +int sys_sigpending(sigset_t *set) { + uint64_t pendingMask; + + HEL_CHECK(helSyscall0_1(kHelObserveSuperCall + posix::superSigGetPending, &pendingMask)); + *set = pendingMask; + + return 0; +} + +} //namespace mlibc |