Even more of previous
parent
1f2b9c7541
commit
34a968a058
|
@ -11,7 +11,7 @@
|
|||
internal String_Const_u8
|
||||
system_get_path(Arena* arena, System_Path_Code path_code){
|
||||
String_Const_u8 result = {};
|
||||
|
||||
|
||||
switch (path_code){
|
||||
case SystemPath_CurrentDirectory: {
|
||||
// glibc extension: getcwd allocates its own memory if passed NULL
|
||||
|
@ -19,70 +19,70 @@ system_get_path(Arena* arena, System_Path_Code path_code){
|
|||
u64 working_dir_len = cstring_length(working_dir);
|
||||
u8 *out = push_array(arena, u8, working_dir_len + 1);
|
||||
block_copy(out, working_dir, working_dir_len);
|
||||
|
||||
|
||||
// NOTE: 4ed appears to expect a slash on the end.
|
||||
out[working_dir_len] = '/';
|
||||
|
||||
|
||||
free(working_dir);
|
||||
result = SCu8(out, working_dir_len + 1);
|
||||
} break;
|
||||
|
||||
|
||||
case SystemPath_Binary: {
|
||||
// linux-specific: binary path symlinked at /proc/self/exe
|
||||
// PATH_MAX is probably good enough...
|
||||
// read the 'readlink' manpage for some comedy about it being 'broken by design'.
|
||||
|
||||
|
||||
char* buf = push_array(arena, char, PATH_MAX);
|
||||
ssize_t n = readlink("/proc/self/exe", buf, PATH_MAX);
|
||||
|
||||
|
||||
if(n == -1) {
|
||||
perror("readlink");
|
||||
*buf = n = 0;
|
||||
}
|
||||
|
||||
|
||||
result = string_remove_last_folder(SCu8(buf, n));
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal String_Const_u8
|
||||
system_get_canonical(Arena* arena, String_Const_u8 name){
|
||||
|
||||
|
||||
// first remove redundant ../, //, ./ parts
|
||||
|
||||
|
||||
const u8* input = (u8*) strndupa((char*)name.str, name.size);
|
||||
u8* output = push_array(arena, u8, name.size + 1);
|
||||
|
||||
|
||||
const u8* p = input;
|
||||
u8* q = output;
|
||||
|
||||
|
||||
while(*p) {
|
||||
|
||||
|
||||
// not a slash - copy char
|
||||
if(p[0] != '/') {
|
||||
*q++ = *p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// two slashes in a row, skip one.
|
||||
if(p[1] == '/') {
|
||||
++p;
|
||||
}
|
||||
else if(p[1] == '.') {
|
||||
|
||||
|
||||
// skip "/./" or trailing "/."
|
||||
if(p[2] == '/' || p[2] == '\0') {
|
||||
p += 2;
|
||||
}
|
||||
|
||||
|
||||
// if we encounter "/../" or trailing "/..", remove last directory instead
|
||||
else if(p[2] == '.' && (p[3] == '/' || p[3] == '\0')) {
|
||||
while(q > output && *--q != '/'){};
|
||||
p += 3;
|
||||
}
|
||||
|
||||
|
||||
else {
|
||||
*q++ = *p++;
|
||||
}
|
||||
|
@ -91,13 +91,13 @@ system_get_canonical(Arena* arena, String_Const_u8 name){
|
|||
*q++ = *p++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef INSO_DEBUG
|
||||
if(name.size != q - output) {
|
||||
LINUX_FN_DEBUG("[%.*s] -> [%.*s]", (int)name.size, name.str, (int)(q - output), output);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// TODO: use realpath at this point to resolve symlinks?
|
||||
return SCu8(output, q - output);
|
||||
}
|
||||
|
@ -106,57 +106,57 @@ internal File_List
|
|||
system_get_file_list(Arena* arena, String_Const_u8 directory){
|
||||
//LINUX_FN_DEBUG("%.*s", (int)directory.size, directory.str);
|
||||
File_List result = {};
|
||||
|
||||
|
||||
char* path = strndupa((char*)directory.str, directory.size);
|
||||
int fd = open(path, O_RDONLY | O_DIRECTORY);
|
||||
if(fd == -1) {
|
||||
perror("open");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DIR* dir = fdopendir(fd);
|
||||
struct dirent* d;
|
||||
|
||||
|
||||
File_Info* head = NULL;
|
||||
File_Info** fip = &head;
|
||||
|
||||
|
||||
while((d = readdir(dir))) {
|
||||
const char* name = d->d_name;
|
||||
|
||||
|
||||
// ignore . and ..
|
||||
if(*name == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
*fip = push_array(arena, File_Info, 1);
|
||||
(*fip)->file_name = push_u8_stringf(arena, "%.*s", d->d_reclen, name);
|
||||
|
||||
|
||||
struct stat st;
|
||||
if(fstatat(fd, name, &st, 0) == -1){
|
||||
perror("fstatat");
|
||||
}
|
||||
|
||||
|
||||
(*fip)->attributes = linux_file_attributes_from_struct_stat(&st);
|
||||
fip = &(*fip)->next;
|
||||
result.count++;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
|
||||
if(result.count > 0) {
|
||||
result.infos = fip = push_array(arena, File_Info*, result.count);
|
||||
|
||||
|
||||
for(File_Info* f = head; f; f = f->next) {
|
||||
*fip++ = f;
|
||||
}
|
||||
|
||||
|
||||
qsort(result.infos, result.count, sizeof(File_Info*), (__compar_fn_t)&linux_compare_file_infos);
|
||||
|
||||
|
||||
for(u32 i = 0; i < result.count - 1; ++i) {
|
||||
result.infos[i]->next = result.infos[i+1];
|
||||
}
|
||||
result.infos[result.count-1]->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -209,9 +209,9 @@ internal File_Attributes
|
|||
system_save_file(Arena* scratch, char* file_name, String_Const_u8 data){
|
||||
LINUX_FN_DEBUG("%s", file_name);
|
||||
File_Attributes result = {};
|
||||
|
||||
|
||||
// TODO(inso): should probably put a \n on the end if it's a text file.
|
||||
|
||||
|
||||
int fd = open(file_name, O_WRONLY, O_CREAT);
|
||||
if (fd != -1) {
|
||||
int bytes_written = write(fd, data.str, data.size);
|
||||
|
@ -225,7 +225,7 @@ system_save_file(Arena* scratch, char* file_name, String_Const_u8 data){
|
|||
} else {
|
||||
perror("open");
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ system_wake_up_timer_create(void){
|
|||
LINUX_FN_DEBUG();
|
||||
Linux_Object* object = linux_alloc_object(LinuxObjectKind_Timer);
|
||||
dll_insert(&linuxvars.timer_objects, &object->node);
|
||||
|
||||
|
||||
// NOTE(inso): timers created on-demand to avoid file-descriptor exhaustion.
|
||||
object->timer.fd = -1;
|
||||
}
|
||||
|
@ -287,23 +287,23 @@ internal void
|
|||
system_wake_up_timer_set(Plat_Handle handle, u32 time_milliseconds){
|
||||
//LINUX_FN_DEBUG("%u", time_milliseconds);
|
||||
Linux_Object* object = handle_to_object(handle);
|
||||
|
||||
|
||||
if (object->kind == LinuxObjectKind_Timer){
|
||||
if(object->timer.fd == -1) {
|
||||
object->timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
|
||||
ev.data.ptr = &object->timer.epoll_tag;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, object->timer.fd, &ev);
|
||||
}
|
||||
|
||||
|
||||
struct itimerspec it = {};
|
||||
it.it_value.tv_sec = time_milliseconds / 1000;
|
||||
it.it_value.tv_nsec = (time_milliseconds % 1000) * UINT64_C(1000000);
|
||||
timerfd_settime(object->timer.fd, 0, &it, NULL);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -358,28 +358,28 @@ system_cli_call(Arena* scratch, char* path, char* script, CLI_Handles* cli_out){
|
|||
perror("system_cli_call: pipe");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
pid_t child_pid = vfork();
|
||||
if (child_pid == -1){
|
||||
perror("system_cli_call: fork");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum { PIPE_FD_READ, PIPE_FD_WRITE };
|
||||
|
||||
|
||||
// child
|
||||
if (child_pid == 0){
|
||||
close(pipe_fds[PIPE_FD_READ]);
|
||||
dup2(pipe_fds[PIPE_FD_WRITE], STDOUT_FILENO);
|
||||
dup2(pipe_fds[PIPE_FD_WRITE], STDERR_FILENO);
|
||||
|
||||
|
||||
if (chdir(path) == -1){
|
||||
perror("system_cli_call: chdir");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
char* argv[] = { "sh", "-c", script, NULL };
|
||||
|
||||
|
||||
if (execv("/bin/sh", argv) == -1){
|
||||
perror("system_cli_call: execv");
|
||||
}
|
||||
|
@ -387,17 +387,17 @@ system_cli_call(Arena* scratch, char* path, char* script, CLI_Handles* cli_out){
|
|||
}
|
||||
else{
|
||||
close(pipe_fds[PIPE_FD_WRITE]);
|
||||
|
||||
|
||||
*(pid_t*)&cli_out->proc = child_pid;
|
||||
*(int*)&cli_out->out_read = pipe_fds[PIPE_FD_READ];
|
||||
*(int*)&cli_out->out_write = pipe_fds[PIPE_FD_WRITE];
|
||||
|
||||
|
||||
struct epoll_event e = {};
|
||||
e.events = EPOLLIN | EPOLLET;
|
||||
e.data.ptr = &epoll_tag_cli_pipe;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, pipe_fds[PIPE_FD_READ], &e);
|
||||
}
|
||||
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
@ -411,16 +411,16 @@ internal b32
|
|||
system_cli_update_step(CLI_Handles* cli, char* dest, u32 max, u32* amount){
|
||||
LINUX_FN_DEBUG();
|
||||
int pipe_read_fd = *(int*)&cli->out_read;
|
||||
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(pipe_read_fd, &fds);
|
||||
|
||||
|
||||
struct timeval tv = {};
|
||||
|
||||
|
||||
size_t space_left = max;
|
||||
char* ptr = dest;
|
||||
|
||||
|
||||
while (space_left > 0 && select(pipe_read_fd + 1, &fds, NULL, NULL, &tv) == 1){
|
||||
ssize_t num = read(pipe_read_fd, ptr, space_left);
|
||||
if (num == -1){
|
||||
|
@ -433,7 +433,7 @@ system_cli_update_step(CLI_Handles* cli, char* dest, u32 max, u32* amount){
|
|||
space_left -= num;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*amount = (ptr - dest);
|
||||
return((ptr - dest) > 0);
|
||||
}
|
||||
|
@ -443,16 +443,16 @@ system_cli_end_update(CLI_Handles* cli){
|
|||
LINUX_FN_DEBUG();
|
||||
pid_t pid = *(pid_t*)&cli->proc;
|
||||
b32 close_me = false;
|
||||
|
||||
|
||||
int status;
|
||||
if (pid && waitpid(pid, &status, WNOHANG) > 0){
|
||||
cli->exit = WEXITSTATUS(status);
|
||||
|
||||
|
||||
close_me = true;
|
||||
close(*(int*)&cli->out_read);
|
||||
close(*(int*)&cli->out_write);
|
||||
}
|
||||
|
||||
|
||||
return(close_me);
|
||||
}
|
||||
|
||||
|
@ -484,28 +484,28 @@ internal System_Thread
|
|||
system_thread_launch(Thread_Function* proc, void* ptr){
|
||||
LINUX_FN_DEBUG();
|
||||
System_Thread result = {};
|
||||
|
||||
|
||||
Linux_Object* thread_info = linux_alloc_object(LinuxObjectKind_Thread);
|
||||
thread_info->thread.proc = proc;
|
||||
thread_info->thread.ptr = ptr;
|
||||
|
||||
|
||||
pthread_attr_t thread_attr;
|
||||
pthread_attr_init(&thread_attr);
|
||||
int create_result = pthread_create(
|
||||
&thread_info->thread.pthread,
|
||||
&thread_attr,
|
||||
linux_thread_proc_start,
|
||||
thread_info);
|
||||
|
||||
&thread_info->thread.pthread,
|
||||
&thread_attr,
|
||||
linux_thread_proc_start,
|
||||
thread_info);
|
||||
|
||||
pthread_attr_destroy(&thread_attr);
|
||||
|
||||
|
||||
// TODO(andrew): Need to wait for thread to confirm it launched?
|
||||
if (create_result == 0) {
|
||||
static_assert(sizeof(Linux_Object*) <= sizeof(System_Thread));
|
||||
static_assert(sizeof(Linux_Object*) <= sizeof(System_Thread), "Linux_Object doesn't fit inside System_Thread");
|
||||
*(Linux_Object**)&result = thread_info;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -626,31 +626,31 @@ system_condition_variable_free(System_Condition_Variable cv){
|
|||
|
||||
internal void*
|
||||
system_memory_allocate(u64 size, String_Const_u8 location){
|
||||
|
||||
static_assert(MEMORY_PREFIX_SIZE >= sizeof(Memory_Annotation_Node));
|
||||
|
||||
static_assert(MEMORY_PREFIX_SIZE >= sizeof(Memory_Annotation_Node), "MEMORY_PREFIX_SIZE is not enough to contain Memory_Annotation_Node");
|
||||
u64 adjusted_size = size + MEMORY_PREFIX_SIZE;
|
||||
|
||||
|
||||
Assert(adjusted_size > size);
|
||||
|
||||
|
||||
const int prot = PROT_READ | PROT_WRITE;
|
||||
const int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
|
||||
|
||||
void* result = mmap(NULL, adjusted_size, prot, flags, -1, 0);
|
||||
|
||||
|
||||
if(result == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Linux_Memory_Tracker_Node* node = (Linux_Memory_Tracker_Node*)result;
|
||||
node->location = location;
|
||||
node->size = size;
|
||||
|
||||
|
||||
pthread_mutex_lock(&linuxvars.memory_tracker_mutex);
|
||||
zdll_push_back(linuxvars.memory_tracker_head, linuxvars.memory_tracker_tail, node);
|
||||
linuxvars.memory_tracker_count++;
|
||||
pthread_mutex_unlock(&linuxvars.memory_tracker_mutex);
|
||||
|
||||
|
||||
return (u8*)result + MEMORY_PREFIX_SIZE;
|
||||
}
|
||||
|
||||
|
@ -669,12 +669,12 @@ internal void
|
|||
system_memory_free(void* ptr, u64 size){
|
||||
u64 adjusted_size = size + MEMORY_PREFIX_SIZE;
|
||||
Linux_Memory_Tracker_Node* node = (Linux_Memory_Tracker_Node*)((u8*)ptr - MEMORY_PREFIX_SIZE);
|
||||
|
||||
|
||||
pthread_mutex_lock(&linuxvars.memory_tracker_mutex);
|
||||
zdll_remove(linuxvars.memory_tracker_head, linuxvars.memory_tracker_tail, node);
|
||||
linuxvars.memory_tracker_count--;
|
||||
pthread_mutex_unlock(&linuxvars.memory_tracker_mutex);
|
||||
|
||||
|
||||
if(munmap(node, adjusted_size) == -1) {
|
||||
perror("munmap");
|
||||
}
|
||||
|
@ -683,12 +683,12 @@ system_memory_free(void* ptr, u64 size){
|
|||
internal Memory_Annotation
|
||||
system_memory_annotation(Arena* arena){
|
||||
LINUX_FN_DEBUG();
|
||||
|
||||
|
||||
Memory_Annotation result;
|
||||
Memory_Annotation_Node** ptr = &result.first;
|
||||
|
||||
|
||||
pthread_mutex_lock(&linuxvars.memory_tracker_mutex);
|
||||
|
||||
|
||||
for(Linux_Memory_Tracker_Node* node = linuxvars.memory_tracker_head; node; node = node->next) {
|
||||
*ptr = push_array(arena, Memory_Annotation_Node, 1);
|
||||
(*ptr)->location = node->location;
|
||||
|
@ -697,25 +697,25 @@ system_memory_annotation(Arena* arena){
|
|||
ptr = &(*ptr)->next;
|
||||
result.count++;
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&linuxvars.memory_tracker_mutex);
|
||||
|
||||
|
||||
*ptr = NULL;
|
||||
result.last = CastFromMember(Memory_Annotation_Node, next, ptr);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
system_show_mouse_cursor(i32 show){
|
||||
LINUX_FN_DEBUG("%d", show);
|
||||
|
||||
|
||||
linuxvars.cursor_show = show;
|
||||
|
||||
|
||||
XDefineCursor(
|
||||
linuxvars.dpy,
|
||||
linuxvars.win,
|
||||
show ? None : linuxvars.hidden_cursor);
|
||||
linuxvars.dpy,
|
||||
linuxvars.win,
|
||||
show ? None : linuxvars.hidden_cursor);
|
||||
}
|
||||
|
||||
internal b32
|
||||
|
@ -727,11 +727,11 @@ system_set_fullscreen(b32 full_screen){
|
|||
internal b32
|
||||
system_is_fullscreen(void){
|
||||
b32 result = 0;
|
||||
|
||||
|
||||
// NOTE(inso): This will get the "true" state of fullscreen,
|
||||
// even if it was toggled outside of 4coder.
|
||||
// (e.g. super-F11 on some WMs sets fullscreen for any window/program)
|
||||
|
||||
|
||||
Atom type, *prop;
|
||||
unsigned long nitems, pad;
|
||||
int fmt;
|
||||
|
@ -741,12 +741,12 @@ system_is_fullscreen(void){
|
|||
0, 32, False, XA_ATOM,
|
||||
&type, &fmt, &nitems, &pad,
|
||||
(unsigned char**)&prop);
|
||||
|
||||
|
||||
if(ret == Success && prop){
|
||||
result = *prop == linuxvars.atom__NET_WM_STATE_FULLSCREEN;
|
||||
XFree((unsigned char*)prop);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue