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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -72,17 +83,22 @@ init_track_system(File_Track_System *system,
 | 
			
		|||
        /*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,8 +106,9 @@ 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);
 | 
			
		||||
    File_Track_Tables *tables = to_tables(vars);
 | 
			
		||||
 | 
			
		||||
    // ACQUIRE LOCK (only keep this if either of the data structures is kept)
 | 
			
		||||
    pthread_mutex_lock(&vars->lock);
 | 
			
		||||
 | 
			
		||||
    // NOTE(allen):
 | 
			
		||||
    // Here do something to begin listening to changes to the file named filename.
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +119,41 @@ add_listener(File_Track_System *system, char *filename){
 | 
			
		|||
    // 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,15 +162,34 @@ 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);
 | 
			
		||||
    File_Track_Tables *tables = to_tables(vars);
 | 
			
		||||
    File_Track_Entry *entries = (File_Track_Entry*) to_ptr(tables, tables->file_table);
 | 
			
		||||
 | 
			
		||||
    // ACQUIRE LOCK
 | 
			
		||||
    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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +199,7 @@ 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);
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +209,9 @@ move_track_system(File_Track_System *system, void *mem, int32_t size){
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // RELEASE LOCK
 | 
			
		||||
    pthread_mutex_unlock(&vars->lock);
 | 
			
		||||
 | 
			
		||||
    LINUX_FN_DEBUG("size: %d, %d", size, result);
 | 
			
		||||
 | 
			
		||||
    return(result);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -149,14 +221,28 @@ 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,8 +251,9 @@ 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);
 | 
			
		||||
    File_Track_Tables *tables = to_tables(vars);
 | 
			
		||||
 | 
			
		||||
    // ACQUIRE LOCK
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +263,34 @@ get_change_event(File_Track_System *system, char *buffer, int32_t max, int32_t *
 | 
			
		|||
    // 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -186,25 +300,14 @@ 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;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        ssize_t read_result = read(fd, buffer, size);
 | 
			
		||||
        if(read_result == -1){
 | 
			
		||||
            if(errno != EINTR){
 | 
			
		||||
                perror("system_file_load_end");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
    if(fstat(fd, &st) == -1){
 | 
			
		||||
        perror("fstat");
 | 
			
		||||
    } else {
 | 
			
		||||
            size -= read_result;
 | 
			
		||||
            ptr  += read_result;
 | 
			
		||||
        result = st.st_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal
 | 
			
		||||
Sys_Load_File_Sig(system_load_file){
 | 
			
		||||
    
 | 
			
		||||
    int fd = *(int*)&handle;
 | 
			
		||||
    do {
 | 
			
		||||
        ssize_t n = read(fd, buffer, size);
 | 
			
		||||
        if(n == -1 && errno != EAGAIN){
 | 
			
		||||
            perror("read");
 | 
			
		||||
            break;
 | 
			
		||||
        } else {
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
Sys_Release_Lock_Sig(system_release_lock){
 | 
			
		||||
    pthread_mutex_unlock(linuxvars.locks + id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    sem_post(LinuxHandleToSem(queue->semaphore));
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
internal void
 | 
			
		||||
system_wait_cv(i32 lock_id, i32 cv_id){
 | 
			
		||||
    pthread_cond_wait(linuxvars.conds + cv_id, linuxvars.locks + lock_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_signal_cv(i32 lock_id, i32 cv_id){
 | 
			
		||||
    pthread_cond_signal(linuxvars.conds + cv_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
 | 
			
		||||
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
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -1608,16 +1390,22 @@ 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