195 lines
5.9 KiB
C++
195 lines
5.9 KiB
C++
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <linux/limits.h>
|
|
#include <stdio.h>
|
|
|
|
#define POSIX_PAGE_SIZE 4096
|
|
|
|
CORE_Static B32
|
|
os_write_file(String filename, String filecontent) {
|
|
FILE *f = fopen((const char *)filename.str, "w");
|
|
if (f) {
|
|
fwrite(filecontent.str, 1, filecontent.len, f);
|
|
fclose(f);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CORE_Static String
|
|
os_read_file(Alloator *a, String name) {
|
|
String result = {0};
|
|
FILE *f = fopen((char *)name.str, "rb");
|
|
if (f) {
|
|
fseek(f, 0, SEEK_END);
|
|
result.len = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
result.str = (U8 *)allocate_size(a, result.len + 1, false);
|
|
fread(result.str, result.len, 1, f);
|
|
fclose(f);
|
|
result.str[result.len] = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
CORE_Static String
|
|
os_get_exe_dir(Allocator *a) {
|
|
char buffer[PATH_MAX] = {};
|
|
if (readlink("/proc/self/exe", buffer, PATH_MAX) == -1) {
|
|
log_info("Failed to retrieve the path of the executable, the method used is fetching /proc/self/exe, very likely you are using an OS that doesn't follow this convention and as such it is currently not supported");
|
|
}
|
|
String exe = string_from_cstring(buffer);
|
|
exe = string_chop_last_slash(exe);
|
|
String result = string_copy(a, exe);
|
|
|
|
log_trace("Retrieved executable path %Q", result);
|
|
return result;
|
|
}
|
|
|
|
CORE_Static String
|
|
os_get_absolute_path(Allocator *a, String path) {
|
|
assert(path.str[path.len] == 0);
|
|
char buffer[PATH_MAX] = {};
|
|
realpath((char *)path.str, buffer);
|
|
String abs = string_from_cstring(buffer);
|
|
String result = string_copy(a, abs);
|
|
return result;
|
|
}
|
|
|
|
CORE_Static B32
|
|
os_does_file_exist(String path) {
|
|
B32 result = false;
|
|
assert(path.str[path.len] == 0);
|
|
if (access((char *)path.str, F_OK) == 0) {
|
|
result = true;
|
|
}
|
|
log_trace("Does file exist? %Q %d", path, result);
|
|
return result;
|
|
}
|
|
|
|
CORE_Static String
|
|
os_get_working_dir(Allocator *allocator) {
|
|
char *buffer = allocate_array(allocator, char, PATH_MAX, false);
|
|
char *result = getcwd(buffer, PATH_MAX);
|
|
return string_from_cstring(result);
|
|
}
|
|
|
|
CORE_Static Array<OS_File_Info>
|
|
os_list_dir(Scratch_Arena *scratch, Allocator *a, String dir, U32 flags = LIST_RECURSE_INTO_DIRS) {
|
|
Scratch_Scope _scope(scratch);
|
|
Array<String> dirs_to_read = {scratch};
|
|
dirs_to_read.add(dir);
|
|
|
|
Array<OS_File_Info> result = {a};
|
|
for (auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++) {
|
|
assert(it->str[it->len] == 0);
|
|
dirent *dir;
|
|
DIR *d = opendir((char *)it->str);
|
|
if (d) {
|
|
while ((dir = readdir(d)) != NULL) {
|
|
if (dir->d_name[0] == '.') {
|
|
if (dir->d_name[1] == '.') {
|
|
if (dir->d_name[2] == 0)
|
|
continue;
|
|
}
|
|
|
|
if (dir->d_name[1] == 0)
|
|
continue;
|
|
}
|
|
|
|
OS_File_Info entry = {};
|
|
entry.relative_path = string_fmt(a, "%Q/%s", *it, dir->d_name);
|
|
entry.absolute_path = os_get_absolute_path(a, entry.relative_path);
|
|
|
|
if (dir->d_type == DT_DIR) {
|
|
entry.is_directory = true;
|
|
|
|
if (flags & LIST_RECURSE_INTO_DIRS) {
|
|
dirs_to_read.add(entry.absolute_path);
|
|
}
|
|
}
|
|
|
|
result.add(entry);
|
|
log_trace("%Q %d", entry.absolute_path, entry.is_directory);
|
|
}
|
|
closedir(d);
|
|
}
|
|
else {
|
|
log_info("ERROR Failed to read dir: %Q, errno: %s", *it, strerror(errno));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
CORE_Static U8 *
|
|
os_advance_commit(OS_Memory *m, size_t *commit_size, size_t page_size) {
|
|
size_t aligned_up_commit = align_up(*commit_size, page_size);
|
|
size_t to_be_total_commited_size = aligned_up_commit + m->commit;
|
|
size_t to_be_total_commited_size_clamped_to_reserve = clamp_top(to_be_total_commited_size, m->reserve);
|
|
size_t adjusted_to_boundary_commit = to_be_total_commited_size_clamped_to_reserve - m->commit;
|
|
assert_message(adjusted_to_boundary_commit, "Debug WIN32 Error: Reached the virtual memory reserved boundary");
|
|
U8 *result = m->data + m->commit;
|
|
if (adjusted_to_boundary_commit == 0)
|
|
result = 0;
|
|
*commit_size = adjusted_to_boundary_commit;
|
|
return result;
|
|
}
|
|
|
|
CORE_Static OS_Memory
|
|
os_reserve(size_t size) {
|
|
OS_Memory result = {};
|
|
size_t size_aligned = align_up(size, POSIX_PAGE_SIZE);
|
|
result.data = (U8 *)mmap(0, size_aligned, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
assert_message(result.data, POSIX_ERROR "Failed to reserve memory using mmap!!");
|
|
if (result.data) {
|
|
result.reserve = size_aligned;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CORE_Static B32
|
|
os_commit(OS_Memory *m, size_t commit) {
|
|
B32 result = false;
|
|
U8 *pointer = os_advance_commit(m, &commit, POSIX_PAGE_SIZE);
|
|
if (pointer) {
|
|
int mprotect_result = mprotect(pointer, commit, PROT_READ | PROT_WRITE);
|
|
assert_message(mprotect_result == 0, "OS1 POSIX Debug Error: Failed to commit more memory using mmap");
|
|
if (mprotect_result == 0) {
|
|
m->commit += commit;
|
|
result = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CORE_Static void
|
|
os_release(OS_Memory *m) {
|
|
int result = munmap(m->data, m->reserve);
|
|
assert_message(result == 0, "OS1 POSIX Debug Error: Failed to release virtual memory using munmap");
|
|
if (result == 0) {
|
|
memory_zero(m, sizeof(*m));
|
|
}
|
|
}
|
|
|
|
CORE_Static U64
|
|
os_get_microseconds() {
|
|
timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
U64 result = (((U64)ts.tv_sec) * 1000000ull) + ((U64)ts.tv_nsec) / 1000ull;
|
|
return result;
|
|
}
|
|
|
|
CORE_Static F64
|
|
os_time() {
|
|
F64 time = (F64)os_get_microseconds();
|
|
F64 result = time / 1000000.0; // Microseconds to seconds
|
|
return result;
|
|
}
|