user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
#include <hel-syscalls.h>
|
||||
#include <hel.h>
|
||||
|
||||
void __frigg_assert_fail(
|
||||
const char *assertion, const char *file, unsigned int line, const char *function
|
||||
) {
|
||||
mlibc::panicLogger() << "In function " << function << ", file " << file << ":" << line << "\n"
|
||||
<< "__ensure(" << assertion << ") failed" << frg::endlog;
|
||||
}
|
||||
|
||||
namespace mlibc {
|
||||
void sys_libc_log(const char *message) {
|
||||
// This implementation is inherently signal-safe.
|
||||
size_t n = 0;
|
||||
while (message[n])
|
||||
n++;
|
||||
HEL_CHECK(helLog(kHelLogSeverityInfo, message, n));
|
||||
}
|
||||
|
||||
void sys_libc_panic() {
|
||||
// This implementation is inherently signal-safe.
|
||||
const char *message = "mlibc: Panic!";
|
||||
size_t n = 0;
|
||||
while (message[n])
|
||||
n++;
|
||||
helPanic(message, n);
|
||||
}
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,135 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/auxv.h>
|
||||
|
||||
#include <frg/eternal.hpp>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/elf/startup.h>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
|
||||
#include <protocols/posix/data.hpp>
|
||||
#include <protocols/posix/supercalls.hpp>
|
||||
|
||||
extern "C" uintptr_t *__dlapi_entrystack();
|
||||
extern "C" void __dlapi_enter(uintptr_t *);
|
||||
|
||||
// declared in posix-pipe.hpp
|
||||
thread_local Queue globalQueue;
|
||||
|
||||
// TODO: clock tracker page and file table don't need to be thread-local!
|
||||
thread_local HelHandle __mlibc_posix_lane;
|
||||
thread_local void *__mlibc_clk_tracker_page;
|
||||
|
||||
namespace {
|
||||
thread_local unsigned __mlibc_gsf_nesting;
|
||||
thread_local posix::ThreadPage *__mlibc_cached_thread_page;
|
||||
thread_local HelHandle *cachedFileTable;
|
||||
|
||||
// This construction is a bit weird: Even though the variables above
|
||||
// are thread_local we still protect their initialization with a pthread_once_t
|
||||
// (instead of using a C++ constructor).
|
||||
// We do this in order to able to clear the pthread_once_t after a fork.
|
||||
thread_local pthread_once_t has_cached_infos = PTHREAD_ONCE_INIT;
|
||||
|
||||
void actuallyCacheInfos() {
|
||||
posix::ManagarmProcessData data;
|
||||
HEL_CHECK(
|
||||
helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast<HelWord>(&data))
|
||||
);
|
||||
|
||||
__mlibc_posix_lane = data.posixLane;
|
||||
__mlibc_cached_thread_page = data.threadPage;
|
||||
cachedFileTable = data.fileTable;
|
||||
__mlibc_clk_tracker_page = data.clockTrackerPage;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SignalGuard::SignalGuard() {
|
||||
pthread_once(&has_cached_infos, &actuallyCacheInfos);
|
||||
if (!__mlibc_cached_thread_page)
|
||||
return;
|
||||
|
||||
if (!__mlibc_gsf_nesting)
|
||||
__atomic_store_n(&__mlibc_cached_thread_page->globalSignalFlag, 1, __ATOMIC_RELAXED);
|
||||
__mlibc_gsf_nesting++;
|
||||
}
|
||||
|
||||
SignalGuard::~SignalGuard() {
|
||||
pthread_once(&has_cached_infos, &actuallyCacheInfos);
|
||||
if (!__mlibc_cached_thread_page)
|
||||
return;
|
||||
|
||||
__ensure(__mlibc_gsf_nesting > 0);
|
||||
__mlibc_gsf_nesting--;
|
||||
if (!__mlibc_gsf_nesting) {
|
||||
unsigned int result =
|
||||
__atomic_exchange_n(&__mlibc_cached_thread_page->globalSignalFlag, 0, __ATOMIC_RELAXED);
|
||||
if (result == 2) {
|
||||
HEL_CHECK(helSyscall0(kHelCallSuper + posix::superSigRaise));
|
||||
} else {
|
||||
__ensure(result == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAllocator &getSysdepsAllocator() {
|
||||
// use frg::eternal to prevent a call to __cxa_atexit().
|
||||
// this is necessary because __cxa_atexit() call this function.
|
||||
static frg::eternal<VirtualAllocator> virtualAllocator;
|
||||
static frg::eternal<MemoryPool> heap{virtualAllocator.get()};
|
||||
static frg::eternal<MemoryAllocator> singleton{&heap.get()};
|
||||
return singleton.get();
|
||||
}
|
||||
|
||||
HelHandle getPosixLane() {
|
||||
cacheFileTable();
|
||||
return __mlibc_posix_lane;
|
||||
}
|
||||
|
||||
HelHandle *cacheFileTable() {
|
||||
// TODO: Make sure that this is signal-safe (it is called e.g. by sys_clock_get()).
|
||||
pthread_once(&has_cached_infos, &actuallyCacheInfos);
|
||||
return cachedFileTable;
|
||||
}
|
||||
|
||||
HelHandle getHandleForFd(int fd) {
|
||||
if (fd >= 512)
|
||||
return 0;
|
||||
|
||||
return cacheFileTable()[fd];
|
||||
}
|
||||
|
||||
void clearCachedInfos() { has_cached_infos = PTHREAD_ONCE_INIT; }
|
||||
|
||||
void resetCancellationId() {
|
||||
pthread_once(&has_cached_infos, &actuallyCacheInfos);
|
||||
__atomic_store_n(&__mlibc_cached_thread_page->cancellationId, 0, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
void setCancellationId(uint64_t id, HelHandle handle, int fd) {
|
||||
pthread_once(&has_cached_infos, &actuallyCacheInfos);
|
||||
|
||||
__mlibc_cached_thread_page->lane = handle;
|
||||
__mlibc_cached_thread_page->fd = fd;
|
||||
|
||||
__atomic_store_n(&__mlibc_cached_thread_page->cancellationId, id, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
namespace {
|
||||
thread_local uint64_t cancellationId = 1;
|
||||
} // namespace
|
||||
|
||||
uint64_t allocateCancellationId() { return cancellationId++; }
|
||||
|
||||
extern char **environ;
|
||||
|
||||
extern "C" void
|
||||
__mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) {
|
||||
__dlapi_enter(entry_stack);
|
||||
auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ);
|
||||
exit(result);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,791 @@
|
||||
|
||||
// for _Exit()
|
||||
#include <bits/errors.hpp>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// for fork() and execve()
|
||||
#include <unistd.h>
|
||||
// for sched_yield()
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
// for getrusage()
|
||||
#include <sys/resource.h>
|
||||
// for waitpid()
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
#include <mlibc/thread-entry.hpp>
|
||||
#include <posix.frigg_bragi.hpp>
|
||||
#include <protocols/posix/supercalls.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_futex_tid() {
|
||||
HelWord tid = 0;
|
||||
HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, &tid));
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
int sys_futex_wait(int *pointer, int expected, const struct timespec *time) {
|
||||
// This implementation is inherently signal-safe.
|
||||
if (time) {
|
||||
if (helFutexWait(pointer, expected, time->tv_nsec + time->tv_sec * 1000000000))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if (helFutexWait(pointer, expected, -1))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_futex_wake(int *pointer) {
|
||||
// This implementation is inherently signal-safe.
|
||||
if (helFutexWake(pointer))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
if (ru) {
|
||||
mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog;
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_request_type(managarm::posix::CntReqType::WAIT);
|
||||
req.set_pid(pid);
|
||||
req.set_flags(flags);
|
||||
req.set_cancellation_id(allocateCancellationId());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSyncCancellable(
|
||||
getPosixLane(),
|
||||
req.cancellation_id(),
|
||||
-1,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
*ret_pid = resp.pid();
|
||||
if (*ret_pid == 0)
|
||||
return 0;
|
||||
|
||||
if (status)
|
||||
*status = resp.mode();
|
||||
|
||||
if (ru != nullptr) {
|
||||
ru->ru_utime.tv_sec = resp.ru_user_time() / 1'000'000'000;
|
||||
ru->ru_utime.tv_usec = (resp.ru_user_time() % 1'000'000'000) / 1'000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::WaitIdRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_idtype(idtype);
|
||||
req.set_id(id);
|
||||
req.set_flags(options);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::WaitIdResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
info->si_pid = resp.pid();
|
||||
info->si_uid = resp.uid();
|
||||
info->si_code = resp.sig_code();
|
||||
switch (info->si_code) {
|
||||
case CLD_EXITED:
|
||||
info->si_status = WEXITSTATUS(resp.sig_status());
|
||||
break;
|
||||
case CLD_KILLED:
|
||||
case CLD_DUMPED:
|
||||
case CLD_STOPPED:
|
||||
info->si_signo = WSTOPSIG(resp.sig_status());
|
||||
break;
|
||||
case CLD_CONTINUED:
|
||||
info->si_signo = SIGCHLD;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_exit(int status) {
|
||||
// This implementation is inherently signal-safe.
|
||||
HEL_CHECK(helSyscall1(kHelCallSuper + posix::superExit, status));
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
void sys_yield() {
|
||||
// This implementation is inherently signal-safe.
|
||||
HEL_CHECK(helYield());
|
||||
}
|
||||
|
||||
int sys_sleep(time_t *secs, long *nanos) {
|
||||
SignalGuard sguard;
|
||||
globalQueue.trim();
|
||||
|
||||
uint64_t now;
|
||||
HEL_CHECK(helGetClock(&now));
|
||||
|
||||
uint64_t async_id;
|
||||
HEL_CHECK(helSubmitAwaitClock(
|
||||
now + uint64_t(*secs) * 1000000000 + uint64_t(*nanos), globalQueue.getQueue(), 0, &async_id
|
||||
));
|
||||
|
||||
auto element = globalQueue.dequeueSingle();
|
||||
auto result = parseSimple(element);
|
||||
HEL_CHECK(result->error);
|
||||
|
||||
*secs = 0;
|
||||
*nanos = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_fork(pid_t *child) {
|
||||
// This implementation is inherently signal-safe.
|
||||
int res;
|
||||
|
||||
sigset_t full_sigset;
|
||||
res = sigfillset(&full_sigset);
|
||||
__ensure(!res);
|
||||
|
||||
sigset_t former_sigset;
|
||||
res = sigprocmask(SIG_SETMASK, &full_sigset, &former_sigset);
|
||||
__ensure(!res);
|
||||
|
||||
HelWord out;
|
||||
HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superFork, &out));
|
||||
*child = out;
|
||||
|
||||
if (!out) {
|
||||
clearCachedInfos();
|
||||
globalQueue.recreateQueue();
|
||||
}
|
||||
|
||||
res = sigprocmask(SIG_SETMASK, &former_sigset, nullptr);
|
||||
__ensure(!res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_execve(const char *path, char *const argv[], char *const envp[]) {
|
||||
// TODO: Make this function signal-safe!
|
||||
frg::string<MemoryAllocator> args_area(getSysdepsAllocator());
|
||||
for (auto it = argv; *it; ++it)
|
||||
args_area += frg::string_view{*it, strlen(*it) + 1};
|
||||
|
||||
frg::string<MemoryAllocator> env_area(getSysdepsAllocator());
|
||||
for (auto it = envp; *it; ++it)
|
||||
env_area += frg::string_view{*it, strlen(*it) + 1};
|
||||
|
||||
uintptr_t out;
|
||||
|
||||
HEL_CHECK(helSyscall6_1(
|
||||
kHelCallSuper + posix::superExecve,
|
||||
reinterpret_cast<uintptr_t>(path),
|
||||
strlen(path),
|
||||
reinterpret_cast<uintptr_t>(args_area.data()),
|
||||
args_area.size(),
|
||||
reinterpret_cast<uintptr_t>(env_area.data()),
|
||||
env_area.size(),
|
||||
&out
|
||||
));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
gid_t sys_getgid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetGidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.uid();
|
||||
}
|
||||
|
||||
int sys_setgid(gid_t gid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::SetGidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_uid(gid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gid_t sys_getegid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetEgidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.uid();
|
||||
}
|
||||
|
||||
int sys_setegid(gid_t egid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::SetEgidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_uid(egid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) {
|
||||
// TODO: handle saved set-user-ID
|
||||
(void)sgid;
|
||||
|
||||
int real = sys_setgid(rgid);
|
||||
if (real)
|
||||
return real;
|
||||
|
||||
int effective = sys_setegid(egid);
|
||||
if (effective)
|
||||
return effective;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uid_t sys_getuid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetUidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.uid();
|
||||
}
|
||||
|
||||
int sys_setuid(uid_t uid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::SetUidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_uid(uid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uid_t sys_geteuid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetEuidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.uid();
|
||||
}
|
||||
|
||||
int sys_seteuid(uid_t euid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::SetEuidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_uid(euid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) {
|
||||
// TODO: handle saved set-user-ID
|
||||
(void)suid;
|
||||
|
||||
int real = sys_setuid(ruid);
|
||||
if (real)
|
||||
return real;
|
||||
|
||||
int effective = sys_seteuid(euid);
|
||||
if (effective)
|
||||
return effective;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setreuid(uid_t ruid, uid_t euid) {
|
||||
int real = sys_setuid(ruid);
|
||||
if (real)
|
||||
return real;
|
||||
|
||||
int effective = sys_seteuid(euid);
|
||||
if (effective)
|
||||
return effective;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setregid(gid_t rgid, gid_t egid) {
|
||||
int real = sys_setgid(rgid);
|
||||
if (real)
|
||||
return real;
|
||||
|
||||
int effective = sys_setegid(egid);
|
||||
if (effective)
|
||||
return effective;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t sys_gettid() {
|
||||
HelWord tid = 0;
|
||||
HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, &tid));
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
pid_t sys_getpid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetPidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.pid();
|
||||
}
|
||||
|
||||
pid_t sys_getppid() {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetPpidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
return resp.pid();
|
||||
}
|
||||
|
||||
int sys_getsid(pid_t pid, pid_t *sid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetSidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_pid(pid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::NO_SUCH_RESOURCE) {
|
||||
*sid = 0;
|
||||
return ESRCH;
|
||||
} else if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
*sid = resp.pid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getpgid(pid_t pid, pid_t *pgid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetPgidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_pid(pid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::NO_SUCH_RESOURCE) {
|
||||
*pgid = 0;
|
||||
return ESRCH;
|
||||
} else if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
*pgid = resp.pid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setpgid(pid_t pid, pid_t pgid) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::SetPgidRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_pid(pid);
|
||||
req.set_pgid(pgid);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getrusage(int scope, struct rusage *usage) {
|
||||
memset(usage, 0, sizeof(struct rusage));
|
||||
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_request_type(managarm::posix::CntReqType::GET_RESOURCE_USAGE);
|
||||
req.set_mode(scope);
|
||||
|
||||
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
usage->ru_utime.tv_sec = resp.ru_user_time() / 1'000'000'000;
|
||||
usage->ru_utime.tv_usec = (resp.ru_user_time() % 1'000'000'000) / 1'000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getschedparam(void *tcb, int *policy, struct sched_param *param) {
|
||||
if (tcb != mlibc::get_current_tcb()) {
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
*policy = SCHED_OTHER;
|
||||
int prio = 0;
|
||||
// TODO(no92): use helGetPriority(kHelThisThread) here
|
||||
mlibc::infoLogger() << "\e[31mlibc: sys_getschedparam always returns priority 0\e[39m"
|
||||
<< frg::endlog;
|
||||
param->sched_priority = prio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setschedparam(void *tcb, int policy, const struct sched_param *param) {
|
||||
if (tcb != mlibc::get_current_tcb()) {
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
if (policy != SCHED_OTHER) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
HEL_CHECK(helSetPriority(kHelThisThread, param->sched_priority));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_clone(void *tcb, pid_t *tid_out, void *stack) {
|
||||
(void)tcb;
|
||||
|
||||
HelWord posixErr = 0;
|
||||
HelWord tid = 0;
|
||||
posix::superCloneArgs args{
|
||||
.flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD),
|
||||
};
|
||||
|
||||
HEL_CHECK(helSyscall3_2(
|
||||
kHelCallSuper + posix::superClone,
|
||||
reinterpret_cast<HelWord>(__mlibc_start_thread),
|
||||
reinterpret_cast<HelWord>(stack),
|
||||
reinterpret_cast<HelWord>(&args),
|
||||
&posixErr,
|
||||
&tid
|
||||
));
|
||||
|
||||
if (posixErr)
|
||||
return managarm::posix::Errors(posixErr) | toErrno;
|
||||
|
||||
if (tid_out)
|
||||
*tid_out = tid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_tcb_set(void *pointer) {
|
||||
#if defined(__x86_64__)
|
||||
HEL_CHECK(helWriteFsBase(pointer));
|
||||
#elif defined(__aarch64__)
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(pointer);
|
||||
addr += sizeof(Tcb) - 0x10;
|
||||
asm volatile("msr tpidr_el0, %0" ::"r"(addr));
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
uintptr_t tp = reinterpret_cast<uintptr_t>(pointer) + sizeof(Tcb);
|
||||
asm volatile("mv tp, %0" : : "r"(tp) : "memory");
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_thread_exit() {
|
||||
// This implementation is inherently signal-safe.
|
||||
HEL_CHECK(helSyscall1(kHelCallSuper + posix::superThreadExit, 0));
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
int sys_thread_setname(void *tcb, const char *name) {
|
||||
if (strlen(name) > 15) {
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
auto t = reinterpret_cast<Tcb *>(tcb);
|
||||
char *path;
|
||||
int cs = 0;
|
||||
|
||||
if (asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
int fd;
|
||||
if (int e = sys_open(path, O_WRONLY, 0, &fd); e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
if (int e = sys_write(fd, name, strlen(name) + 1, nullptr)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_thread_getname(void *tcb, char *name, size_t size) {
|
||||
auto t = reinterpret_cast<Tcb *>(tcb);
|
||||
char *path;
|
||||
int cs = 0;
|
||||
ssize_t real_size = 0;
|
||||
|
||||
if (asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||
|
||||
int fd;
|
||||
if (int e = sys_open(path, O_RDONLY | O_CLOEXEC, 0, &fd); e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
if (int e = sys_read(fd, name, size, &real_size)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
name[real_size - 1] = 0;
|
||||
sys_close(fd);
|
||||
|
||||
pthread_setcancelstate(cs, nullptr);
|
||||
|
||||
if (static_cast<ssize_t>(size) <= real_size) {
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <protocols/posix/supercalls.hpp>
|
||||
|
||||
#include <hel-syscalls.h>
|
||||
#include <hel.h>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_anon_allocate(size_t size, void **pointer) {
|
||||
// This implementation is inherently signal-safe.
|
||||
__ensure(!(size & 0xFFF));
|
||||
HelWord out;
|
||||
HEL_CHECK(helSyscall1_1(kHelCallSuper + posix::superAnonAllocate, size, &out));
|
||||
*pointer = reinterpret_cast<void *>(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_anon_free(void *pointer, size_t size) {
|
||||
// This implementation is inherently signal-safe.
|
||||
HEL_CHECK(helSyscall2(kHelCallSuper + posix::superAnonDeallocate, (HelWord)pointer, size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <bits/errors.hpp>
|
||||
#include <bragi/helpers-frigg.hpp>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
#include <posix.frigg_bragi.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int
|
||||
sys_mount(const char *source, const char *target, const char *fstype, unsigned long, const void *) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::MountRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), source ? source : ""));
|
||||
req.set_target_path(frg::string<MemoryAllocator>(getSysdepsAllocator(), target ? target : ""));
|
||||
req.set_fs_type(frg::string<MemoryAllocator>(getSysdepsAllocator(), fstype ? fstype : ""));
|
||||
|
||||
auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(send_tail.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
auto resp =
|
||||
*bragi::parse_head_only<managarm::posix::SvrResponse>(recv_resp, getSysdepsAllocator());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <errno.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "generic-helpers/netlink.hpp"
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_if_indextoname(unsigned int index, char *name) {
|
||||
int fd = 0;
|
||||
int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
struct ifreq ifr;
|
||||
ifr.ifr_ifindex = index;
|
||||
|
||||
int res = 0;
|
||||
int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, &res);
|
||||
close(fd);
|
||||
|
||||
if (ret) {
|
||||
if (ret == ENODEV)
|
||||
return ENXIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_if_nametoindex(const char *name, unsigned int *ret) {
|
||||
int fd = 0;
|
||||
int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
struct ifreq ifr;
|
||||
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
||||
|
||||
int res = 0;
|
||||
r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, &res);
|
||||
close(fd);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
*ret = ifr.ifr_ifindex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getifaddrs(struct ifaddrs **out) {
|
||||
NetlinkHelper nl;
|
||||
*out = nullptr;
|
||||
|
||||
bool link_ret = nl.send_request(RTM_GETLINK) && nl.recv(&getifaddrs_callback, out);
|
||||
__ensure(link_ret);
|
||||
bool addr_ret = nl.send_request(RTM_GETADDR) && nl.recv(&getifaddrs_callback, out);
|
||||
__ensure(addr_ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(MLIBC_BUILDING_RTLD)
|
||||
int sys_inet_configured(bool *ipv4, bool *ipv6) {
|
||||
struct context {
|
||||
bool *ipv4;
|
||||
bool *ipv6;
|
||||
} context = {.ipv4 = ipv4, .ipv6 = ipv6};
|
||||
|
||||
NetlinkHelper nl;
|
||||
if (!nl.send_request(RTM_GETADDR)) {
|
||||
*ipv4 = false;
|
||||
*ipv6 = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ret = nl.recv(
|
||||
[](void *data, const nlmsghdr *hdr) {
|
||||
if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_len >= sizeof(struct ifaddrmsg)) {
|
||||
const struct ifaddrmsg *ifaddr =
|
||||
reinterpret_cast<const struct ifaddrmsg *>(NLMSG_DATA(hdr));
|
||||
struct context *ctx = reinterpret_cast<struct context *>(data);
|
||||
|
||||
char name[IF_NAMESIZE];
|
||||
auto interfaceNameResult = sys_if_indextoname(ifaddr->ifa_index, name);
|
||||
|
||||
if (interfaceNameResult || !strncmp(name, "lo", IF_NAMESIZE))
|
||||
return;
|
||||
|
||||
if (ifaddr->ifa_family == AF_INET)
|
||||
*ctx->ipv4 = true;
|
||||
else if (ifaddr->ifa_family == AF_INET6)
|
||||
*ctx->ipv6 = true;
|
||||
}
|
||||
},
|
||||
&context
|
||||
);
|
||||
|
||||
if (!ret) {
|
||||
*ipv4 = false;
|
||||
*ipv6 = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // !defined(MLIBC_BUILDING_RTLD)
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hel-syscalls.h>
|
||||
#include <hel.h>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
#include <mlibc/posix-sysdeps.hpp>
|
||||
|
||||
#include <posix.frigg_bragi.hpp>
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_getscheduler(pid_t, int *policy) {
|
||||
*policy = SCHED_OTHER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) {
|
||||
return sys_getthreadaffinity(pid, cpusetsize, mask);
|
||||
}
|
||||
|
||||
int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::GetAffinityRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_pid(tid);
|
||||
req.set_size(cpusetsize);
|
||||
|
||||
auto [offer, send_head, recv_resp, recv_data] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::recvInline(),
|
||||
helix_ng::recvBuffer(mask, cpusetsize)
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.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_ARGUMENTS) {
|
||||
return EINVAL;
|
||||
} else if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!"
|
||||
<< frg::endlog;
|
||||
return EIEIO;
|
||||
}
|
||||
HEL_CHECK(recv_data.error());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask) {
|
||||
return sys_setthreadaffinity(pid, cpusetsize, mask);
|
||||
}
|
||||
|
||||
int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask) {
|
||||
SignalGuard sguard;
|
||||
|
||||
frg::vector<uint8_t, MemoryAllocator> affinity_mask(getSysdepsAllocator());
|
||||
affinity_mask.resize(cpusetsize);
|
||||
memcpy(affinity_mask.data(), mask, cpusetsize);
|
||||
managarm::posix::SetAffinityRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
|
||||
req.set_pid(tid);
|
||||
req.set_mask(affinity_mask);
|
||||
|
||||
auto [offer, send_head, send_tail, recv_resp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_head.error());
|
||||
HEL_CHECK(send_tail.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_ARGUMENTS) {
|
||||
return EINVAL;
|
||||
} else if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!"
|
||||
<< frg::endlog;
|
||||
return EIEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_getcpu(int *cpu) {
|
||||
HEL_CHECK(helGetCurrentCpu(cpu));
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,195 @@
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hel-syscalls.h>
|
||||
#include <hel.h>
|
||||
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-pipe.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,
|
||||
*reinterpret_cast<const HelWord *>(set),
|
||||
&former,
|
||||
&unused
|
||||
));
|
||||
} else {
|
||||
HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, 0, 0, &former, &unused)
|
||||
);
|
||||
}
|
||||
if (retrieve)
|
||||
*reinterpret_cast<uint64_t *>(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(*reinterpret_cast<const uint64_t *>(&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();
|
||||
*reinterpret_cast<uint64_t *>(&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.
|
||||
HelWord out;
|
||||
HEL_CHECK(helSyscall2_1(kHelObserveSuperCall + posix::superSigKill, pid, number, &out));
|
||||
return out;
|
||||
}
|
||||
|
||||
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,
|
||||
*reinterpret_cast<const HelWord *>(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));
|
||||
*reinterpret_cast<uint64_t *>(set) = pendingMask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_pause() {
|
||||
HelWord set = 0;
|
||||
uint64_t former, seq;
|
||||
|
||||
// no-op to obtain a seqnum
|
||||
HEL_CHECK(
|
||||
helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_BLOCK, set, &former, &seq)
|
||||
);
|
||||
HEL_CHECK(helSyscall1(kHelObserveSuperCall + posix::superSigSuspend, seq));
|
||||
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
int sys_sigtimedwait(
|
||||
const sigset_t *__restrict set,
|
||||
siginfo_t *__restrict info,
|
||||
const struct timespec *__restrict timeout,
|
||||
int *out_signal
|
||||
) {
|
||||
uint64_t nanos = timeout ? (timeout->tv_nsec + timeout->tv_sec * 1'000'000'000) : UINT64_MAX;
|
||||
HelWord status;
|
||||
HelWord signal;
|
||||
|
||||
HEL_CHECK(helSyscall3_2(
|
||||
kHelObserveSuperCall + posix::superSigTimedWait,
|
||||
*reinterpret_cast<const HelWord *>(set),
|
||||
nanos,
|
||||
reinterpret_cast<HelWord>(info),
|
||||
&status,
|
||||
&signal
|
||||
));
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
*out_signal = signal;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,625 @@
|
||||
#include <array>
|
||||
#include <asm/socket.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <errno.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <bits/errors.hpp>
|
||||
#include <fs.frigg_bragi.hpp>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
#include <posix.frigg_bragi.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
int fcntl_helper(int fd, int request, int *result, ...) {
|
||||
va_list args;
|
||||
va_start(args, result);
|
||||
if (!mlibc::sys_fcntl) {
|
||||
return ENOSYS;
|
||||
}
|
||||
int ret = mlibc::sys_fcntl(fd, request, args, result);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) {
|
||||
SignalGuard sguard;
|
||||
|
||||
managarm::posix::AcceptRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_fd(fd);
|
||||
|
||||
auto [offer, sendReq, recvResp] = exchangeMsgsSync(
|
||||
getPosixLane(),
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(sendReq.error());
|
||||
HEL_CHECK(recvResp.error());
|
||||
|
||||
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recvResp.data(), recvResp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
return resp.error() | toErrno;
|
||||
} else {
|
||||
*newfd = resp.fd();
|
||||
}
|
||||
|
||||
if (addr_ptr && addr_length) {
|
||||
if (int e = mlibc::sys_peername(*newfd, addr_ptr, *addr_length, addr_length); e) {
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SOCK_NONBLOCK) {
|
||||
int fcntl_ret = 0;
|
||||
fcntl_helper(*newfd, F_GETFL, &fcntl_ret);
|
||||
fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK);
|
||||
}
|
||||
|
||||
if (flags & SOCK_CLOEXEC) {
|
||||
int fcntl_ret = 0;
|
||||
fcntl_helper(*newfd, F_GETFD, &fcntl_ret);
|
||||
fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) {
|
||||
SignalGuard sguard;
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_req_type(managarm::fs::CntReqType::PT_BIND);
|
||||
|
||||
auto [offer, send_req, send_creds, send_buf, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::imbueCredentials(),
|
||||
helix_ng::sendBuffer(addr_ptr, addr_length),
|
||||
helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(send_creds.error());
|
||||
HEL_CHECK(send_buf.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_req_type(managarm::fs::CntReqType::PT_CONNECT);
|
||||
|
||||
frg::string<MemoryAllocator> ser(getSysdepsAllocator());
|
||||
req.SerializeToString(&ser);
|
||||
|
||||
auto [offer, send_req, imbue_creds, send_addr, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBuffer(ser.data(), ser.size()),
|
||||
helix_ng::imbueCredentials(),
|
||||
helix_ng::sendBuffer(const_cast<struct sockaddr *>(addr_ptr), addr_length),
|
||||
helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(imbue_creds.error());
|
||||
HEL_CHECK(send_addr.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
int sys_sockname(
|
||||
int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length
|
||||
) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_req_type(managarm::fs::CntReqType::PT_SOCKNAME);
|
||||
req.set_fd(fd);
|
||||
req.set_size(max_addr_length);
|
||||
|
||||
auto [offer, send_req, recv_resp, recv_addr] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::recvInline(),
|
||||
helix_ng::recvBuffer(addr_ptr, max_addr_length)
|
||||
)
|
||||
);
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() == managarm::fs::Errors::SUCCESS) {
|
||||
HEL_CHECK(recv_addr.error());
|
||||
*actual_length = resp.file_size();
|
||||
return 0;
|
||||
}
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
int sys_peername(
|
||||
int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length
|
||||
) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_req_type(managarm::fs::CntReqType::PT_PEERNAME);
|
||||
req.set_fd(fd);
|
||||
req.set_size(max_addr_length);
|
||||
|
||||
frg::string<MemoryAllocator> ser(getSysdepsAllocator());
|
||||
req.SerializeToString(&ser);
|
||||
|
||||
auto [offer, sendReq, recvResp, recvData] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBuffer(ser.data(), ser.size()),
|
||||
helix_ng::recvInline(),
|
||||
helix_ng::recvBuffer(addr_ptr, max_addr_length)
|
||||
)
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(sendReq.error());
|
||||
if (recvResp.error() == kHelErrDismissed)
|
||||
return ENOTSOCK;
|
||||
HEL_CHECK(recvResp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recvResp.data(), recvResp.length());
|
||||
|
||||
if (resp.error() == managarm::fs::Errors::SUCCESS) {
|
||||
HEL_CHECK(recvData.error());
|
||||
*actual_length = resp.file_size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<std::pair<int, int>, 6> getsockopt_passthrough = {{
|
||||
{SOL_SOCKET, SO_PROTOCOL},
|
||||
{SOL_SOCKET, SO_PEERCRED},
|
||||
{SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS},
|
||||
{SOL_SOCKET, SO_TYPE},
|
||||
{SOL_SOCKET, SO_ACCEPTCONN},
|
||||
{SOL_SOCKET, SO_PEERPIDFD},
|
||||
}};
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) {
|
||||
SignalGuard sguard;
|
||||
|
||||
if (layer == SOL_SOCKET && number == SO_SNDBUF) {
|
||||
// This is really only relevant on Linux
|
||||
*(int *)buffer = 4096;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_RCVBUF) {
|
||||
// This is really only relevant on Linux
|
||||
*(int *)buffer = 4096;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_ERROR) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is "
|
||||
"unimplemented, hardcoding 0\e[39m"
|
||||
<< frg::endlog;
|
||||
*(int *)buffer = 0;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is "
|
||||
"unimplemented, hardcoding 0\e[39m"
|
||||
<< frg::endlog;
|
||||
*(int *)buffer = 0;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_LINGER) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_LINGER is "
|
||||
"unimplemented, hardcoding 0\e[39m"
|
||||
<< frg::endlog;
|
||||
*(int *)buffer = 0;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_PEERSEC) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERSEC is "
|
||||
"unimplemented, hardcoding 0\e[39m"
|
||||
<< frg::endlog;
|
||||
*(int *)buffer = 0;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_PEERGROUPS) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERGROUPS "
|
||||
"is unimplemented, hardcoding 0\e[39m"
|
||||
<< frg::endlog;
|
||||
*(int *)buffer = 0;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_MAXSEG) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with IPPROTO_TCP and TCP_MAXSEG is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_CONGESTION) {
|
||||
mlibc::infoLogger(
|
||||
) << "\e[31mmlibc: getsockopt() call with IPPROTO_TCP and TCP_CONGESTION is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (std::find(
|
||||
getsockopt_passthrough.begin(),
|
||||
getsockopt_passthrough.end(),
|
||||
std::pair<int, int>{layer, number}
|
||||
)
|
||||
!= getsockopt_passthrough.end()) {
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::GetSockOpt<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_layer(layer);
|
||||
req.set_number(number);
|
||||
req.set_optlen(size ? *size : 0);
|
||||
|
||||
auto [offer, send_req, send_creds, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::want_lane,
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::imbueCredentials(),
|
||||
helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(send_creds.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
*size = resp.size();
|
||||
|
||||
auto [recv_buffer] =
|
||||
exchangeMsgsSync(offer.descriptor().getHandle(), helix_ng::recvBuffer(buffer, *size));
|
||||
HEL_CHECK(recv_buffer.error());
|
||||
|
||||
return resp.error() | toErrno;
|
||||
} else {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer
|
||||
<< " number: " << number << "\e[39m" << frg::endlog;
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<std::pair<int, int>, 6> setsockopt_readonly = {{
|
||||
{SOL_SOCKET, SO_ACCEPTCONN},
|
||||
{SOL_SOCKET, SO_DOMAIN},
|
||||
{SOL_SOCKET, SO_ERROR},
|
||||
{SOL_SOCKET, SO_PROTOCOL},
|
||||
{SOL_SOCKET, SO_TYPE},
|
||||
{SOL_IP, SO_PEERSEC},
|
||||
}};
|
||||
|
||||
std::array<std::pair<int, int>, 12> setsockopt_passthrough = {{
|
||||
{SOL_PACKET, PACKET_AUXDATA},
|
||||
{SOL_SOCKET, SO_LOCK_FILTER},
|
||||
{SOL_SOCKET, SO_BINDTODEVICE},
|
||||
{SOL_SOCKET, SO_TIMESTAMP},
|
||||
{SOL_SOCKET, SO_PASSCRED},
|
||||
{SOL_SOCKET, SO_RCVTIMEO},
|
||||
{SOL_SOCKET, SO_SNDTIMEO},
|
||||
{SOL_IP, IP_PKTINFO},
|
||||
{SOL_IP, IP_RECVTTL},
|
||||
{SOL_IP, IP_RETOPTS},
|
||||
{SOL_NETLINK, NETLINK_ADD_MEMBERSHIP},
|
||||
{SOL_NETLINK, NETLINK_PKTINFO},
|
||||
}};
|
||||
|
||||
std::array<std::pair<int, int>, 2> setsockopt_passthrough_noopt = {{
|
||||
{SOL_SOCKET, SO_DETACH_FILTER},
|
||||
}};
|
||||
|
||||
} // namespace
|
||||
|
||||
int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) {
|
||||
SignalGuard sguard;
|
||||
|
||||
if (std::find(
|
||||
setsockopt_passthrough.begin(),
|
||||
setsockopt_passthrough.end(),
|
||||
std::pair<int, int>{layer, number}
|
||||
)
|
||||
!= setsockopt_passthrough.end()) {
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::SetSockOpt<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_layer(layer);
|
||||
req.set_number(number);
|
||||
req.set_optlen(size);
|
||||
|
||||
auto [offer, send_req, send_buf, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::sendBuffer(buffer, size),
|
||||
helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(send_buf.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
} else if (std::find(
|
||||
setsockopt_passthrough_noopt.begin(),
|
||||
setsockopt_passthrough_noopt.end(),
|
||||
std::pair<int, int>{layer, number}
|
||||
)
|
||||
!= setsockopt_passthrough_noopt.end()) {
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::SetSockOpt<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_layer(layer);
|
||||
req.set_number(number);
|
||||
req.set_optlen(0);
|
||||
|
||||
auto [offer, send_req, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
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::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
} else if (std::find(
|
||||
setsockopt_readonly.begin(),
|
||||
setsockopt_readonly.end(),
|
||||
std::pair<int, int>{layer, number}
|
||||
)
|
||||
!= setsockopt_readonly.end()) {
|
||||
// this is purely read-only
|
||||
return ENOPROTOOPT;
|
||||
} else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) {
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
if (size != sizeof(sock_fprog))
|
||||
return EINVAL;
|
||||
|
||||
auto fprog = reinterpret_cast<const sock_fprog *>(buffer);
|
||||
|
||||
managarm::fs::SetSockOpt<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_layer(layer);
|
||||
req.set_number(number);
|
||||
req.set_optlen(fprog->len * sizeof(*fprog->filter));
|
||||
|
||||
auto [offer, send_req, send_buf, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(
|
||||
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
|
||||
helix_ng::sendBuffer(fprog->filter, req.optlen()),
|
||||
helix_ng::recvInline()
|
||||
)
|
||||
);
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(send_buf.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
} else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented"
|
||||
" correctly\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_SNDBUF) {
|
||||
// This is really only relevant on Linux
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_SNDBUFFORCE) {
|
||||
// This is really only relevant on Linux
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_REUSEADDR) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_REUSEPORT) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEPORT is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_RCVBUF) {
|
||||
mlibc::infoLogger(
|
||||
) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_RCVBUF is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_NODELAY) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_MAXSEG) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_KEEPIDLE) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPIDLE "
|
||||
"is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_NETLINK && number == NETLINK_BROADCAST_ERROR) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and "
|
||||
"NETLINK_BROADCAST_ERROR is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_NETLINK && number == NETLINK_EXT_ACK) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and "
|
||||
"NETLINK_EXT_ACK is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_NETLINK && number == NETLINK_GET_STRICT_CHK) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and "
|
||||
"NETLINK_EXT_ACK is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_KEEPINTVL) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPINTVL "
|
||||
"is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == IPPROTO_TCP && number == TCP_KEEPCNT) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPCNT is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_OOBINLINE) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_OOBINLINE is "
|
||||
"unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_PRIORITY) {
|
||||
mlibc::infoLogger(
|
||||
) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_PRIORITY is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_IP && number == IP_RECVERR) {
|
||||
mlibc::infoLogger(
|
||||
) << "\e[31mmlibc: setsockopt() call with SOL_IP and IP_RECVERR is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return 0;
|
||||
} else if (layer == SOL_SOCKET && number == SO_PASSSEC) {
|
||||
mlibc::infoLogger(
|
||||
) << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_PASSSEC is unimplemented\e[39m"
|
||||
<< frg::endlog;
|
||||
return ENOSYS;
|
||||
} else {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer
|
||||
<< " number: " << number << "\e[39m" << frg::endlog;
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int sys_listen(int fd, int) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_req_type(managarm::fs::CntReqType::PT_LISTEN);
|
||||
|
||||
frg::string<MemoryAllocator> ser(getSysdepsAllocator());
|
||||
req.SerializeToString(&ser);
|
||||
|
||||
auto [offer, send_req, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
helix_ng::offer(helix_ng::sendBuffer(ser.data(), ser.size()), helix_ng::recvInline())
|
||||
);
|
||||
|
||||
HEL_CHECK(offer.error());
|
||||
HEL_CHECK(send_req.error());
|
||||
HEL_CHECK(recv_resp.error());
|
||||
|
||||
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
int sys_shutdown(int fd, int how) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto handle = getHandleForFd(fd);
|
||||
if (!handle)
|
||||
return EBADF;
|
||||
|
||||
managarm::fs::ShutdownSocket<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_how(how);
|
||||
|
||||
auto [offer, send_req, recv_resp] = exchangeMsgsSync(
|
||||
handle,
|
||||
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::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::fs::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
@@ -0,0 +1,418 @@
|
||||
|
||||
#include <bits/ensure.h>
|
||||
#include <bits/errors.hpp>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <frg/allocation.hpp>
|
||||
#include <hel-syscalls.h>
|
||||
#include <hel.h>
|
||||
#include <mlibc/all-sysdeps.hpp>
|
||||
#include <mlibc/allocator.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
#include <mlibc/posix-pipe.hpp>
|
||||
#include <protocols/posix/supercalls.hpp>
|
||||
|
||||
#include "posix.frigg_bragi.hpp"
|
||||
|
||||
struct TrackerPage {
|
||||
uint64_t seqlock;
|
||||
int32_t state;
|
||||
int32_t padding;
|
||||
int64_t refClock;
|
||||
int64_t baseRealtime;
|
||||
};
|
||||
|
||||
extern thread_local TrackerPage *__mlibc_clk_tracker_page;
|
||||
|
||||
namespace mlibc {
|
||||
|
||||
int sys_clock_get(int clock, time_t *secs, long *nanos) {
|
||||
// This implementation is inherently signal-safe.
|
||||
if (clock == CLOCK_MONOTONIC || clock == CLOCK_MONOTONIC_RAW
|
||||
|| clock == CLOCK_MONOTONIC_COARSE) {
|
||||
uint64_t tick;
|
||||
HEL_CHECK(helGetClock(&tick));
|
||||
*secs = tick / 1000000000;
|
||||
*nanos = tick % 1000000000;
|
||||
} else if (clock == CLOCK_REALTIME) {
|
||||
cacheFileTable();
|
||||
|
||||
// Start the seqlock read.
|
||||
auto seqlock = __atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_ACQUIRE);
|
||||
__ensure(!(seqlock & 1));
|
||||
|
||||
// Perform the actual loads.
|
||||
auto ref = __atomic_load_n(&__mlibc_clk_tracker_page->refClock, __ATOMIC_RELAXED);
|
||||
auto base = __atomic_load_n(&__mlibc_clk_tracker_page->baseRealtime, __ATOMIC_RELAXED);
|
||||
|
||||
// Finish the seqlock read.
|
||||
__atomic_thread_fence(__ATOMIC_ACQUIRE);
|
||||
__ensure(__atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_RELAXED) == seqlock);
|
||||
|
||||
// Calculate the current time.
|
||||
uint64_t tick;
|
||||
HEL_CHECK(helGetClock(&tick));
|
||||
__ensure(
|
||||
tick >= (uint64_t)__mlibc_clk_tracker_page->refClock
|
||||
); // TODO: Respect the seqlock!
|
||||
tick -= ref;
|
||||
tick += base;
|
||||
*secs = tick / 1000000000;
|
||||
*nanos = tick % 1000000000;
|
||||
} else if (clock == CLOCK_PROCESS_CPUTIME_ID) {
|
||||
mlibc::infoLogger() << "\e[31mmlibc: clock_gettime does not support the CPU time clocks"
|
||||
"\e[39m"
|
||||
<< frg::endlog;
|
||||
*secs = 0;
|
||||
*nanos = 0;
|
||||
} else if (clock == CLOCK_BOOTTIME) {
|
||||
uint64_t tick;
|
||||
HEL_CHECK(helGetClock(&tick));
|
||||
|
||||
*secs = tick / 1000000000;
|
||||
*nanos = tick % 1000000000;
|
||||
} else {
|
||||
mlibc::panicLogger() << "mlibc: Unexpected clock " << clock << frg::endlog;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_clock_getres(int clock, time_t *secs, long *nanos) {
|
||||
(void)clock;
|
||||
(void)secs;
|
||||
(void)nanos;
|
||||
mlibc::infoLogger() << "mlibc: clock_getres is a stub" << frg::endlog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) {
|
||||
SignalGuard sguard;
|
||||
|
||||
if (which != ITIMER_REAL) {
|
||||
mlibc::infoLogger() << "mlibc: setitimers other than ITIMER_REAL are unsupported"
|
||||
<< frg::endlog;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
managarm::posix::SetIntervalTimerRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_which(which);
|
||||
req.set_value_sec(new_value->it_value.tv_sec);
|
||||
req.set_value_usec(new_value->it_value.tv_usec);
|
||||
req.set_interval_sec(new_value->it_interval.tv_sec);
|
||||
req.set_interval_usec(new_value->it_interval.tv_usec);
|
||||
|
||||
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::SetIntervalTimerResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
|
||||
|
||||
if (old_value) {
|
||||
old_value->it_value.tv_sec = resp.value_sec();
|
||||
old_value->it_value.tv_usec = resp.value_usec();
|
||||
old_value->it_interval.tv_sec = resp.interval_sec();
|
||||
old_value->it_interval.tv_usec = resp.interval_usec();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool timerThreadInit = false;
|
||||
|
||||
struct PosixTimerContext {
|
||||
int setupSem = 0;
|
||||
int workerSem = 0;
|
||||
sigevent *sigev;
|
||||
};
|
||||
|
||||
struct TimerHandle {
|
||||
uint64_t id;
|
||||
int notify_type;
|
||||
pthread_t thread = {};
|
||||
};
|
||||
|
||||
void timer_handle(int, siginfo_t *, void *) {}
|
||||
|
||||
void *timer_setup(void *arg) {
|
||||
auto ctx = reinterpret_cast<PosixTimerContext *>(arg);
|
||||
|
||||
sigset_t set = {};
|
||||
sigaddset(&set, SIGTIMER);
|
||||
|
||||
// wait for parent setup to be complete
|
||||
while (__atomic_load_n(&ctx->setupSem, __ATOMIC_RELAXED) == 0)
|
||||
;
|
||||
pthread_testcancel();
|
||||
|
||||
// copy out the function and argument, as the lifetime of the context ends with
|
||||
// incrementing workerSem
|
||||
auto notify = ctx->sigev->sigev_notify_function;
|
||||
union sigval val = ctx->sigev->sigev_value;
|
||||
|
||||
// notify the parent that the context can be dropped
|
||||
__atomic_store_n(&ctx->workerSem, 1, __ATOMIC_RELEASE);
|
||||
|
||||
siginfo_t si;
|
||||
int signo;
|
||||
|
||||
while (true) {
|
||||
pthread_testcancel();
|
||||
while (sys_sigtimedwait(&set, &si, nullptr, &signo))
|
||||
;
|
||||
pthread_testcancel();
|
||||
if (si.si_code == SI_TIMER && signo == SIGTIMER)
|
||||
notify(val);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) {
|
||||
SignalGuard sguard;
|
||||
|
||||
if (!res)
|
||||
return EINVAL;
|
||||
|
||||
managarm::posix::TimerCreateRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_clockid(clk);
|
||||
|
||||
// TODO: pass sigev_value
|
||||
if (!evp) {
|
||||
req.set_sigev_signo(SIGALRM);
|
||||
req.set_sigev_tid(sys_gettid());
|
||||
} else if (evp->sigev_notify == SIGEV_NONE) {
|
||||
req.set_sigev_signo(0);
|
||||
req.set_sigev_tid(0);
|
||||
} else if (evp->sigev_notify == SIGEV_SIGNAL) {
|
||||
req.set_sigev_signo(evp->sigev_signo);
|
||||
req.set_sigev_tid(sys_gettid());
|
||||
} else if (evp->sigev_notify == SIGEV_THREAD_ID) {
|
||||
req.set_sigev_signo(evp->sigev_signo);
|
||||
req.set_sigev_tid(evp->sigev_notify_thread_id);
|
||||
} else if (evp->sigev_notify == SIGEV_THREAD) {
|
||||
if (!timerThreadInit) {
|
||||
struct sigaction sa{};
|
||||
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||
sa.sa_sigaction = timer_handle;
|
||||
sys_sigaction(SIGTIMER, &sa, nullptr);
|
||||
timerThreadInit = true;
|
||||
}
|
||||
|
||||
pthread_attr_t attr;
|
||||
if (evp->sigev_notify_attributes)
|
||||
attr = *evp->sigev_notify_attributes;
|
||||
else
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
int ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
PosixTimerContext context{};
|
||||
context.sigev = evp;
|
||||
|
||||
// mask for all signals except the libc-reserved RT signal range
|
||||
sigset_t mask = {
|
||||
#if ULONG_MAX == 0xFFFF'FFFF
|
||||
0x7FFF'FFFF, 0xFFFF'FFFC
|
||||
#else
|
||||
0xFFFF'FFFC'7FFF'FFFF
|
||||
#endif
|
||||
};
|
||||
// but also mask SIGTIMER
|
||||
sigaddset(&mask, SIGTIMER);
|
||||
HelWord original_set;
|
||||
uint64_t unused;
|
||||
|
||||
HEL_CHECK(helSyscall2_2(
|
||||
kHelObserveSuperCall + posix::superSigMask,
|
||||
SIG_BLOCK,
|
||||
*reinterpret_cast<const HelWord *>(&mask),
|
||||
&original_set,
|
||||
&unused
|
||||
));
|
||||
|
||||
pthread_t pthread;
|
||||
ret = pthread_create(&pthread, &attr, timer_setup, &context);
|
||||
|
||||
// restore previous signal mask
|
||||
HEL_CHECK(helSyscall2_2(
|
||||
kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, original_set, &unused, &unused
|
||||
));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req.set_sigev_signo(SIGTIMER);
|
||||
req.set_sigev_tid(reinterpret_cast<Tcb *>(pthread)->tid);
|
||||
infoLogger() << "mlibc: timer_create: created timer thread "
|
||||
<< reinterpret_cast<Tcb *>(pthread)->tid << frg::endlog;
|
||||
|
||||
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::TimerCreateResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS) {
|
||||
pthread_cancel(pthread);
|
||||
__atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE);
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
// notify worker that setup is complete
|
||||
__atomic_store_n(&context.setupSem, 1, __ATOMIC_RELEASE);
|
||||
// await worker setup to let the context go out of scope
|
||||
while (__atomic_load_n(&context.workerSem, __ATOMIC_RELAXED) == 0)
|
||||
;
|
||||
|
||||
*res = frg::construct<TimerHandle>(
|
||||
getSysdepsAllocator(), resp.timer_id(), evp->sigev_notify, pthread
|
||||
);
|
||||
return 0;
|
||||
} else {
|
||||
mlibc::infoLogger() << "mlibc: timer_create: unsupported sigevent type "
|
||||
<< evp->sigev_notify << frg::endlog;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
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::TimerCreateResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
*res = frg::construct<TimerHandle>(
|
||||
getSysdepsAllocator(), resp.timer_id(), evp ? evp->sigev_notify : SIGEV_SIGNAL, pthread_t{}
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_timer_settime(
|
||||
timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old
|
||||
) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto timerHandle = reinterpret_cast<TimerHandle *>(t);
|
||||
managarm::posix::TimerSetRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_timer(timerHandle->id);
|
||||
req.set_flags(flags);
|
||||
req.set_value_sec(val->it_value.tv_sec);
|
||||
req.set_value_nsec(val->it_value.tv_nsec);
|
||||
req.set_interval_sec(val->it_interval.tv_sec);
|
||||
req.set_interval_nsec(val->it_interval.tv_nsec);
|
||||
|
||||
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::TimerSetResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
if (old) {
|
||||
old->it_value.tv_sec = resp.value_sec();
|
||||
old->it_value.tv_nsec = resp.value_nsec();
|
||||
old->it_interval.tv_sec = resp.interval_sec();
|
||||
old->it_interval.tv_nsec = resp.interval_nsec();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_timer_gettime(timer_t t, struct itimerspec *val) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto timerHandle = reinterpret_cast<TimerHandle *>(t);
|
||||
managarm::posix::TimerGetRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_timer((timerHandle->id));
|
||||
|
||||
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::TimerGetResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
if (resp.error() != managarm::posix::Errors::SUCCESS)
|
||||
return resp.error() | toErrno;
|
||||
|
||||
if (val) {
|
||||
val->it_value.tv_sec = resp.value_sec();
|
||||
val->it_value.tv_nsec = resp.value_nsec();
|
||||
val->it_interval.tv_sec = resp.interval_sec();
|
||||
val->it_interval.tv_nsec = resp.interval_nsec();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_timer_delete(timer_t t) {
|
||||
SignalGuard sguard;
|
||||
|
||||
auto timerHandle = reinterpret_cast<TimerHandle *>(t);
|
||||
|
||||
if (timerHandle->notify_type == SIGEV_THREAD) {
|
||||
pthread_cancel(timerHandle->thread);
|
||||
pthread_kill(timerHandle->thread, SIGTIMER);
|
||||
}
|
||||
|
||||
managarm::posix::TimerDeleteRequest<MemoryAllocator> req(getSysdepsAllocator());
|
||||
req.set_timer(timerHandle->id);
|
||||
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::TimerDeleteResponse<MemoryAllocator> resp(getSysdepsAllocator());
|
||||
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
|
||||
return resp.error() | toErrno;
|
||||
}
|
||||
|
||||
} // namespace mlibc
|
||||
Reference in New Issue
Block a user