first version of file track system
This commit is contained in:
parent
74407bc0f6
commit
2c0b575f5c
|
@ -261,8 +261,8 @@ default_keys(Bind_Helper *context){
|
|||
|
||||
bind(context, '.', MDFR_ALT, change_to_build_panel);
|
||||
bind(context, ',', MDFR_ALT, close_build_panel);
|
||||
bind(context, 'n', MDFR_ALT, goto_next_error_no_skips);
|
||||
bind(context, 'N', MDFR_ALT, goto_prev_error_no_skips);
|
||||
bind(context, 'n', MDFR_ALT, goto_next_error);
|
||||
bind(context, 'N', MDFR_ALT, goto_prev_error);
|
||||
bind(context, 'M', MDFR_ALT, goto_first_error);
|
||||
bind(context, 'm', MDFR_ALT, build_search);
|
||||
|
||||
|
@ -397,10 +397,10 @@ default_keys(Bind_Helper *context){
|
|||
end_map(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef NO_BINDING
|
||||
|
||||
|
||||
|
||||
extern "C" int
|
||||
get_bindings(void *data, int size){
|
||||
Bind_Helper context_ = begin_bind_helper(data, size);
|
||||
|
|
|
@ -2516,7 +2516,7 @@ CUSTOM_COMMAND_SIG(word_complete){
|
|||
&complete_state.iter);
|
||||
|
||||
if (match.found_match){
|
||||
int match_size = match.end - match.start;
|
||||
match_size = match.end - match.start;
|
||||
Temp_Memory temp = begin_temp_memory(&global_part);
|
||||
char *spare = push_array(&global_part, char, match_size);
|
||||
|
||||
|
@ -2698,8 +2698,8 @@ SCROLL_RULE_SIG(smooth_scroll_rule){
|
|||
// If this hook is not implemented a default behavior of calling the
|
||||
// command is used. It is important to note that paste_next does not
|
||||
// work without this hook.
|
||||
// NOTE(allen|a4.0.10): As of this version the word_complete command also
|
||||
// relies on this particular command caller hook.
|
||||
// NOTE(allen|a4.0.10): As of this version the word_complete command
|
||||
// also relies on this particular command caller hook.
|
||||
COMMAND_CALLER_HOOK(default_command_caller){
|
||||
View_Summary view = app->get_active_view(app, AccessAll);
|
||||
|
||||
|
@ -2714,3 +2714,4 @@ COMMAND_CALLER_HOOK(default_command_caller){
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -374,7 +374,7 @@ query_user_general(Application_Links *app, Query_Bar *bar, int force_number){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(allen|a3.4.4): All we have to do to update the query bar is edit our
|
||||
// local Query_Bar struct! This is handy because it means our Query_Bar
|
||||
// is always correct for typical use without extra work updating the bar.
|
||||
|
@ -393,6 +393,8 @@ query_user_general(Application_Links *app, Query_Bar *bar, int force_number){
|
|||
}
|
||||
}
|
||||
|
||||
terminate_with_null(&bar->string);
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
|
|
|
@ -3295,7 +3295,7 @@ view_new_file(System_Functions *system, Models *models,
|
|||
file->settings.is_initialized = 1;
|
||||
|
||||
#if BUFFER_EXPERIMENT_SCALPEL <= 0
|
||||
if (file->settings.tokens_exist){
|
||||
if (file->settings.tokens_exist && file->state.token_stack.tokens == 0){
|
||||
file_first_lex_parallel(system, general, file);
|
||||
}
|
||||
#endif
|
||||
|
@ -3310,7 +3310,7 @@ init_normal_file(System_Functions *system, Models *models, Editing_File *file,
|
|||
String val = make_string(buffer, size);
|
||||
file_create_from_string(system, models, file, file->name.source_path.str, val);
|
||||
|
||||
if (file->settings.tokens_exist){
|
||||
if (file->settings.tokens_exist && file->state.token_stack.tokens == 0){
|
||||
file_first_lex_parallel(system, general, file);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
|
||||
Copy Right FourTech LLC, 2016
|
||||
All Rights Are Reserved
|
||||
|
||||
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: 20.07.2016
|
||||
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#ifndef FILE_TRACK_4TECH_H
|
||||
#define FILE_TRACK_4TECH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum{
|
||||
FileTrack_Good,
|
||||
FileTrack_MemoryTooSmall,
|
||||
FileTrack_OutOfTableMemory,
|
||||
FileTrack_OutOfListenerMemory,
|
||||
FileTrack_FileNotFound,
|
||||
FileTrack_FileAlreadyTracked,
|
||||
FileTrack_FileNotTracked,
|
||||
FileTrack_NoMoreEvents,
|
||||
FileTrack_FileSystemError
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
uint8_t opaque[128];
|
||||
} File_Track_System;
|
||||
|
||||
typedef struct{
|
||||
uint32_t id[4];
|
||||
} File_Index;
|
||||
|
||||
static File_Index
|
||||
zero_file_index(){
|
||||
File_Index a = {0};
|
||||
return(a);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
file_index_eq(File_Index a, File_Index b){
|
||||
return ((a.id[0] == b.id[0]) &&
|
||||
(a.id[1] == b.id[1]) &&
|
||||
(a.id[2] == b.id[2]) &&
|
||||
(a.id[3] == b.id[3]));
|
||||
}
|
||||
|
||||
typedef int32_t File_Track_Result;
|
||||
typedef uint64_t File_Time;
|
||||
|
||||
File_Track_Result
|
||||
init_track_system(File_Track_System *system,
|
||||
void *table_memory, int32_t table_memory_size,
|
||||
void *listener_memory, int32_t listener_memory_size);
|
||||
|
||||
File_Track_Result
|
||||
begin_tracking_file(File_Track_System *system, char *name, File_Index *index, File_Time *time);
|
||||
|
||||
File_Track_Result
|
||||
get_tracked_file_index(File_Track_System *system, char *name, File_Index *index);
|
||||
|
||||
File_Track_Result
|
||||
stop_tracking_file(File_Track_System *system, File_Index index);
|
||||
|
||||
File_Track_Result
|
||||
count_tracked_files(File_Track_System *system, int32_t *count);
|
||||
|
||||
File_Track_Result
|
||||
get_tracked_file_time(File_Track_System *system, File_Index index, File_Time *time);
|
||||
|
||||
File_Track_Result
|
||||
move_track_system(File_Track_System *system, void *mem, int32_t size);
|
||||
|
||||
File_Track_Result
|
||||
expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size);
|
||||
|
||||
File_Track_Result
|
||||
get_change_event(File_Track_System *system, File_Index *index);
|
||||
|
||||
File_Track_Result
|
||||
get_tracked_file_size(File_Track_System *system, File_Index index, uint32_t *size);
|
||||
|
||||
File_Track_Result
|
||||
get_tracked_file_data(File_Track_System *system, File_Index index, void *mem, uint32_t size);
|
||||
|
||||
File_Track_Result
|
||||
rewrite_tracked_file(File_Track_System *system, File_Index index,
|
||||
void *data, int32_t size, File_Time *time);
|
||||
|
||||
File_Track_Result
|
||||
shut_down_track_system(File_Track_System *system);
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
@echo off
|
||||
|
||||
set WARNINGOPS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX
|
||||
set WARNINGOPS=%WARNINGOPS% /GR- /EHa- /nologo /FC
|
||||
set WIN_LIBS=user32.lib winmm.lib gdi32.lib
|
||||
|
||||
pushd w:\filetrack\build
|
||||
cl %WARNINGOPS% ..\code\filetrack_test.c /Fefile_rewriter /Zi %*
|
||||
cl %WARNINGOPS% ..\code\filetrack_main.c /Fefiletrack /Zi %*
|
||||
popd
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
|
||||
Copy Right FourTech LLC, 2016
|
||||
All Rights Are Reserved
|
||||
|
||||
A test bed for a cross platform file tracking reliability layer.
|
||||
Developed for the use cases in 4coder, but I anticipate that this
|
||||
will be a general problem for me. - Allen Webster
|
||||
|
||||
Created on: 20.07.2016
|
||||
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#define FILE_TRACK_MAIN
|
||||
|
||||
#include "4tech_file_track.h"
|
||||
#include "4tech_file_track_win32.c"
|
||||
|
||||
#include "filetrack_test.c"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FILE_TRACK_TEST_DIR1 "w:/filetrack/data/"
|
||||
#define FILE_TRACK_TEST_DIR2 "w:/filetrack/data2/"
|
||||
|
||||
#define FAKE_TRACK_TEST_DIR "w:/filetrack/data1000/"
|
||||
|
||||
#define ALT_NAME_TEST_DIR1 "c:/work/filetrack/data/"
|
||||
#define ALT_NAME_TEST_DIR2 "c:/work/filetrack/data2/"
|
||||
|
||||
static char * test_files[] = {
|
||||
FILE_TRACK_TEST_DIR1"autotab.cpp",
|
||||
FILE_TRACK_TEST_DIR1"basic.cpp",
|
||||
FILE_TRACK_TEST_DIR1"basic.txt",
|
||||
FILE_TRACK_TEST_DIR1"cleanme.cpp",
|
||||
FILE_TRACK_TEST_DIR1"emptyfile.txt",
|
||||
FILE_TRACK_TEST_DIR1"lexer_test.cpp",
|
||||
FILE_TRACK_TEST_DIR1"lexer_test2.cpp",
|
||||
FILE_TRACK_TEST_DIR1"lexer_test3.cpp",
|
||||
FILE_TRACK_TEST_DIR1"saveas.txt",
|
||||
FILE_TRACK_TEST_DIR1"test_large.cpp",
|
||||
|
||||
FILE_TRACK_TEST_DIR2"autotab.cpp",
|
||||
FILE_TRACK_TEST_DIR2"basic.cpp",
|
||||
FILE_TRACK_TEST_DIR2"basic.txt",
|
||||
FILE_TRACK_TEST_DIR2"cleanme.cpp",
|
||||
FILE_TRACK_TEST_DIR2"emptyfile.txt",
|
||||
FILE_TRACK_TEST_DIR2"lexer_test.cpp",
|
||||
FILE_TRACK_TEST_DIR2"lexer_test2.cpp",
|
||||
FILE_TRACK_TEST_DIR2"lexer_test3.cpp",
|
||||
FILE_TRACK_TEST_DIR2"saveas.txt",
|
||||
FILE_TRACK_TEST_DIR2"test_large.cpp",
|
||||
};
|
||||
|
||||
static char * test_alt_files[] = {
|
||||
ALT_NAME_TEST_DIR1"autotab.cpp",
|
||||
ALT_NAME_TEST_DIR1"basic.cpp",
|
||||
ALT_NAME_TEST_DIR1"basic.txt",
|
||||
ALT_NAME_TEST_DIR1"cleanme.cpp",
|
||||
ALT_NAME_TEST_DIR1"emptyfile.txt",
|
||||
ALT_NAME_TEST_DIR1"lexer_test.cpp",
|
||||
ALT_NAME_TEST_DIR1"lexer_test2.cpp",
|
||||
ALT_NAME_TEST_DIR1"lexer_test3.cpp",
|
||||
ALT_NAME_TEST_DIR1"saveas.txt",
|
||||
ALT_NAME_TEST_DIR1"test_large.cpp",
|
||||
|
||||
ALT_NAME_TEST_DIR2"autotab.cpp",
|
||||
ALT_NAME_TEST_DIR2"basic.cpp",
|
||||
ALT_NAME_TEST_DIR2"basic.txt",
|
||||
ALT_NAME_TEST_DIR2"cleanme.cpp",
|
||||
ALT_NAME_TEST_DIR2"emptyfile.txt",
|
||||
ALT_NAME_TEST_DIR2"lexer_test.cpp",
|
||||
ALT_NAME_TEST_DIR2"lexer_test2.cpp",
|
||||
ALT_NAME_TEST_DIR2"lexer_test3.cpp",
|
||||
ALT_NAME_TEST_DIR2"saveas.txt",
|
||||
ALT_NAME_TEST_DIR2"test_large.cpp",
|
||||
};
|
||||
|
||||
static char * fake_files[] = {
|
||||
FAKE_TRACK_TEST_DIR"autotab.cpp",
|
||||
FAKE_TRACK_TEST_DIR"basic.cpp",
|
||||
FAKE_TRACK_TEST_DIR"basic.txt",
|
||||
FAKE_TRACK_TEST_DIR"cleanme.cpp",
|
||||
FAKE_TRACK_TEST_DIR"emptyfile.txt",
|
||||
FAKE_TRACK_TEST_DIR"lexer_test.cpp",
|
||||
FAKE_TRACK_TEST_DIR"lexer_test2.cpp",
|
||||
FAKE_TRACK_TEST_DIR"lexer_test3.cpp",
|
||||
FAKE_TRACK_TEST_DIR"saveas.txt",
|
||||
FAKE_TRACK_TEST_DIR"test_large.cpp",
|
||||
};
|
||||
|
||||
#define ArrayCount(a) ((sizeof(a))/(sizeof(*a)))
|
||||
|
||||
typedef struct{
|
||||
File_Index unique_file_index;
|
||||
File_Time time;
|
||||
} MyFileThing;
|
||||
|
||||
void test_body_A(int32_t size1, int32_t size2){
|
||||
void *mem1 = malloc(size1);
|
||||
void *mem2 = malloc(size2);
|
||||
memset(mem1, 0, size1);
|
||||
|
||||
File_Track_System track = {0};
|
||||
int32_t result = init_track_system(&track,
|
||||
mem1, size1,
|
||||
mem2, size2);
|
||||
assert(result == FileTrack_Good);
|
||||
|
||||
MyFileThing my_file_things[1000];
|
||||
memset(my_file_things, 0, sizeof(my_file_things));
|
||||
|
||||
// NOTE(allen): track in all the test files
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
char *filename = test_files[i];
|
||||
|
||||
File_Index new_file = zero_file_index();
|
||||
File_Time new_time = 0;
|
||||
int32_t result = begin_tracking_file(&track, filename, &new_file, &new_time);
|
||||
while (result != FileTrack_Good){
|
||||
|
||||
switch (result){
|
||||
case FileTrack_OutOfTableMemory:
|
||||
{
|
||||
int32_t new_mem_size = size1*2;
|
||||
void *new_mem = malloc(new_mem_size);
|
||||
|
||||
memset(new_mem, 0, new_mem_size);
|
||||
move_track_system(&track, new_mem, new_mem_size);
|
||||
|
||||
free(mem1);
|
||||
size1 = new_mem_size;
|
||||
mem1 = new_mem;
|
||||
}break;
|
||||
|
||||
case FileTrack_OutOfListenerMemory:
|
||||
{
|
||||
size2 *= 2;
|
||||
void *new_mem = malloc(size2);
|
||||
memset(new_mem, 0, size2);
|
||||
expand_track_system_listeners(&track, new_mem, size2);
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
Assert(result == FileTrack_Good);
|
||||
}break;
|
||||
}
|
||||
|
||||
result = begin_tracking_file(&track, filename, &new_file, &new_time);
|
||||
}
|
||||
|
||||
my_file_things[i].unique_file_index = new_file;
|
||||
my_file_things[i].time = new_time;
|
||||
}
|
||||
|
||||
// NOTE(allen): track in fake directories
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(fake_files);
|
||||
++i){
|
||||
File_Index new_file = zero_file_index();
|
||||
File_Time new_time = 0;
|
||||
|
||||
char *filename = fake_files[i];
|
||||
|
||||
int32_t result = begin_tracking_file(&track, filename, &new_file, &new_time);
|
||||
assert(result == FileTrack_FileNotFound);
|
||||
}
|
||||
|
||||
// NOTE(allen): track in already tracked files
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index new_file = zero_file_index();
|
||||
File_Time new_time = 0;
|
||||
|
||||
char *filename = test_files[i];
|
||||
|
||||
int32_t result = begin_tracking_file(&track, filename, &new_file, &new_time);
|
||||
assert(result == FileTrack_FileAlreadyTracked);
|
||||
}
|
||||
|
||||
// NOTE(allen): track in already tracked files via alt-names
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_alt_files);
|
||||
++i){
|
||||
File_Index new_file = zero_file_index();
|
||||
File_Time new_time = 0;
|
||||
|
||||
char *filename = test_alt_files[i];
|
||||
|
||||
int32_t result = begin_tracking_file(&track, filename, &new_file, &new_time);
|
||||
assert(result == FileTrack_FileAlreadyTracked);
|
||||
}
|
||||
|
||||
// NOTE(allen): each file is still up to date
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Time time = 0;
|
||||
File_Index index = my_file_things[i].unique_file_index;
|
||||
|
||||
get_tracked_file_time(&track, index, &time);
|
||||
|
||||
assert(time == my_file_things[i].time);
|
||||
}
|
||||
|
||||
// NOTE(allen): can still get index from file name
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index index = my_file_things[i].unique_file_index;
|
||||
|
||||
File_Index result_index1 = zero_file_index();
|
||||
char *filename1 = test_files[i];
|
||||
get_tracked_file_index(&track, filename1, &result_index1);
|
||||
|
||||
File_Index result_index2 = zero_file_index();
|
||||
char *filename2 = test_alt_files[i];
|
||||
get_tracked_file_index(&track, filename2, &result_index2);
|
||||
|
||||
assert(file_index_eq(result_index1, index));
|
||||
assert(file_index_eq(result_index2, index));
|
||||
}
|
||||
|
||||
// NOTE(allen): rewrite all of the files
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
char *filename = test_files[i];
|
||||
|
||||
test_rewrite_file_in_child_proc(filename);
|
||||
}
|
||||
|
||||
// NOTE(allen): each file is behind
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Time time = 0;
|
||||
File_Index index = my_file_things[i].unique_file_index;
|
||||
|
||||
get_tracked_file_time(&track, index, &time);
|
||||
|
||||
assert(my_file_things[i].time < time);
|
||||
}
|
||||
|
||||
// NOTE(allen): poll the tracking system for changed files
|
||||
for (;;){
|
||||
File_Index index = zero_file_index();
|
||||
File_Time time = 0;
|
||||
|
||||
int32_t result = get_change_event(&track, &index);
|
||||
|
||||
if (result == FileTrack_NoMoreEvents){
|
||||
break;
|
||||
}
|
||||
|
||||
result = get_tracked_file_time(&track, index, &time);
|
||||
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index my_index = my_file_things[i].unique_file_index;
|
||||
if (file_index_eq(my_index, index)){
|
||||
my_file_things[i].time = time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(allen): each file is still up to date (episode 2)
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Time time = 0;
|
||||
File_Index index = my_file_things[i].unique_file_index;
|
||||
|
||||
get_tracked_file_time(&track, index, &time);
|
||||
|
||||
assert(time == my_file_things[i].time);
|
||||
}
|
||||
|
||||
// NOTE(allen): rewrite each file myself
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index index = my_file_things[i].unique_file_index;
|
||||
File_Time time = test_rewrite_file(&track, index);
|
||||
|
||||
my_file_things[i].time = time;
|
||||
}
|
||||
|
||||
// NOTE(allen): check there are no changed file events
|
||||
{
|
||||
File_Index index = zero_file_index();
|
||||
|
||||
int32_t result = get_change_event(&track, &index);
|
||||
assert(result == FileTrack_NoMoreEvents);
|
||||
}
|
||||
|
||||
// NOTE(allen): rewrite half of the files twice
|
||||
int32_t mid_point = ArrayCount(test_files) / 2;
|
||||
for (int32_t i = 0;
|
||||
i < mid_point;
|
||||
++i){
|
||||
char *filename = test_files[i];
|
||||
|
||||
test_rewrite_file_in_child_proc(filename);
|
||||
}
|
||||
|
||||
for (int32_t i = 0;
|
||||
i < mid_point;
|
||||
++i){
|
||||
char *filename = test_files[i];
|
||||
|
||||
test_rewrite_file_in_child_proc(filename);
|
||||
}
|
||||
|
||||
// NOTE(allen): check number of events equals mid_point
|
||||
int32_t count = 0;
|
||||
for (;;){
|
||||
File_Index index = zero_file_index();
|
||||
File_Time time = 0;
|
||||
|
||||
int32_t result = get_change_event(&track, &index);
|
||||
|
||||
if (result == FileTrack_NoMoreEvents){
|
||||
break;
|
||||
}
|
||||
|
||||
result = get_tracked_file_time(&track, index, &time);
|
||||
|
||||
++count;
|
||||
|
||||
for (int32_t i = 0;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index my_index = my_file_things[i].unique_file_index;
|
||||
if (file_index_eq(my_index, index)){
|
||||
my_file_things[i].time = time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(count == mid_point);
|
||||
|
||||
// NOTE(allen): untrack half of the files
|
||||
for (int32_t i = 0;
|
||||
i < mid_point;
|
||||
++i){
|
||||
File_Index stop_file = my_file_things[i].unique_file_index;
|
||||
stop_tracking_file(&track, stop_file);
|
||||
}
|
||||
|
||||
// NOTE(allen): untrack the same files again
|
||||
for (int32_t i = 0;
|
||||
i < mid_point;
|
||||
++i){
|
||||
File_Index stop_file = my_file_things[i].unique_file_index;
|
||||
int32_t result = stop_tracking_file(&track, stop_file);
|
||||
assert(result == FileTrack_FileNotTracked);
|
||||
}
|
||||
|
||||
// NOTE(allen): make sure the number of remaining files is correct
|
||||
{
|
||||
int32_t track_count = 0;
|
||||
count_tracked_files(&track, &track_count);
|
||||
assert(track_count == (ArrayCount(test_files) - mid_point));
|
||||
}
|
||||
|
||||
// NOTE(allen): untrack the rest of the files
|
||||
for (int32_t i = mid_point;
|
||||
i < ArrayCount(test_files);
|
||||
++i){
|
||||
File_Index stop_file = my_file_things[i].unique_file_index;
|
||||
stop_tracking_file(&track, stop_file);
|
||||
}
|
||||
|
||||
// NOTE(allen): make sure the system is empty
|
||||
{
|
||||
int32_t track_count = 0;
|
||||
count_tracked_files(&track, &track_count);
|
||||
assert(track_count == 0);
|
||||
}
|
||||
|
||||
// NOTE(allen): finish using the track system
|
||||
{
|
||||
int32_t result = shut_down_track_system(&track);
|
||||
assert(result == FileTrack_Good);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(allen): test basic tracking logic
|
||||
void test_1(void){
|
||||
int32_t size1 = (16 << 10);
|
||||
int32_t size2 = (16 << 10);
|
||||
test_body_A(size1, size2);
|
||||
}
|
||||
|
||||
// NOTE(allen): test memory expansion system for tables
|
||||
void test_2(void){
|
||||
int32_t size1 = (1 << 10);
|
||||
int32_t size2 = (16 << 10);
|
||||
test_body_A(size1, size2);
|
||||
}
|
||||
|
||||
// NOTE(allen): test memory expansion system for listening nodes
|
||||
void test_3(void){
|
||||
int32_t size1 = (16 << 10);
|
||||
int32_t size2 = (5 << 10);
|
||||
test_body_A(size1, size2);
|
||||
}
|
||||
|
||||
// NOTE(allen): test both memory expansion systems
|
||||
void test_4(void){
|
||||
int32_t size1 = (1 << 10);
|
||||
int32_t size2 = (5 << 10);
|
||||
test_body_A(size1, size2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
test_4();
|
||||
return(0);
|
||||
}
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
|
||||
Copy Right FourTech LLC, 2016
|
||||
All Rights Are Reserved
|
||||
|
||||
Helpers for the filetrack_main.c test bed.
|
||||
|
||||
Created on: 20.07.2016
|
||||
|
||||
*/
|
||||
|
||||
// TOP
|
||||
|
||||
#define FILE_REWRITER "w:/filetrack/build/file_rewriter"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void
|
||||
rewrite(char *buffer, int32_t size){
|
||||
for (int32_t i = 0;
|
||||
i < size;
|
||||
++i){
|
||||
if (buffer[i] >= 'a' && buffer[i] < 'z'){
|
||||
++buffer[i];
|
||||
}
|
||||
else if (buffer[i] == 'z'){
|
||||
buffer[i] = 'a';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
append(char *buffer, int32_t *pos, char *src){
|
||||
int32_t i = *pos;
|
||||
src -= i;
|
||||
for (; src[i]; ++i){
|
||||
buffer[i] = src[i];
|
||||
}
|
||||
*pos = i;
|
||||
}
|
||||
|
||||
static void
|
||||
test_rewrite_file_in_child_proc(char *filename){
|
||||
char space[2048];
|
||||
int32_t pos = 0;
|
||||
|
||||
append(space, &pos, FILE_REWRITER" ");
|
||||
append(space, &pos, filename);
|
||||
space[pos] = 0;
|
||||
|
||||
int32_t result = system(space);
|
||||
assert(result == 0);
|
||||
}
|
||||
|
||||
#ifndef FILE_TRACK_MAIN
|
||||
|
||||
int
|
||||
main(int argc, char **argv){
|
||||
if (argc == 2){
|
||||
char *filename = argv[1];
|
||||
|
||||
char *mem = 0;
|
||||
int32_t size = 0;
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
assert(file);
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
mem = (char*)malloc(size+1);
|
||||
fread(mem, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
rewrite(mem, size);
|
||||
|
||||
file = fopen(filename, "wb");
|
||||
assert(file);
|
||||
fwrite(mem, 1, size, file);
|
||||
fclose(file);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static File_Time
|
||||
test_rewrite_file(File_Track_System *system, File_Index index){
|
||||
char *mem = 0;
|
||||
uint32_t size = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
result = get_tracked_file_size(system, index, &size);
|
||||
assert(result == FileTrack_Good);
|
||||
mem = (char*)malloc(size+1);
|
||||
result = get_tracked_file_data(system, index, mem, size);
|
||||
assert(result == FileTrack_Good);
|
||||
|
||||
rewrite(mem, size);
|
||||
|
||||
File_Time time = 0;
|
||||
rewrite_tracked_file(system, index, mem, size, &time);
|
||||
|
||||
free(mem);
|
||||
|
||||
return(time);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// BOTTOM
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
//
|
||||
|
||||
Theme_Color ThemeColors[] = {
|
||||
{Stag_Bar, 0x9a99e7},
|
||||
{Stag_Bar_Active, 0x9a99e7},
|
||||
{Stag_Margin, 0x606590},
|
||||
{Stag_Margin_Hover, 0x9a99e7},
|
||||
{Stag_Margin_Active, 0x9a99e7},
|
||||
{Stag_Comment, 0x505f89},
|
||||
{Stag_Keyword, 0xaa8da7},
|
||||
{Stag_Default, 0xffffff},
|
||||
{Stag_Cursor, 0xd96e26},
|
||||
{Stag_Int_Constant, 0x9a99e7},
|
||||
{Stag_Float_Constant, 0x9a99e7},
|
||||
{Stag_Bool_Constant, 0x9a99e7},
|
||||
{Stag_Str_Constant, 0x9a99e7},
|
||||
{Stag_Char_Constant, 0x9a99e7},
|
||||
{Stag_Preproc, 0x606590},
|
||||
{Stag_Include, 0x9a99e7},
|
||||
};
|
198
win32_4ed.cpp
198
win32_4ed.cpp
|
@ -352,202 +352,6 @@ system_signal_cv(i32 crit_id, i32 cv_id){
|
|||
WakeConditionVariable(win32vars.condition_vars + cv_id);
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal DWORD
|
||||
JobThreadProc(LPVOID lpParameter){
|
||||
Thread_Context *thread = (Thread_Context*)lpParameter;
|
||||
Work_Queue *queue = win32vars.queues + thread->group_id;
|
||||
Thread_Group *group = win32vars.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 = win32vars.thread_memory + thread_index;
|
||||
|
||||
if (thread_memory->size == 0){
|
||||
i32 new_size = Kbytes(64);
|
||||
thread_memory->data = Win32GetMemory(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){
|
||||
// NOTE(allen): Previously I was wrapping by the job wrap then
|
||||
// wrapping by the queue wrap. That was super stupid what was that?
|
||||
// Now it just wraps by the queue wrap.
|
||||
u32 next_read_index = (read_index + 1) % QUEUE_WRAP;
|
||||
u32 safe_read_index =
|
||||
InterlockedCompareExchange(&queue->read_position,
|
||||
next_read_index, 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 =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
thread->id, THREAD_NOT_ASSIGNED);
|
||||
|
||||
if (safe_running_thread == THREAD_NOT_ASSIGNED){
|
||||
thread->job_id = full_job->id;
|
||||
thread->running = 1;
|
||||
|
||||
full_job->job.callback(&win32vars.system,
|
||||
thread, thread_memory, full_job->job.data);
|
||||
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0);
|
||||
full_job->running_thread = 0;
|
||||
thread->running = 0;
|
||||
|
||||
system_acquire_lock(cancel_lock);
|
||||
if (thread->cancel){
|
||||
thread->cancel = 0;
|
||||
system_signal_cv(cancel_lock, cancel_cv);
|
||||
}
|
||||
system_release_lock(cancel_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
Work_Queue *queue = win32vars.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 =
|
||||
InterlockedCompareExchange(&queue->write_position,
|
||||
next_write_index, write_index);
|
||||
if (safe_write_index == write_index){
|
||||
result = write_index;
|
||||
queue->jobs[write_index].job = job;
|
||||
queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED;
|
||||
queue->jobs[write_index].id = result;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE(allen): New job cancelling system:
|
||||
//
|
||||
// Jobs are expected to periodically check their cancelation
|
||||
// state, especially if they are taking a while.
|
||||
//
|
||||
// When the main thread asks to cancel a job it sets the cancel
|
||||
// state and does not resume until the thread running the job
|
||||
// signals that it is okay.
|
||||
//
|
||||
// Don't hold the frame lock while sleeping, as this can dead-lock
|
||||
// the job thread and the main thread, and since main is sleeping
|
||||
// they won't collide anyway.
|
||||
internal
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
Work_Queue *queue = win32vars.queues + group_id;
|
||||
Thread_Group *group = win32vars.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 =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
0, THREAD_NOT_ASSIGNED);
|
||||
|
||||
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{
|
||||
system_wait_cv(cancel_lock, cancel_cv);
|
||||
}while (thread->cancel == 1);
|
||||
system_acquire_lock(FRAME_LOCK);
|
||||
|
||||
system_release_lock(cancel_lock);
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Check_Cancel_Sig(system_check_cancel){
|
||||
b32 result = 0;
|
||||
|
||||
Thread_Group *group = win32vars.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);
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
internal void
|
||||
INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){
|
||||
Work_Queue *queue = win32vars.queues + id;
|
||||
u32 write = queue->write_position;
|
||||
u32 read = queue->read_position;
|
||||
if (write < read) write += QUEUE_WRAP;
|
||||
*pending = (i32)(write - read);
|
||||
|
||||
Thread_Group *group = win32vars.groups + id;
|
||||
for (i32 i = 0; i < group->count; ++i){
|
||||
running[i] = (group->threads[i].running != 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
internal DWORD
|
||||
JobThreadProc(LPVOID lpParameter){
|
||||
Thread_Context *thread = (Thread_Context*)lpParameter;
|
||||
|
@ -854,8 +658,6 @@ INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Coroutines
|
||||
|
|
Loading…
Reference in New Issue