linux file track stuff working afaict

master
insofaras 2016-08-30 02:45:36 +01:00
parent 0378546dd8
commit a0f3996e73
3 changed files with 293 additions and 417 deletions

View File

@ -1,4 +1,5 @@
CPP_FILES := $(wildcard *.cpp) $(wildcard **/*.cpp) CPP_FILES := $(wildcard *.cpp) $(wildcard **/*.cpp)
C_FILES := $(wildcard *.c) $(wildcard **/*.c)
H_FILES := $(wildcard *.h) $(wildcard **/*.h) H_FILES := $(wildcard *.h) $(wildcard **/*.h)
WARNINGS := -Wno-write-strings WARNINGS := -Wno-write-strings
PLAT_LINKS := -L/usr/local/lib -lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes -lfreetype -lfontconfig 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: FLAGS += -DFRED_INTERNAL=1 -DFRED_SUPER=1 -g -O0
debug: ../4ed_app.so ../4ed 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 $@ 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 $@ g++ $(WARNINGS) $(FLAGS) linux_4ed.cpp -iquoteforeign $(PLAT_LINKS) -o $@
clean: clean:

View File

@ -43,8 +43,16 @@ typedef struct {
// Right now the way the API works, it assumes that the user will // 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 // only ever add memory and never free it. If freeing becomes necessary
// on Linux the API can be extended to support that. // 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; } Linux_File_Track_Vars;
//static_assert(sizeof(Linux_File_Track_Vars) <= sizeof(File_Track_System));
typedef struct { typedef struct {
File_Index hash; File_Index hash;
// NOTE(allen): // NOTE(allen):
@ -54,8 +62,11 @@ typedef struct {
// would be fine. If it is used hash should be the first element // 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 // of this struct and it should be used to uniquely identify each
// entry because it is used as the key for the table. // entry because it is used as the key for the table.
char* filename;
} Linux_File_Track_Entry; } 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_vars(s) ((Linux_File_Track_Vars*)(s))
#define to_tables(v) ((File_Track_Tables*)(v->tables)) #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){ /*if listener memory is important check it's size here*/ 1){
// NOTE(allen): Initialize main data tables // NOTE(allen): Initialize main data tables
vars->tables = table_memory; vars->tables = (File_Track_Tables*) table_memory;
File_Track_Tables *tables = to_tables(vars); File_Track_Tables *tables = to_tables(vars);
init_table_memory(tables, table_memory_size); init_table_memory(tables, table_memory_size);
// NOTE(allen): vars->inotify = inotify_init1(IN_NONBLOCK);
// Here prepare the data structure and synchronization primatives
// in the vars struct. 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; result = FileTrack_Good;
} }
LINUX_FN_DEBUG("result: %d", result);
return(result); return(result);
} }
@ -90,8 +106,9 @@ FILE_TRACK_LINK File_Track_Result
add_listener(File_Track_System *system, char *filename){ add_listener(File_Track_System *system, char *filename){
File_Track_Result result = FileTrack_Good; File_Track_Result result = FileTrack_Good;
Linux_File_Track_Vars *vars = to_vars(system); 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): // NOTE(allen):
// Here do something to begin listening to changes to the file named filename. // 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 // treat them as two separate files so that if one of the listeners is removed
// the other on the same file keeps working. // 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); return(result);
} }
@ -111,15 +162,34 @@ FILE_TRACK_LINK File_Track_Result
remove_listener(File_Track_System *system, char *filename){ remove_listener(File_Track_System *system, char *filename){
File_Track_Result result = FileTrack_Good; File_Track_Result result = FileTrack_Good;
Linux_File_Track_Vars *vars = to_vars(system); 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): // NOTE(allen):
// Here do something to stop listening to changes to the file named filename. // 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 // 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. // 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); return(result);
} }
@ -129,7 +199,7 @@ move_track_system(File_Track_System *system, void *mem, int32_t size){
File_Track_Result result = FileTrack_Good; File_Track_Result result = FileTrack_Good;
Linux_File_Track_Vars *vars = to_vars(system); Linux_File_Track_Vars *vars = to_vars(system);
// ACQUIRE LOCK pthread_mutex_lock(&vars->lock);
{ {
File_Track_Tables *original_tables = to_tables(vars); 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); 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; File_Track_Result result = FileTrack_Good;
Linux_File_Track_Vars *vars = to_vars(system); 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 // NOTE(allen): If there is a data structure for the listeners
// this call adds more memory to that system. If this system // this call adds more memory to that system. If this system
// wants to free old memory the API does not currently support // wants to free old memory the API does not currently support
// that but it can. // 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); 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){ get_change_event(File_Track_System *system, char *buffer, int32_t max, int32_t *size){
File_Track_Result result = FileTrack_NoMoreEvents; File_Track_Result result = FileTrack_NoMoreEvents;
Linux_File_Track_Vars *vars = to_vars(system); 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 // NOTE(allen): If there are any new file changes report them
// by copying the name of the file to the buffer and returning // 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 // about that file. If there are no new changes the return
// FileTrack_NoMoreEvents. // 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); return(result);
} }
@ -186,25 +300,14 @@ shut_down_track_system(File_Track_System *system){
File_Track_Result result = FileTrack_Good; File_Track_Result result = FileTrack_Good;
Linux_File_Track_Vars *vars = to_vars(system); 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. // 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); return(result);
} }

