summaryrefslogtreecommitdiff
path: root/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp')
-rw-r--r--lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp744
1 files changed, 744 insertions, 0 deletions
diff --git a/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp b/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp
new file mode 100644
index 0000000..8da0e1e
--- /dev/null
+++ b/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp
@@ -0,0 +1,744 @@
+
+// for _Exit()
+#include <stdlib.h>
+
+#include <string.h>
+#include <errno.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 <sys/wait.h>
+#include <pthread.h>
+
+#include <bits/ensure.h>
+#include <mlibc/allocator.hpp>
+#include <mlibc/debug.hpp>
+#include <mlibc/posix-pipe.hpp>
+#include <mlibc/thread-entry.hpp>
+#include <mlibc/all-sysdeps.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) {
+ if(ru) {
+ mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog;
+ return ENOSYS;
+ }
+
+ SignalGuard sguard;
+
+ managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
+ req.set_request_type(managarm::posix::CntReqType::WAIT);
+ req.set_pid(pid);
+ req.set_flags(flags);
+
+ 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::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ if(status)
+ *status = resp.mode();
+ *ret_pid = resp.pid();
+ 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::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ info->si_pid = resp.pid();
+ info->si_uid = resp.uid();
+ info->si_signo = SIGCHLD;
+ info->si_status = resp.sig_status();
+ info->si_code = resp.sig_code();
+ 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::ACCESS_DENIED) {
+ return EPERM;
+ }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }else{
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ 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::ACCESS_DENIED) {
+ return EPERM;
+ }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }else{
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ 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::ACCESS_DENIED) {
+ return EPERM;
+ }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }else{
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ 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::ACCESS_DENIED) {
+ return EPERM;
+ }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) {
+ return EINVAL;
+ }else{
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ return 0;
+ }
+}
+
+pid_t sys_gettid() {
+ // TODO: use an actual gettid syscall.
+ return sys_getpid();
+}
+
+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 {
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ *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 {
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ *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::INSUFFICIENT_PERMISSION) {
+ return EPERM;
+ }else if(resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) {
+ return ESRCH;
+ }else if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) {
+ return EACCES;
+ }else{
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+ 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());
+ __ensure(resp.error() == managarm::posix::Errors::SUCCESS);
+
+ 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 *pid_out, void *stack) {
+ HelWord pid = 0;
+ HEL_CHECK(helSyscall2_1(kHelCallSuper + posix::superClone,
+ reinterpret_cast<HelWord>(__mlibc_start_thread),
+ reinterpret_cast<HelWord>(stack),
+ &pid));
+
+ if (pid_out)
+ *pid_out = pid;
+
+ return 0;
+}
+
+int sys_tcb_set(void *pointer) {
+#if defined(__aarch64__)
+ uintptr_t addr = reinterpret_cast<uintptr_t>(pointer);
+ addr += sizeof(Tcb) - 0x10;
+ asm volatile ("msr tpidr_el0, %0" :: "r"(addr));
+#else
+ HEL_CHECK(helWriteFsBase(pointer));
+#endif
+ return 0;
+}
+
+void sys_thread_exit() {
+ // This implementation is inherently signal-safe.
+ HEL_CHECK(helSyscall1(kHelCallSuper + posix::superExit, 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, NULL)) {
+ return e;
+ }
+
+ sys_close(fd);
+
+ pthread_setcancelstate(cs, 0);
+
+ 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, 0);
+
+ if(static_cast<ssize_t>(size) <= real_size) {
+ return ERANGE;
+ }
+
+ return 0;
+}
+
+
+} //namespace mlibc
+