mirror of
https://github.com/geode-sdk/geode.git
synced 2024-12-17 19:32:28 -05:00
242 lines
6.2 KiB
C++
242 lines
6.2 KiB
C++
|
#include <errno.h>
|
||
|
#include <limits.h>
|
||
|
#include <pthread.h>
|
||
|
|
||
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||
|
#include <pthread_np.h> // for pthread_set_name_np
|
||
|
#endif
|
||
|
|
||
|
#include <sched.h> // for sched_yield
|
||
|
#include <stdio.h>
|
||
|
#include <time.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <sys/mman.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/syscall.h>
|
||
|
|
||
|
#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||
|
#include <sys/sysctl.h> // NOLINT, for sysctl
|
||
|
#endif
|
||
|
|
||
|
#include "logging/logging.h"
|
||
|
#include "logging/check_logging.h"
|
||
|
#include "UnifiedInterface/platform.h"
|
||
|
|
||
|
#if defined(__APPLE__)
|
||
|
#include <dlfcn.h>
|
||
|
#include <mach/mach.h>
|
||
|
#include <mach/vm_statistics.h>
|
||
|
#include <mach/mach_vm.h>
|
||
|
#include <mach/mach_init.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT)
|
||
|
#define ANDROID_LOG_TAG "Dobby"
|
||
|
#include <android/log.h>
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#if defined(__APPLE__)
|
||
|
const int kMmapFd = VM_MAKE_TAG(255);
|
||
|
#else
|
||
|
const int kMmapFd = -1;
|
||
|
#endif
|
||
|
|
||
|
const int kMmapFdOffset = 0;
|
||
|
|
||
|
// ================================================================
|
||
|
// base :: Thread
|
||
|
|
||
|
using namespace base;
|
||
|
|
||
|
typedef struct thread_handle_t {
|
||
|
pthread_t thread;
|
||
|
} thread_handle_t;
|
||
|
|
||
|
void ThreadInterface::SetName(const char *name) {
|
||
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||
|
pthread_set_name_np(pthread_self(), name);
|
||
|
#elif defined(__APPLE__)
|
||
|
pthread_setname_np(name);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int ThreadInterface::CurrentId() {
|
||
|
#if defined(__APPLE__)
|
||
|
mach_port_t port = mach_thread_self();
|
||
|
mach_port_deallocate(mach_task_self(), port);
|
||
|
return port;
|
||
|
#elif defined(_POSIX_VERSION)
|
||
|
return syscall(__NR_gettid);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void *thread_handler_wrapper(void *ctx) {
|
||
|
ThreadInterface::Delegate *d = (ThreadInterface::Delegate *)ctx;
|
||
|
d->ThreadMain();
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
bool ThreadInterface::Create(ThreadInterface::Delegate *delegate, ThreadHandle *handle) {
|
||
|
thread_handle_t *handle_impl = new thread_handle_t;
|
||
|
|
||
|
int err = 0;
|
||
|
err = pthread_create(&(handle_impl->thread), nullptr, thread_handler_wrapper, delegate);
|
||
|
if (err != 0) {
|
||
|
FATAL("pthread create failed");
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Thread::Thread(const char *name) {
|
||
|
strncpy(name_, name, sizeof(name_));
|
||
|
}
|
||
|
|
||
|
bool Thread::Start() {
|
||
|
if (ThreadInterface::Create(this, &handle_) == false) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// ================================================================
|
||
|
// base :: OSMemory
|
||
|
|
||
|
static int GetProtectionFromMemoryPermission(MemoryPermission access) {
|
||
|
switch (access) {
|
||
|
case MemoryPermission::kNoAccess:
|
||
|
return PROT_NONE;
|
||
|
case MemoryPermission::kRead:
|
||
|
return PROT_READ;
|
||
|
case MemoryPermission::kReadWrite:
|
||
|
return PROT_READ | PROT_WRITE
|
||
|
#if defined(__APPLE__)
|
||
|
| VM_PROT_COPY
|
||
|
#endif
|
||
|
;
|
||
|
case MemoryPermission::kReadWriteExecute:
|
||
|
return PROT_READ | PROT_WRITE | PROT_EXEC
|
||
|
#if defined(__APPLE__)
|
||
|
| VM_PROT_COPY
|
||
|
#endif
|
||
|
;
|
||
|
case MemoryPermission::kReadExecute:
|
||
|
return PROT_READ | PROT_EXEC;
|
||
|
}
|
||
|
UNREACHABLE();
|
||
|
}
|
||
|
|
||
|
int OSMemory::AllocPageSize() {
|
||
|
return OSMemory::PageSize();
|
||
|
}
|
||
|
|
||
|
int OSMemory::PageSize() {
|
||
|
return static_cast<int>(sysconf(_SC_PAGESIZE));
|
||
|
}
|
||
|
|
||
|
void *OSMemory::Allocate(void *address, int size, MemoryPermission access) {
|
||
|
int prot = GetProtectionFromMemoryPermission(access);
|
||
|
|
||
|
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||
|
if (address != NULL) {
|
||
|
flags = flags | MAP_FIXED;
|
||
|
}
|
||
|
void *result = mmap(address, size, prot, flags, kMmapFd, kMmapFdOffset);
|
||
|
if (result == MAP_FAILED)
|
||
|
return nullptr;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool OSMemory::Free(void *address, const int size) {
|
||
|
DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % PageSize());
|
||
|
DCHECK_EQ(0, size % PageSize());
|
||
|
|
||
|
return munmap(address, size) == 0;
|
||
|
}
|
||
|
|
||
|
bool OSMemory::Release(void *address, int size) {
|
||
|
DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % PageSize());
|
||
|
DCHECK_EQ(0, size % PageSize());
|
||
|
|
||
|
return munmap(address, size) == 0;
|
||
|
}
|
||
|
|
||
|
// static
|
||
|
bool OSMemory::SetPermission(void *address, int size, MemoryPermission access) {
|
||
|
DLOG(0, "SetPermission 1");
|
||
|
DCHECK_EQ(0, reinterpret_cast<uintptr_t>(address) % PageSize());
|
||
|
DLOG(0, "SetPermission 2");
|
||
|
DCHECK_EQ(0, size % PageSize());
|
||
|
|
||
|
DLOG(0, "SetPermission 3");
|
||
|
int prot = GetProtectionFromMemoryPermission(access);
|
||
|
DLOG(0, "SetPermission 4 %p %d %d", address, size, prot);
|
||
|
#if defined(__APPLE__)
|
||
|
int ret = mach_vm_protect(mach_task_self(), (mach_vm_address_t)address, size, FALSE, prot);
|
||
|
#else
|
||
|
int ret = mprotect(address, size, prot);
|
||
|
#endif
|
||
|
DLOG(0, "SetPermission 4.5");
|
||
|
if (ret == 0 && access == MemoryPermission::kNoAccess) {
|
||
|
// This is advisory; ignore errors and continue execution.
|
||
|
// ReclaimInaccessibleMemory(address, size);
|
||
|
}
|
||
|
|
||
|
if (ret) {
|
||
|
FATAL("[!] %s\n", ((const char *)strerror(errno)));
|
||
|
}
|
||
|
|
||
|
// For accounting purposes, we want to call MADV_FREE_REUSE on macOS after
|
||
|
// changing permissions away from MemoryPermission::kNoAccess. Since this
|
||
|
// state is not kept at this layer, we always call this if access != kNoAccess.
|
||
|
// The cost is a syscall that effectively no-ops.
|
||
|
// TODO(erikchen): Fix this to only call MADV_FREE_REUSE when necessary.
|
||
|
// https://crbug.com/823915
|
||
|
#if defined(OS_MACOSX)
|
||
|
DLOG(0, "SetPermission 5");
|
||
|
if (access != MemoryPermission::kNoAccess)
|
||
|
madvise(address, size, MADV_FREE_REUSE);
|
||
|
#endif
|
||
|
DLOG(0, "SetPermission 6");
|
||
|
return ret == 0;
|
||
|
}
|
||
|
|
||
|
// ================================================================
|
||
|
// base :: OSPrint
|
||
|
|
||
|
void OSPrint::Print(const char *format, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
VPrint(format, args);
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
void OSPrint::VPrint(const char *format, va_list args) {
|
||
|
#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT)
|
||
|
__android_log_vprint(ANDROID_LOG_INFO, ANDROID_LOG_TAG, format, args);
|
||
|
#else
|
||
|
vprintf(format, args);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void OSPrint::PrintError(const char *format, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
VPrintError(format, args);
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
void OSPrint::VPrintError(const char *format, va_list args) {
|
||
|
#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT)
|
||
|
__android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
|
||
|
#else
|
||
|
vfprintf(stderr, format, args);
|
||
|
#endif
|
||
|
}
|