View File

@ -69,8 +69,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/input.h> #include <linux/input.h>
#include "filetrack/4tech_file_track_linux.c"
#include "system_shared.h"
// //
// Linux macros // Linux macros
@ -105,6 +103,9 @@
#define InterlockedCompareExchange(dest, ex, comp) __sync_val_compare_and_swap((dest), (comp), (ex)) #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 // Linux structs / enums
// //
@ -120,11 +121,10 @@ struct Sys_Bubble : public Bubble{
enum { enum {
LINUX_4ED_EVENT_X11 = (UINT64_C(1) << 32), LINUX_4ED_EVENT_X11 = (UINT64_C(1) << 32),
LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(1) << 33), LINUX_4ED_EVENT_X11_INTERNAL = (UINT64_C(2) << 32),
LINUX_4ED_EVENT_FILE = (UINT64_C(1) << 34), LINUX_4ED_EVENT_STEP = (UINT64_C(3) << 32),
LINUX_4ED_EVENT_STEP = (UINT64_C(1) << 35), LINUX_4ED_EVENT_STEP_TIMER = (UINT64_C(4) << 32),
LINUX_4ED_EVENT_STEP_TIMER = (UINT64_C(1) << 36), LINUX_4ED_EVENT_CLI = (UINT64_C(5) << 32),
LINUX_4ED_EVENT_CLI = (UINT64_C(1) << 37),
}; };
struct Linux_Coroutine { 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"); static_assert(sizeof(Plat_Handle) >= sizeof(int), "Plat_Handle not big enough");
// //
// Linux shared/system functions // Shared system functions (system_shared.h)
//
//
// Memory
// //
internal void* internal void*
@ -341,9 +337,6 @@ Sys_Free_Memory_Sig(system_free_memory){
LinuxFreeMemory(block); LinuxFreeMemory(block);
} }
//
// File
//
internal internal
Sys_File_Can_Be_Made_Sig(system_file_can_be_made){ 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 internal
Sys_Set_File_List_Sig(system_set_file_list){ Sys_Set_File_List_Sig(system_set_file_list){
DIR *d; DIR *d;
@ -503,105 +460,88 @@ Sys_Set_File_List_Sig(system_set_file_list){
} }
internal internal
Sys_File_Unique_Hash_Sig(system_file_unique_hash){ Sys_Get_Canonical_Sig(system_get_canonical){
Unique_Hash result = {}; int32_t result = 0;
struct stat st = {};
*success = 0;
if(stat(filename.str, &st) == 0){ char* path = realpath(strndupa(filename, len), NULL);
memcpy(&result, &st.st_dev, sizeof(st.st_dev)); if(!path){
memcpy((char*)&result + sizeof(st.st_dev), &st.st_ino, sizeof(st.st_ino)); perror("realpath");
*success = 1; } 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; return result;
} }
internal internal
Sys_File_Track_Sig(system_file_track){ Sys_Load_Handle_Sig(system_load_handle){
if(filename.size <= 0 || !filename.str) return; b32 result = 0;
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);
int fd = open(filename, O_RDONLY); int fd = open(filename, O_RDONLY);
if(fd < 0){ if(fd == -1){
fprintf(stderr, "sys_open_file: open '%s': %s\n", filename, strerror(errno)); perror("open");
goto out; } else {
} *(int*)handle_out = fd;
if(fstat(fd, &info) < 0){ result = 1;
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;
} }
loading.handle = LinuxFDToHandle(fd); return result;
loading.size = info.st_size;
loading.exists = 1;
out:
if(fd != -1 && !loading.exists) close(fd);
return(loading);
} }
internal internal
Sys_File_Load_End_Sig(system_file_load_end){ Sys_Load_Size_Sig(system_load_size){
int fd = LinuxHandleToFD(loading.handle); u32 result = 0;
char* ptr = buffer;
size_t size = loading.size;
if(!loading.exists || fd == -1) return 0; int fd = *(int*)&handle;
struct stat st;
do { if(fstat(fd, &st) == -1){
ssize_t read_result = read(fd, buffer, size); perror("fstat");
if(read_result == -1){
if(errno != EINTR){
perror("system_file_load_end");
break;
}
} else { } else {
size -= read_result; result = st.st_size;
ptr += read_result; }
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); } while(size);
close(fd); return size == 0;
LINUX_FN_DEBUG("success == %d", (size == 0));
return (size == 0);
} }
internal 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; b32 result = 0;
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 00640); 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 internal
@ -692,10 +649,6 @@ MEMORY_FREE_SIG(system_memory_free){
munmap(mem, size); munmap(mem, size);
} }
//
// Filesystem navigation
//
internal internal
FILE_EXISTS_SIG(system_file_exists){ FILE_EXISTS_SIG(system_file_exists){
int result = 0; int result = 0;
@ -983,175 +936,26 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
// Threads // Threads
// //
//#define OLD_JOB_QUEUE internal
Sys_Acquire_Lock_Sig(system_acquire_lock){
#ifdef OLD_JOB_QUEUE pthread_mutex_lock(linuxvars.locks + id);
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 internal
Sys_Post_Job_Sig(system_post_job){ Sys_Release_Lock_Sig(system_release_lock){
Work_Queue *queue = linuxvars.queues + group_id; pthread_mutex_unlock(linuxvars.locks + 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)); internal void
system_wait_cv(i32 lock_id, i32 cv_id){
return result; pthread_cond_wait(linuxvars.conds + cv_id, linuxvars.locks + lock_id);
} }
internal internal void
Sys_Cancel_Job_Sig(system_cancel_job){ system_signal_cv(i32 lock_id, i32 cv_id){
Work_Queue *queue = linuxvars.queues + group_id; pthread_cond_signal(linuxvars.conds + cv_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
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* internal void*
JobThreadProc(void* lpParameter){ JobThreadProc(void* lpParameter){
Thread_Context *thread = (Thread_Context*)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); 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 // Debug
// //
@ -1608,16 +1390,22 @@ LinuxLoadAppCode(String* base_dir){
internal void internal void
LinuxLoadSystemCode(){ LinuxLoadSystemCode(){
linuxvars.system.file_time_stamp = system_file_time_stamp; // files
linuxvars.system.now_time_stamp = system_now_time_stamp;
linuxvars.system.set_file_list = system_set_file_list; linuxvars.system.set_file_list = system_set_file_list;
linuxvars.system.file_unique_hash = system_file_unique_hash; linuxvars.system.get_canonical = system_get_canonical;
linuxvars.system.file_track = system_file_track; linuxvars.system.add_listener = system_add_listener;
linuxvars.system.file_untrack = system_file_untrack; linuxvars.system.remove_listener = system_remove_listener;
linuxvars.system.file_load_begin = system_file_load_begin; linuxvars.system.get_file_change = system_get_file_change;
linuxvars.system.file_load_end = system_file_load_end; linuxvars.system.load_handle = system_load_handle;
linuxvars.system.file_save = system_file_save; 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_allocate = system_memory_allocate;
linuxvars.system.memory_set_protection = system_memory_set_protection; linuxvars.system.memory_set_protection = system_memory_set_protection;
linuxvars.system.memory_free = system_memory_free; linuxvars.system.memory_free = system_memory_free;
@ -1626,18 +1414,22 @@ LinuxLoadSystemCode(){
linuxvars.system.get_4ed_path = system_get_4ed_path; linuxvars.system.get_4ed_path = system_get_4ed_path;
linuxvars.system.show_mouse_cursor = system_show_mouse_cursor; linuxvars.system.show_mouse_cursor = system_show_mouse_cursor;
// clipboard
linuxvars.system.post_clipboard = system_post_clipboard; linuxvars.system.post_clipboard = system_post_clipboard;
// coroutine
linuxvars.system.create_coroutine = system_create_coroutine; linuxvars.system.create_coroutine = system_create_coroutine;
linuxvars.system.launch_coroutine = system_launch_coroutine; linuxvars.system.launch_coroutine = system_launch_coroutine;
linuxvars.system.resume_coroutine = system_resume_coroutine; linuxvars.system.resume_coroutine = system_resume_coroutine;
linuxvars.system.yield_coroutine = system_yield_coroutine; linuxvars.system.yield_coroutine = system_yield_coroutine;
// cli
linuxvars.system.cli_call = system_cli_call; linuxvars.system.cli_call = system_cli_call;
linuxvars.system.cli_begin_update = system_cli_begin_update; linuxvars.system.cli_begin_update = system_cli_begin_update;
linuxvars.system.cli_update_step = system_cli_update_step; linuxvars.system.cli_update_step = system_cli_update_step;
linuxvars.system.cli_end_update = system_cli_end_update; linuxvars.system.cli_end_update = system_cli_end_update;
// threads
linuxvars.system.post_job = system_post_job; linuxvars.system.post_job = system_post_job;
linuxvars.system.cancel_job = system_cancel_job; linuxvars.system.cancel_job = system_cancel_job;
linuxvars.system.check_cancel = system_check_cancel; linuxvars.system.check_cancel = system_check_cancel;
@ -1645,12 +1437,14 @@ LinuxLoadSystemCode(){
linuxvars.system.acquire_lock = system_acquire_lock; linuxvars.system.acquire_lock = system_acquire_lock;
linuxvars.system.release_lock = system_release_lock; linuxvars.system.release_lock = system_release_lock;
// debug
#if FRED_INTERNAL #if FRED_INTERNAL
linuxvars.system.internal_sentinel = internal_sentinel; linuxvars.system.internal_sentinel = internal_sentinel;
linuxvars.system.internal_get_thread_states = internal_get_thread_states; linuxvars.system.internal_get_thread_states = internal_get_thread_states;
linuxvars.system.internal_debug_message = internal_debug_message; linuxvars.system.internal_debug_message = internal_debug_message;
#endif #endif
// non-function details
linuxvars.system.slash = '/'; linuxvars.system.slash = '/';
} }
@ -2226,7 +2020,7 @@ LinuxStringDup(String* str, void* data, size_t size){
internal void internal void
LinuxScheduleStep(void) LinuxScheduleStep(void)
{ {
u64 now = system_now_time_stamp(); u64 now = system_now_time();
u64 diff = (now - linuxvars.last_step); u64 diff = (now - linuxvars.last_step);
if(diff > (u64)frame_useconds){ 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 // Entry point
// //
@ -2979,7 +2756,9 @@ main(int argc, char **argv)
memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size); memory_vars.user_memory = system_get_memory(memory_vars.user_memory_size);
linuxvars.target.max = Mbytes(1); 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 // Read command line
@ -3248,9 +3027,6 @@ main(int argc, char **argv)
e.data.u64 = LINUX_4ED_EVENT_X11; e.data.u64 = LINUX_4ED_EVENT_X11;
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.x11_fd, &e); 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; e.data.u64 = LINUX_4ED_EVENT_STEP;
epoll_ctl(linuxvars.epoll, EPOLL_CTL_ADD, linuxvars.step_event_fd, &e); 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); XProcessInternalConnection(linuxvars.XDisplay, fd);
} break; } break;
case LINUX_4ED_EVENT_FILE: {
LinuxHandleFileEvents();
} break;
case LINUX_4ED_EVENT_STEP: { case LINUX_4ED_EVENT_STEP: {
u64 ev; u64 ev;
int ret; int ret;
@ -3350,7 +3122,7 @@ main(int argc, char **argv)
} }
if(do_step){ if(do_step){
linuxvars.last_step = system_now_time_stamp(); linuxvars.last_step = system_now_time();
if(linuxvars.input.first_step || !linuxvars.has_xfixes){ if(linuxvars.input.first_step || !linuxvars.has_xfixes){
XConvertSelection( XConvertSelection(