AuroraRuntime/Source/AuProcAddresses.Linux.cpp

225 lines
5.7 KiB
C++

/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuProcAddresses.Linux.cpp
Date: 2023-8-11
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/random.h>
namespace Aurora
{
#define read_barrier() __asm__ __volatile__("lfence" ::: "memory")
static const auto kAioRingMagic = 0xa10a10a1u;
void InitLinuxAddresses()
{
}
int pidfd_getfd(int pidfd, int targetfd,
unsigned int flags)
{
return syscall(SYS_pidfd_getfd, pidfd, targetfd, flags);
}
int pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(SYS_pidfd_open, pid, flags);
}
long set_robust_list(struct robust_list_head *head, size_t len)
{
return syscall(SYS_set_robust_list, head, len);
}
long get_robust_list(int pid, struct robust_list_head **head_ptr, size_t *len_ptr)
{
return syscall(SYS_get_robust_list, pid, head_ptr, len_ptr);
}
static int futex(uint32_t *uaddr, int futex_op, uint32_t val,
const struct timespec *timeout,
uint32_t *uaddr2, uint32_t val3)
{
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
}
int futex_wait(uint32_t *addr, uint32_t expected)
{
return futex(addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, expected, 0, 0, 0);
}
int futex_wait(uint32_t *addr, uint32_t expected, const struct timespec *timeout)
{
if (timeout)
{
return futex(addr, FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, expected, timeout, 0, FUTEX_BITSET_MATCH_ANY);
}
else
{
return futex(addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, expected, timeout, 0, 0);
}
}
int futex_wait_shared(uint32_t *addr, uint32_t expected, const struct timespec *timeout)
{
if (timeout)
{
return futex(addr, FUTEX_WAIT_BITSET, expected, timeout, 0, FUTEX_BITSET_MATCH_ANY);
}
else
{
return futex(addr, FUTEX_WAIT, expected, timeout, 0, 0);
}
}
int futex_wake(uint32_t *addr, uint32_t nthreads)
{
return futex(addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, nthreads, 0, 0, 0);
}
int futex_wake_shared(uint32_t *addr, uint32_t nthreads)
{
return futex(addr, FUTEX_WAKE, nthreads, 0, 0, 0);
}
int futex_wait(volatile uint32_t *addr, uint32_t expected)
{
return futex((uint32_t *)addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, expected, 0, 0, 0);
}
int futex_wait(volatile uint32_t *addr, uint32_t expected, const struct timespec *timeout)
{
if (timeout)
{
return futex((uint32_t *)addr, FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, expected, timeout, 0, FUTEX_BITSET_MATCH_ANY);
}
else
{
return futex((uint32_t *)addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, expected, timeout, 0, 0);
}
}
int futex_wake(volatile uint32_t *addr, uint32_t nthreads)
{
return futex((uint32_t *)addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, nthreads, 0, 0, 0);
}
int io_setup(unsigned nr, aio_context_t *ctxp)
{
return syscall(__NR_io_setup, nr, ctxp);
}
int io_destroy(aio_context_t ctx)
{
return syscall(__NR_io_destroy, ctx);
}
int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
{
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
#if 0
int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
struct io_event *events,
struct timespec *timeout)
{
return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
}
#endif
struct aio_ring
{
unsigned id;
unsigned nr;
unsigned head;
unsigned tail;
unsigned magic;
unsigned compat_features;
unsigned incompat_features;
unsigned header_length;
struct io_event events[0];
};
int io_getevents(aio_context_t ctx,
long min_nr, long max_nr,
struct io_event *events,
struct timespec *timeout)
{
int i {};
auto pRing = (struct aio_ring *)ctx;
if (!pRing ||
pRing->magic != kAioRingMagic)
{
goto do_syscall;
}
while (i < max_nr)
{
auto head = pRing->head;
if (head == pRing->tail)
{
break;
}
events[i++] = pRing->events[head];
read_barrier();
pRing->head = (head + 1) % pRing->nr;
}
if (!i &&
timeout &&
!timeout->tv_sec &&
!timeout->tv_nsec)
{
return 0;
}
if (i &&
i >= min_nr)
{
return i;
}
do_syscall:
return syscall(__NR_io_getevents,
ctx, min_nr - i,
max_nr - i,
&events[i], timeout) + i;
}
int io_cancel(aio_context_t ctx_id, struct iocb *iocb,
struct io_event *result)
{
return syscall(SYS_io_cancel, ctx_id, iocb, result);
}
ssize_t sys_getrandom(void *pBuffer, size_t uLength)
{
static AuUInt32 gShouldNotGetRand {};
ssize_t ret {};
if (gShouldNotGetRand)
{
return ENOSYS;
}
ret = syscall(SYS_getrandom, pBuffer, uLength, 1);
if (ret == ENOSYS)
{
gShouldNotGetRand = 1;
}
return ret;
}
}