summaryrefslogtreecommitdiff
path: root/lib/mlibc/sysdeps/managarm/generic/signals.cpp
blob: 486f3d439fe9b06b9002de6f01ece01993b9bae1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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