linux file track stuff working afaict
parent
0378546dd8
commit
a0f3996e73
5
Makefile
5
Makefile
|
@ -1,4 +1,5 @@
|
|||
CPP_FILES := $(wildcard *.cpp) $(wildcard **/*.cpp)
|
||||
C_FILES := $(wildcard *.c) $(wildcard **/*.c)
|
||||
H_FILES := $(wildcard *.h) $(wildcard **/*.h)
|
||||
WARNINGS := -Wno-write-strings
|
||||
PLAT_LINKS := -L/usr/local/lib -lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes -lfreetype -lfontconfig
|
||||
|
@ -9,10 +10,10 @@ FLAGS := -fPIC -fno-threadsafe-statics -pthread -I../foreign $(shell pkg-co
|
|||
debug: FLAGS += -DFRED_INTERNAL=1 -DFRED_SUPER=1 -g -O0
|
||||
debug: ../4ed_app.so ../4ed
|
||||
|
||||
../4ed_app.so: $(CPP_FILES) $(H_FILES)
|
||||
../4ed_app.so: $(CPP_FILES) $(C_FILES) $(H_FILES)
|
||||
g++ $(WARNINGS) $(FLAGS) -shared 4ed_app_target.cpp -iquoteforeign -o $@
|
||||
|
||||
../4ed: $(CPP_FILES) $(H_FILES)
|
||||
../4ed: $(CPP_FILES) $(C_FILES) $(H_FILES)
|
||||
g++ $(WARNINGS) $(FLAGS) linux_4ed.cpp -iquoteforeign $(PLAT_LINKS) -o $@
|
||||
|
||||
clean:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
|
||||
The OS agnostic file tracking API for applications
|
||||
that want to interact with potentially many files on
|
||||
the disk that could be changed by other applications.
|
||||
The OS agnostic file tracking API for applications
|
||||
that want to interact with potentially many files on
|
||||
the disk that could be changed by other applications.
|
||||
|
||||
Created on: 29.08.2016
|
||||
Created on: 29.08.2016
|
||||
|
||||
*/
|
||||
|
||||
|
@ -43,8 +43,16 @@ typedef struct {
|
|||
// Right now the way the API works, it assumes that the user will
|
||||
// only ever add memory and never free it. If freeing becomes necessary
|
||||
// on Linux the API can be extended to support that.
|
||||
|
||||
int inotify;
|
||||
pthread_mutex_t lock;
|
||||
char *string_mem_begin;
|
||||
char *string_mem_end;
|
||||
|
||||
} Linux_File_Track_Vars;
|
||||
|
||||
//static_assert(sizeof(Linux_File_Track_Vars) <= sizeof(File_Track_System));
|
||||
|
||||
typedef struct {
|
||||
File_Index hash;
|
||||
// NOTE(allen):
|
||||
|
@ -54,8 +62,11 @@ typedef struct {
|
|||
// would be fine. If it is used hash should be the first element
|
||||
// of this struct and it should be used to uniquely identify each
|
||||
// entry because it is used as the key for the table.
|
||||
char* filename;
|
||||
} Linux_File_Track_Entry;
|
||||
|
||||
//static_assert(sizeof(Linux_File_Track_Entry) <= sizeof(File_Track_Entry));
|
||||
|
||||
#define to_vars(s) ((Linux_File_Track_Vars*)(s))
|
||||
#define to_tables(v) ((File_Track_Tables*)(v->tables))
|
||||
|
||||
|
@ -65,24 +76,29 @@ init_track_system(File_Track_System *system,
|
|||
void *listener_memory, int32_t listener_memory_size){
|
||||
File_Track_Result result = FileTrack_MemoryTooSmall;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
|
||||
Assert(sizeof(Linux_File_Track_Entry) <= sizeof(File_Track_Entry));
|
||||
|
||||
|
||||
if (enough_memory_to_init_table(table_memory_size) &&
|
||||
/*if listener memory is important check it's size here*/ 1){
|
||||
|
||||
|
||||
// NOTE(allen): Initialize main data tables
|
||||
vars->tables = table_memory;
|
||||
vars->tables = (File_Track_Tables*) table_memory;
|
||||
File_Track_Tables *tables = to_tables(vars);
|
||||
init_table_memory(tables, table_memory_size);
|
||||
|
||||
// NOTE(allen):
|
||||
// Here prepare the data structure and synchronization primatives
|
||||
// in the vars struct.
|
||||
|
||||
|
||||
vars->inotify = inotify_init1(IN_NONBLOCK);
|
||||
|
||||
pthread_mutex_init(&vars->lock, NULL);
|
||||
|
||||
vars->string_mem_begin = (char*)listener_memory;
|
||||
vars->string_mem_end = (char*)listener_memory + listener_memory_size;
|
||||
|
||||
result = FileTrack_Good;
|
||||
}
|
||||
|
||||
|
||||
LINUX_FN_DEBUG("result: %d", result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -90,9 +106,10 @@ FILE_TRACK_LINK File_Track_Result
|
|||
add_listener(File_Track_System *system, char *filename){
|
||||
File_Track_Result result = FileTrack_Good;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
// ACQUIRE LOCK (only keep this if either of the data structures is kept)
|
||||
|
||||
File_Track_Tables *tables = to_tables(vars);
|
||||
|
||||
pthread_mutex_lock(&vars->lock);
|
||||
|
||||
// NOTE(allen):
|
||||
// Here do something to begin listening to changes to the file named filename.
|
||||
// On Windows it listens to the parent directory if no other file in that
|
||||
|
@ -101,9 +118,43 @@ add_listener(File_Track_System *system, char *filename){
|
|||
// different names that both refer to the same file. In this case we should
|
||||
// treat them as two separate files so that if one of the listeners is removed
|
||||
// the other on the same file keeps working.
|
||||
|
||||
// RELEASE LOCK
|
||||
|
||||
|
||||
if(tracking_system_has_space(tables, 1)){
|
||||
size_t filename_len = strlen(filename) + 1;
|
||||
if(vars->string_mem_end - vars->string_mem_begin >= filename_len){
|
||||
|
||||
// TODO(inso): which events do we want?
|
||||
int wd = inotify_add_watch(vars->inotify, filename, IN_ALL_EVENTS);
|
||||
if(wd != -1){
|
||||
File_Index key = { wd, 1 };
|
||||
File_Track_Entry *entry = tracking_system_lookup_entry(tables, key);
|
||||
Linux_File_Track_Entry *linux_entry = (Linux_File_Track_Entry*) entry;
|
||||
|
||||
LINUX_FN_DEBUG("map %s to wd %d", filename, wd);
|
||||
|
||||
Assert(entry_is_available(entry));
|
||||
|
||||
linux_entry->hash = key;
|
||||
linux_entry->filename = vars->string_mem_begin;
|
||||
|
||||
memcpy(vars->string_mem_begin, filename, filename_len);
|
||||
vars->string_mem_begin += filename_len;
|
||||
|
||||
++tables->tracked_count;
|
||||
} else {
|
||||
result = FileTrack_FileSystemError;
|
||||
}
|
||||
} else {
|
||||
result = FileTrack_OutOfListenerMemory;
|
||||
}
|
||||
} else {
|
||||
result = FileTrack_OutOfTableMemory;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&vars->lock);
|
||||
|
||||
LINUX_FN_DEBUG("result: %d", result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -111,16 +162,35 @@ FILE_TRACK_LINK File_Track_Result
|
|||
remove_listener(File_Track_System *system, char *filename){
|
||||
File_Track_Result result = FileTrack_Good;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
// ACQUIRE LOCK
|
||||
|
||||
File_Track_Tables *tables = to_tables(vars);
|
||||
File_Track_Entry *entries = (File_Track_Entry*) to_ptr(tables, tables->file_table);
|
||||
|
||||
pthread_mutex_lock(&vars->lock);
|
||||
|
||||
// NOTE(allen):
|
||||
// Here do something to stop listening to changes to the file named filename.
|
||||
// We assume this filename has been passed into add_listener already and that
|
||||
// if it has not it is a bug in the user's code not in this code.
|
||||
|
||||
// RELEASE LOCK
|
||||
|
||||
|
||||
for(uint32_t i = 0; i < tables->max; ++i){
|
||||
Linux_File_Track_Entry *e = (Linux_File_Track_Entry*)(entries + i);
|
||||
if(e->hash.id[1] != 1) continue;
|
||||
if(strcmp(e->filename, filename) == 0){
|
||||
LINUX_FN_DEBUG("%s found as wd %d", filename, e->hash.id[0]);
|
||||
if(inotify_rm_watch(vars->inotify, e->hash.id[0]) == -1){
|
||||
perror("inotify_rm_watch");
|
||||
result = FileTrack_FileSystemError;
|
||||
}
|
||||
internal_free_slot(tables, (File_Track_Entry*)e);
|
||||
// NOTE(inso): associated string memory in listeners would be freed here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&vars->lock);
|
||||
|
||||
LINUX_FN_DEBUG("result: %d", result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -128,9 +198,9 @@ FILE_TRACK_LINK File_Track_Result
|
|||
move_track_system(File_Track_System *system, void *mem, int32_t size){
|
||||
File_Track_Result result = FileTrack_Good;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
// ACQUIRE LOCK
|
||||
|
||||
|
||||
pthread_mutex_lock(&vars->lock);
|
||||
|
||||
{
|
||||
File_Track_Tables *original_tables = to_tables(vars);
|
||||
result = move_table_memory(original_tables, mem, size);
|
||||
|
@ -138,9 +208,11 @@ move_track_system(File_Track_System *system, void *mem, int32_t size){
|
|||
vars->tables = mem;
|
||||
}
|
||||
}
|
||||
|
||||
// RELEASE LOCK
|
||||
|
||||
|
||||
pthread_mutex_unlock(&vars->lock);
|
||||
|
||||
LINUX_FN_DEBUG("size: %d, %d", size, result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -148,16 +220,30 @@ FILE_TRACK_LINK File_Track_Result
|
|||
expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size){
|
||||
File_Track_Result result = FileTrack_Good;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
// ACQUIRE LOCK
|
||||
|
||||
|
||||
pthread_mutex_lock(&vars->lock);
|
||||
|
||||
// NOTE(allen): If there is a data structure for the listeners
|
||||
// this call adds more memory to that system. If this system
|
||||
// wants to free old memory the API does not currently support
|
||||
// that but it can.
|
||||
|
||||
// RELEASE LOCK
|
||||
|
||||
|
||||
// NOTE(inso): pointer to old string mem is lost here.
|
||||
// would need to keep it around if we want to free in the future
|
||||
|
||||
// NOTE(inso): assuming PATH_MAX is a reasonable lower bound of extra memory to get
|
||||
|
||||
if(size < PATH_MAX){
|
||||
result = FileTrack_MemoryTooSmall;
|
||||
} else {
|
||||
vars->string_mem_begin = (char*) mem;
|
||||
vars->string_mem_end = (char*) mem + size;;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&vars->lock);
|
||||
|
||||
LINUX_FN_DEBUG("size: %d, result: %d", size, result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -165,9 +251,10 @@ FILE_TRACK_LINK File_Track_Result
|
|||
get_change_event(File_Track_System *system, char *buffer, int32_t max, int32_t *size){
|
||||
File_Track_Result result = FileTrack_NoMoreEvents;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
// ACQUIRE LOCK
|
||||
|
||||
File_Track_Tables *tables = to_tables(vars);
|
||||
|
||||
pthread_mutex_lock(&vars->lock);
|
||||
|
||||
// NOTE(allen): If there are any new file changes report them
|
||||
// by copying the name of the file to the buffer and returning
|
||||
// FileTrack_Good. It is allowed for this system to report
|
||||
|
@ -175,9 +262,36 @@ get_change_event(File_Track_System *system, char *buffer, int32_t max, int32_t *
|
|||
// is up to the user to check the filename and see if it cares
|
||||
// about that file. If there are no new changes the return
|
||||
// FileTrack_NoMoreEvents.
|
||||
|
||||
// RELEASE LOCK
|
||||
|
||||
|
||||
struct inotify_event ev;
|
||||
|
||||
ssize_t n = read(vars->inotify, &ev, sizeof(ev));
|
||||
if(n == -1 && errno != EAGAIN){
|
||||
perror("inotify read");
|
||||
} else if(n > 0){
|
||||
File_Index key = { ev.wd, 1 };
|
||||
File_Track_Entry *entry = tracking_system_lookup_entry(tables, key);
|
||||
Linux_File_Track_Entry *linux_entry = (Linux_File_Track_Entry*) entry;
|
||||
|
||||
if(!entry_is_available(entry)){
|
||||
LINUX_FN_DEBUG("event from wd %d (%s)", ev.wd, linux_entry->filename);
|
||||
size_t filename_size = strlen(linux_entry->filename);
|
||||
if(max < filename_size){
|
||||
result = FileTrack_MemoryTooSmall;
|
||||
// NOTE(inso): this event will be dropped, needs to be stashed.
|
||||
LINUX_FN_DEBUG("max too small, event dropped");
|
||||
} else {
|
||||
memcpy(buffer, linux_entry->filename, filename_size);
|
||||
*size = filename_size;
|
||||
result = FileTrack_Good;
|
||||
}
|
||||
} else {
|
||||
LINUX_FN_DEBUG("dead event from wd %d", ev.wd);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&vars->lock);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -185,27 +299,16 @@ FILE_TRACK_LINK File_Track_Result
|
|||
shut_down_track_system(File_Track_System *system){
|
||||
File_Track_Result result = FileTrack_Good;
|
||||
Linux_File_Track_Vars *vars = to_vars(system);
|
||||
|
||||
|
||||
// NOTE(allen): Close all the handles stored in the table.
|
||||
{
|
||||
File_Track_Tables *tables = to_tables(vars);
|
||||
|
||||
File_Track_Entry *entries = (File_Track_Entry*)to_ptr(tables, tables->file_table);
|
||||
uint32_t max = tables->max;
|
||||
|
||||
for (uint32_t index = 0; index < max; ++index){
|
||||
File_Track_Entry *entry = entries + index;
|
||||
|
||||
if (!entry_is_available(entry)){
|
||||
// NOTE(allen): If table entries contain anything
|
||||
// that need cleanup, that cleanup should happen here.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(allen): Close all the global track system resources.
|
||||
|
||||
if(close(vars->inotify) == -1){
|
||||
result = FileTrack_FileSystemError;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&vars->lock);
|
||||
|
||||
LINUX_FN_DEBUG("result: %d", result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
|
474
linux_4ed.cpp
474
linux_4ed.cpp
|
@ -69,8 +69,6 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "filetrack/4tech_file_track_linux.c"
|
||||
#include "system_shared.h"
|
||||
|
||||
//
|
||||
// Linux macros
|
||||
|
@ -105,6 +103,9 @@
|
|||
|
||||
#define InterlockedCompareExchange(dest, ex, comp) __sync_val_compare_and_swap((dest), (comp), (ex))
|
||||
|
||||
#include "filetrack/4tech_file_track_linux.c"
|
||||
#include "system_shared.h"
|
||||
|
||||
//
|
||||
// Linux structs / enums
|
||||
//
|
||||
|
@ -120,11 +121,10 @@ struct Sys_Bubble : public Bubble{
|
|||
|
||||
enum {
|
||||
LINUX_4ED_EVENT_X11 = (UINT64_C(1) << 32),
|
||||
LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(1) << 33),
|
||||
LINUX_4ED_EVENT_FILE = (UINT64_C(1) << 34),
|
||||
LINUX_4ED_EVENT_STEP = (UINT64_C(1) << 35),
|
||||
LINUX_4ED_EVENT_STEP_TIMER = (UINT64_C(1) << 36),
|
||||
LINUX_4ED_EVENT_CLI = (UINT64_C(1) << 37),
|
||||
LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(2) << 32),
|
||||
LINUX_4ED_EVENT_STEP = (UINT64_C(3) << 32),
|
||||
LINUX_4ED_EVENT_STEP_TIMER = (UINT64_C(4) << 32),
|
||||
LINUX_4ED_EVENT_CLI = (UINT64_C(5) << 32),
|
||||
};
|
||||
|
||||
struct Linux_Coroutine {
|
||||
|
@ -268,11 +268,7 @@ static_assert(sizeof(Plat_Handle) >= sizeof(sem_t*), "Plat_Handle not big e
|
|||
static_assert(sizeof(Plat_Handle) >= sizeof(int), "Plat_Handle not big enough");
|
||||
|
||||
//
|
||||
// Linux shared/system functions
|
||||
//
|
||||
|
||||
//
|
||||
// Memory
|
||||
// Shared system functions (system_shared.h)
|
||||
//
|
||||
|
||||
internal void*
|
||||
|
@ -341,9 +337,6 @@ Sys_Free_Memory_Sig(system_free_memory){
|
|||
LinuxFreeMemory(block);
|
||||
}
|
||||
|
||||
//
|
||||
// File
|
||||
//
|
||||
|
||||
internal
|
||||
Sys_File_Can_Be_Made_Sig(system_file_can_be_made){
|
||||
|
@ -368,49 +361,13 @@ Sys_Get_Binary_Path_Sig(system_get_binary_path){
|
|||
}
|
||||
|
||||
//
|
||||
// Linux application/system functions
|
||||
// System Functions (4ed_system.h)
|
||||
//
|
||||
|
||||
//
|
||||
// File
|
||||
// Files
|
||||
//
|
||||
|
||||
internal
|
||||
Sys_File_Time_Stamp_Sig(system_file_time_stamp){
|
||||
struct stat info = {};
|
||||
u64 microsecond_timestamp = 0;
|
||||
|
||||
if(stat(filename, &info) == 0){
|
||||
#if OLD_STAT_NANO_TIME
|
||||
microsecond_timestamp =
|
||||
(info.st_mtime * UINT64_C(1000000)) +
|
||||
(info.st_mtimensec / UINT64_C(1000));
|
||||
#else
|
||||
microsecond_timestamp =
|
||||
(info.st_mtim.tv_sec * UINT64_C(1000000)) +
|
||||
(info.st_mtim.tv_nsec / UINT64_C(1000));
|
||||
#endif
|
||||
}
|
||||
|
||||
//LINUX_FN_DEBUG("%s = %" PRIu64, filename, microsecond_timestamp);
|
||||
|
||||
return(microsecond_timestamp);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Now_Time_Stamp_Sig(system_now_time_stamp){
|
||||
struct timespec spec;
|
||||
u64 result;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000));
|
||||
|
||||
//LINUX_FN_DEBUG("ts: %" PRIu64, result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
internal
|
||||
Sys_Set_File_List_Sig(system_set_file_list){
|
||||
DIR *d;
|
||||
|
@ -503,105 +460,88 @@ Sys_Set_File_List_Sig(system_set_file_list){
|
|||
}
|
||||
|
||||
internal
|
||||
Sys_File_Unique_Hash_Sig(system_file_unique_hash){
|
||||
Unique_Hash result = {};
|
||||
struct stat st = {};
|
||||
*success = 0;
|
||||
Sys_Get_Canonical_Sig(system_get_canonical){
|
||||
int32_t result = 0;
|
||||
|
||||
if(stat(filename.str, &st) == 0){
|
||||
memcpy(&result, &st.st_dev, sizeof(st.st_dev));
|
||||
memcpy((char*)&result + sizeof(st.st_dev), &st.st_ino, sizeof(st.st_ino));
|
||||
*success = 1;
|
||||
char* path = realpath(strndupa(filename, len), NULL);
|
||||
if(!path){
|
||||
perror("realpath");
|
||||
} else {
|
||||
size_t path_len = strlen(path);
|
||||
if(max >= path_len){
|
||||
memcpy(buffer, path, path_len);
|
||||
result = path_len;
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
// LINUX_FN_DEBUG("%s = %ld:%ld", filename.str, (long)st.st_dev, (long)st.st_ino);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_File_Track_Sig(system_file_track){
|
||||
if(filename.size <= 0 || !filename.str) return;
|
||||
|
||||
char* fname = (char*) alloca(filename.size+1);
|
||||
memcpy(fname, filename.str, filename.size);
|
||||
fname[filename.size] = 0;
|
||||
|
||||
int wd = inotify_add_watch(linuxvars.inotify_fd, fname, IN_ALL_EVENTS);
|
||||
if(wd == -1){
|
||||
perror("inotify_add_watch");
|
||||
} else {
|
||||
printf("watch %s\n", fname);
|
||||
// TODO: store the wd somewhere so Untrack can use it
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_File_Untrack_Sig(system_file_untrack){
|
||||
//TODO
|
||||
// inotify_rm_watch(...)
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_File_Load_Begin_Sig(system_file_load_begin){
|
||||
File_Loading loading = {};
|
||||
struct stat info = {};
|
||||
|
||||
LINUX_FN_DEBUG("%s", filename);
|
||||
Sys_Load_Handle_Sig(system_load_handle){
|
||||
b32 result = 0;
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if(fd < 0){
|
||||
fprintf(stderr, "sys_open_file: open '%s': %s\n", filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
if(fstat(fd, &info) < 0){
|
||||
fprintf(stderr, "sys_open_file: stat '%s': %s\n", filename, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
if(info.st_size < 0){
|
||||
fprintf(stderr, "sys_open_file: st_size < 0: %ld\n", info.st_size);
|
||||
goto out;
|
||||
if(fd == -1){
|
||||
perror("open");
|
||||
} else {
|
||||
*(int*)handle_out = fd;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
loading.handle = LinuxFDToHandle(fd);
|
||||
loading.size = info.st_size;
|
||||
loading.exists = 1;
|
||||
|
||||
out:
|
||||
if(fd != -1 && !loading.exists) close(fd);
|
||||
return(loading);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_File_Load_End_Sig(system_file_load_end){
|
||||
int fd = LinuxHandleToFD(loading.handle);
|
||||
char* ptr = buffer;
|
||||
size_t size = loading.size;
|
||||
Sys_Load_Size_Sig(system_load_size){
|
||||
u32 result = 0;
|
||||
|
||||
if(!loading.exists || fd == -1) return 0;
|
||||
int fd = *(int*)&handle;
|
||||
struct stat st;
|
||||
|
||||
if(fstat(fd, &st) == -1){
|
||||
perror("fstat");
|
||||
} else {
|
||||
result = st.st_size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Load_File_Sig(system_load_file){
|
||||
|
||||
int fd = *(int*)&handle;
|
||||
do {
|
||||
ssize_t read_result = read(fd, buffer, size);
|
||||
if(read_result == -1){
|
||||
if(errno != EINTR){
|
||||
perror("system_file_load_end");
|
||||
break;
|
||||
}
|
||||
ssize_t n = read(fd, buffer, size);
|
||||
if(n == -1 && errno != EAGAIN){
|
||||
perror("read");
|
||||
break;
|
||||
} else {
|
||||
size -= read_result;
|
||||
ptr += read_result;
|
||||
size -= n;
|
||||
buffer += n;
|
||||
}
|
||||
} while(size);
|
||||
|
||||
close(fd);
|
||||
|
||||
LINUX_FN_DEBUG("success == %d", (size == 0));
|
||||
|
||||
return (size == 0);
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_File_Save_Sig(system_file_save){
|
||||
Sys_Load_Close_Sig(system_load_close){
|
||||
b32 result = 1;
|
||||
|
||||
int fd = *(int*)&handle;
|
||||
if(close(fd) == -1){
|
||||
perror("close");
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Save_File_Sig(system_save_file){
|
||||
b32 result = 0;
|
||||
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 00640);
|
||||
|
||||
|
@ -630,7 +570,24 @@ Sys_File_Save_Sig(system_file_save){
|
|||
}
|
||||
|
||||
//
|
||||
// Custom access to OS pages
|
||||
// Time
|
||||
//
|
||||
|
||||
internal
|
||||
Sys_Now_Time_Sig(system_now_time){
|
||||
struct timespec spec;
|
||||
u64 result;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
result = (spec.tv_sec * UINT64_C(1000000)) + (spec.tv_nsec / UINT64_C(1000));
|
||||
|
||||
//LINUX_FN_DEBUG("ts: %" PRIu64, result);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
//
|
||||
// 4coder_custom.h
|
||||
//
|
||||
|
||||
internal
|
||||
|
@ -692,10 +649,6 @@ MEMORY_FREE_SIG(system_memory_free){
|
|||
munmap(mem, size);
|
||||
}
|
||||
|
||||
//
|
||||
// Filesystem navigation
|
||||
//
|
||||
|
||||
internal
|
||||
FILE_EXISTS_SIG(system_file_exists){
|
||||
int result = 0;
|
||||
|
@ -983,175 +936,26 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
|
|||
// Threads
|
||||
//
|
||||
|
||||
//#define OLD_JOB_QUEUE
|
||||
|
||||
#ifdef OLD_JOB_QUEUE
|
||||
internal void*
|
||||
JobThreadProc(void* arg){
|
||||
Thread_Context *thread = (Thread_Context*)arg;
|
||||
Work_Queue *queue = linuxvars.queues + thread->group_id;
|
||||
Thread_Group *group = linuxvars.groups + thread->group_id;
|
||||
|
||||
i32 thread_index = thread->id - 1;
|
||||
|
||||
i32 cancel_lock = group->cancel_lock0 + thread_index;
|
||||
i32 cancel_cv = group->cancel_cv0 + thread_index;
|
||||
|
||||
Thread_Memory *thread_memory = linuxvars.thread_memory + thread_index;
|
||||
|
||||
if (thread_memory->size == 0){
|
||||
i32 new_size = Kbytes(64);
|
||||
thread_memory->data = LinuxGetMemory(new_size);
|
||||
thread_memory->size = new_size;
|
||||
}
|
||||
|
||||
for (;;){
|
||||
u32 read_index = queue->read_position;
|
||||
u32 write_index = queue->write_position;
|
||||
|
||||
if (read_index != write_index){
|
||||
u32 next_read_index = (read_index + 1) % QUEUE_WRAP;
|
||||
u32 safe_read_index =
|
||||
__sync_val_compare_and_swap(&queue->read_position,
|
||||
read_index, next_read_index);
|
||||
|
||||
if (safe_read_index == read_index){
|
||||
Full_Job_Data *full_job = queue->jobs + safe_read_index;
|
||||
// NOTE(allen): This is interlocked so that it plays nice
|
||||
// with the cancel job routine, which may try to cancel this job
|
||||
// at the same time that we try to run it
|
||||
|
||||
i32 safe_running_thread =
|
||||
__sync_val_compare_and_swap(&full_job->running_thread,
|
||||
THREAD_NOT_ASSIGNED, thread->id);
|
||||
|
||||
if (safe_running_thread == THREAD_NOT_ASSIGNED){
|
||||
thread->job_id = full_job->id;
|
||||
thread->running = 1;
|
||||
|
||||
full_job->job.callback(&linuxvars.system, thread, thread_memory, full_job->job.data);
|
||||
full_job->running_thread = 0;
|
||||
thread->running = 0;
|
||||
|
||||
system_acquire_lock(cancel_lock);
|
||||
if(thread->cancel){
|
||||
thread->cancel = 0;
|
||||
pthread_cond_signal(linuxvars.conds + cancel_cv);
|
||||
}
|
||||
system_release_lock(cancel_lock);
|
||||
|
||||
LinuxScheduleStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
sem_wait(LinuxHandleToSem(queue->semaphore));
|
||||
}
|
||||
}
|
||||
internal
|
||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||
pthread_mutex_lock(linuxvars.locks + id);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
Work_Queue *queue = linuxvars.queues + group_id;
|
||||
|
||||
Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP);
|
||||
|
||||
b32 success = 0;
|
||||
u32 result = 0;
|
||||
while (!success){
|
||||
u32 write_index = queue->write_position;
|
||||
u32 next_write_index = (write_index + 1) % QUEUE_WRAP;
|
||||
u32 safe_write_index =
|
||||
__sync_val_compare_and_swap(&queue->write_position,
|
||||
write_index, next_write_index);
|
||||
if (safe_write_index == write_index){
|
||||
result = write_index;
|
||||
write_index = write_index % QUEUE_WRAP;
|
||||
queue->jobs[write_index].job = job;
|
||||
queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED;
|
||||
queue->jobs[write_index].id = result;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sem_post(LinuxHandleToSem(queue->semaphore));
|
||||
|
||||
return result;
|
||||
Sys_Release_Lock_Sig(system_release_lock){
|
||||
pthread_mutex_unlock(linuxvars.locks + id);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
Work_Queue *queue = linuxvars.queues + group_id;
|
||||
Thread_Group *group = linuxvars.groups + group_id;
|
||||
|
||||
u32 job_index = job_id % QUEUE_WRAP;
|
||||
Full_Job_Data *full_job = queue->jobs + job_index;
|
||||
|
||||
Assert(full_job->id == job_id);
|
||||
u32 thread_id =
|
||||
__sync_val_compare_and_swap(&full_job->running_thread,
|
||||
THREAD_NOT_ASSIGNED, 0);
|
||||
|
||||
if (thread_id != THREAD_NOT_ASSIGNED && thread_id != 0){
|
||||
i32 thread_index = thread_id - 1;
|
||||
|
||||
i32 cancel_lock = group->cancel_lock0 + thread_index;
|
||||
i32 cancel_cv = group->cancel_cv0 + thread_index;
|
||||
Thread_Context *thread = group->threads + thread_index;
|
||||
|
||||
system_acquire_lock(cancel_lock);
|
||||
thread->cancel = 1;
|
||||
|
||||
system_release_lock(FRAME_LOCK);
|
||||
do {
|
||||
pthread_cond_wait(linuxvars.conds + cancel_cv, linuxvars.locks + cancel_lock);
|
||||
} while(thread->cancel == 1);
|
||||
system_acquire_lock(FRAME_LOCK);
|
||||
|
||||
system_release_lock(cancel_lock);
|
||||
|
||||
LinuxScheduleStep();
|
||||
}
|
||||
|
||||
internal void
|
||||
system_wait_cv(i32 lock_id, i32 cv_id){
|
||||
pthread_cond_wait(linuxvars.conds + cv_id, linuxvars.locks + lock_id);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Check_Cancel_Sig(system_check_cancel){
|
||||
b32 result = 0;
|
||||
|
||||
Thread_Group* group = linuxvars.groups + thread->group_id;
|
||||
i32 thread_index = thread->id - 1;
|
||||
i32 cancel_lock = group->cancel_lock0 + thread_index;
|
||||
|
||||
system_acquire_lock(cancel_lock);
|
||||
if (thread->cancel){
|
||||
result = 1;
|
||||
}
|
||||
system_release_lock(cancel_lock);
|
||||
|
||||
return (result);
|
||||
internal void
|
||||
system_signal_cv(i32 lock_id, i32 cv_id){
|
||||
pthread_cond_signal(linuxvars.conds + cv_id);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
||||
void *old_data;
|
||||
i32 old_size, new_size;
|
||||
|
||||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
old_data = memory->data;
|
||||
old_size = memory->size;
|
||||
new_size = LargeRoundUp(memory->size*2, Kbytes(4));
|
||||
memory->data = system_get_memory(new_size);
|
||||
memory->size = new_size;
|
||||
if (old_data){
|
||||
memcpy(memory->data, old_data, old_size);
|
||||
system_free_memory(old_data);
|
||||
}
|
||||
system_release_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
}
|
||||
|
||||
#else // new job queue
|
||||
|
||||
internal void*
|
||||
JobThreadProc(void* lpParameter){
|
||||
Thread_Context *thread = (Thread_Context*)lpParameter;
|
||||
|
@ -1441,28 +1245,6 @@ Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
|||
system_release_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
}
|
||||
|
||||
#endif // OLD_JOB_QUEUE
|
||||
|
||||
internal
|
||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||
pthread_mutex_lock(linuxvars.locks + id);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Release_Lock_Sig(system_release_lock){
|
||||
pthread_mutex_unlock(linuxvars.locks + id);
|
||||
}
|
||||
|
||||
internal void
|
||||
system_wait_cv(i32 lock_id, i32 cv_id){
|
||||
pthread_cond_wait(linuxvars.conds + cv_id, linuxvars.locks + lock_id);
|
||||
}
|
||||
|
||||
internal void
|
||||
system_signal_cv(i32 lock_id, i32 cv_id){
|
||||
pthread_cond_signal(linuxvars.conds + cv_id);
|
||||
}
|
||||
|
||||
//
|
||||
// Debug
|
||||
//
|
||||
|
@ -1607,17 +1389,23 @@ LinuxLoadAppCode(String* base_dir){
|
|||
|
||||
internal void
|
||||
LinuxLoadSystemCode(){
|
||||
|
||||
linuxvars.system.file_time_stamp = system_file_time_stamp;
|
||||
linuxvars.system.now_time_stamp = system_now_time_stamp;
|
||||
|
||||
// files
|
||||
linuxvars.system.set_file_list = system_set_file_list;
|
||||
linuxvars.system.file_unique_hash = system_file_unique_hash;
|
||||
linuxvars.system.file_track = system_file_track;
|
||||
linuxvars.system.file_untrack = system_file_untrack;
|
||||
linuxvars.system.file_load_begin = system_file_load_begin;
|
||||
linuxvars.system.file_load_end = system_file_load_end;
|
||||
linuxvars.system.file_save = system_file_save;
|
||||
linuxvars.system.get_canonical = system_get_canonical;
|
||||
linuxvars.system.add_listener = system_add_listener;
|
||||
linuxvars.system.remove_listener = system_remove_listener;
|
||||
linuxvars.system.get_file_change = system_get_file_change;
|
||||
linuxvars.system.load_handle = system_load_handle;
|
||||
linuxvars.system.load_size = system_load_size;
|
||||
linuxvars.system.load_file = system_load_file;
|
||||
linuxvars.system.load_close = system_load_close;
|
||||
linuxvars.system.save_file = system_save_file;
|
||||
|
||||
// time
|
||||
linuxvars.system.now_time = system_now_time;
|
||||
|
||||
// 4coder_custom.h
|
||||
linuxvars.system.memory_allocate = system_memory_allocate;
|
||||
linuxvars.system.memory_set_protection = system_memory_set_protection;
|
||||
linuxvars.system.memory_free = system_memory_free;
|
||||
|
@ -1626,18 +1414,22 @@ LinuxLoadSystemCode(){
|
|||
linuxvars.system.get_4ed_path = system_get_4ed_path;
|
||||
linuxvars.system.show_mouse_cursor = system_show_mouse_cursor;
|
||||
|
||||
// clipboard
|
||||
linuxvars.system.post_clipboard = system_post_clipboard;
|
||||
|
||||
// coroutine
|
||||
linuxvars.system.create_coroutine = system_create_coroutine;
|
||||
linuxvars.system.launch_coroutine = system_launch_coroutine;
|
||||
linuxvars.system.resume_coroutine = system_resume_coroutine;
|
||||
linuxvars.system.yield_coroutine = system_yield_coroutine;
|
||||
|
||||
// cli
|
||||
linuxvars.system.cli_call = system_cli_call;
|
||||
linuxvars.system.cli_begin_update = system_cli_begin_update;
|
||||
linuxvars.system.cli_update_step = system_cli_update_step;
|
||||
linuxvars.system.cli_end_update = system_cli_end_update;
|
||||
|
||||
// threads
|
||||
linuxvars.system.post_job = system_post_job;
|
||||
linuxvars.system.cancel_job = system_cancel_job;
|
||||
linuxvars.system.check_cancel = system_check_cancel;
|
||||
|
@ -1645,12 +1437,14 @@ LinuxLoadSystemCode(){
|
|||
linuxvars.system.acquire_lock = system_acquire_lock;
|
||||
linuxvars.system.release_lock = system_release_lock;
|
||||
|
||||
// debug
|
||||
#if FRED_INTERNAL
|
||||
linuxvars.system.internal_sentinel = internal_sentinel;
|
||||
linuxvars.system.internal_get_thread_states = internal_get_thread_states;
|
||||
linuxvars.system.internal_debug_message = internal_debug_message;
|
||||
#endif
|
||||
|
||||
// non-function details
|
||||
linuxvars.system.slash = '/';
|
||||
}
|
||||
|
||||
|
@ -2226,7 +2020,7 @@ LinuxStringDup(String* str, void* data, size_t size){
|
|||
internal void
|
||||
LinuxScheduleStep(void)
|
||||
{
|
||||
u64 now = system_now_time_stamp();
|
||||
u64 now = system_now_time();
|
||||
u64 diff = (now - linuxvars.last_step);
|
||||
|
||||
if(diff > (u64)frame_useconds){
|
||||
|
@ -2924,23 +2718,6 @@ LinuxHandleX11Events(void)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// inotify utility func
|
||||
//
|
||||
|
||||
internal void
|
||||
LinuxHandleFileEvents()
|
||||
{
|
||||
struct inotify_event* e;
|
||||
char buff[sizeof(*e) + NAME_MAX + 1];
|
||||
|
||||
ssize_t num_bytes = read(linuxvars.inotify_fd, buff, sizeof(buff));
|
||||
for(char* p = buff; (p - buff) < num_bytes; p += (sizeof(*e) + e->len)){
|
||||
e = (struct inotify_event*)p;
|
||||
// TODO: do something with the e->wd / e->name & report that in app.step?
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Entry point
|
||||
//
|
||||
|
@ -2979,7 +2756,9 @@ main(int argc, char **argv)
|
|||
memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size);
|
||||
|
||||
linuxvars.target.max = Mbytes(1);
|
||||
linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max);
|
||||
linuxvars.target.push_buffer = (char*)system_get_memory(linuxvars.target.max);
|
||||
|
||||
init_shared_vars();
|
||||
|
||||
//
|
||||
// Read command line
|
||||
|
@ -3248,9 +3027,6 @@ main(int argc, char **argv)
|
|||
e.data.u64 = LINUX_4ED_EVENT_X11;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.x11_fd, &e);
|
||||
|
||||
e.data.u64 = LINUX_4ED_EVENT_FILE;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.inotify_fd, &e);
|
||||
|
||||
e.data.u64 = LINUX_4ED_EVENT_STEP;
|
||||
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e);
|
||||
|
||||
|
@ -3321,10 +3097,6 @@ main(int argc, char **argv)
|
|||
XProcessInternalConnection(linuxvars.XDisplay, fd);
|
||||
} break;
|
||||
|
||||
case LINUX_4ED_EVENT_FILE: {
|
||||
LinuxHandleFileEvents();
|
||||
} break;
|
||||
|
||||
case LINUX_4ED_EVENT_STEP: {
|
||||
u64 ev;
|
||||
int ret;
|
||||
|
@ -3350,7 +3122,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if(do_step){
|
||||
linuxvars.last_step = system_now_time_stamp();
|
||||
linuxvars.last_step = system_now_time();
|
||||
|
||||
if(linuxvars.input.first_step || !linuxvars.has_xfixes){
|
||||
XConvertSelection(
|
||||
|
|
Loading…
Reference in New Issue