linux file loading / saving working (with questionable threading)
parent
654e2ab8e1
commit
c1b0521e81
334
linux_4ed.cpp
334
linux_4ed.cpp
|
@ -57,6 +57,32 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
struct Linux_Semaphore {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
struct Linux_Semaphore_Handle {
|
||||
pthread_mutex_t *mutex_p;
|
||||
pthread_cond_t *cond_p;
|
||||
};
|
||||
|
||||
struct Thread_Context{
|
||||
u32 job_id;
|
||||
b32 running;
|
||||
|
||||
Work_Queue *queue;
|
||||
u32 id;
|
||||
pthread_t handle;
|
||||
};
|
||||
|
||||
struct Thread_Group{
|
||||
Thread_Context *threads;
|
||||
i32 count;
|
||||
};
|
||||
|
||||
struct Linux_Vars{
|
||||
Display *XDisplay;
|
||||
|
@ -80,6 +106,11 @@ struct Linux_Vars{
|
|||
void *app_code;
|
||||
void *custom;
|
||||
|
||||
Thread_Memory *thread_memory;
|
||||
Thread_Group groups[THREAD_GROUP_COUNT];
|
||||
Linux_Semaphore thread_locks[THREAD_GROUP_COUNT];
|
||||
Linux_Semaphore locks[LOCK_COUNT];
|
||||
|
||||
Plat_Settings settings;
|
||||
System_Functions *system;
|
||||
App_Functions app;
|
||||
|
@ -99,6 +130,8 @@ struct Linux_Vars{
|
|||
#define FPS 60
|
||||
#define frame_useconds (1000000 / FPS)
|
||||
|
||||
#define DBG_FN do { fprintf(stderr, "Fn called: %s\n", __PRETTY_FUNCTION__); } while(0)
|
||||
|
||||
globalvar Linux_Vars linuxvars;
|
||||
globalvar Application_Memory memory_vars;
|
||||
globalvar Exchange exchange_vars;
|
||||
|
@ -328,6 +361,7 @@ Sys_Post_Clipboard_Sig(system_post_clipboard){
|
|||
|
||||
Sys_CLI_Call_Sig(system_cli_call){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(path);
|
||||
AllowLocal(script_name);
|
||||
AllowLocal(cli_out);
|
||||
|
@ -335,11 +369,13 @@ Sys_CLI_Call_Sig(system_cli_call){
|
|||
|
||||
Sys_CLI_Begin_Update_Sig(system_cli_begin_update){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(cli);
|
||||
}
|
||||
|
||||
Sys_CLI_Update_Step_Sig(system_cli_update_step){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(cli);
|
||||
AllowLocal(dest);
|
||||
AllowLocal(max);
|
||||
|
@ -348,31 +384,156 @@ Sys_CLI_Update_Step_Sig(system_cli_update_step){
|
|||
|
||||
Sys_CLI_End_Update_Sig(system_cli_end_update){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(cli);
|
||||
}
|
||||
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
// TODO(allen): Implement
|
||||
AllowLocal(group_id);
|
||||
AllowLocal(job);
|
||||
static_assert(sizeof(Plat_Handle) >= sizeof(Linux_Semaphore_Handle), "Plat_Handle not big enough");
|
||||
|
||||
internal Plat_Handle
|
||||
LinuxSemToHandle(Linux_Semaphore* sem){
|
||||
Linux_Semaphore_Handle h = { &sem->mutex, &sem->cond };
|
||||
return *(Plat_Handle*)&h;
|
||||
}
|
||||
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
internal void*
|
||||
ThreadProc(void* arg){
|
||||
Thread_Context *thread = (Thread_Context*)arg;
|
||||
Work_Queue *queue = thread->queue;
|
||||
|
||||
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) % JOB_ID_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 % QUEUE_WRAP);
|
||||
// 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;
|
||||
Thread_Memory *thread_memory = 0;
|
||||
|
||||
// TODO(allen): remove memory_request
|
||||
if (full_job->job.memory_request != 0){
|
||||
thread_memory = linuxvars.thread_memory + thread->id - 1;
|
||||
if (thread_memory->size < full_job->job.memory_request){
|
||||
if (thread_memory->data){
|
||||
LinuxFreeMemory(thread_memory->data);
|
||||
}
|
||||
i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4));
|
||||
thread_memory->data = LinuxGetMemory(new_size);
|
||||
thread_memory->size = new_size;
|
||||
}
|
||||
}
|
||||
full_job->job.callback(linuxvars.system, thread, thread_memory,
|
||||
&exchange_vars.thread, full_job->job.data);
|
||||
full_job->running_thread = 0;
|
||||
thread->running = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
Linux_Semaphore_Handle* h = (Linux_Semaphore_Handle*)&(queue->semaphore);
|
||||
pthread_cond_wait(h->cond_p, h->mutex_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(group_id);
|
||||
AllowLocal(job_id);
|
||||
AllowLocal(job);
|
||||
|
||||
Work_Queue *queue = exchange_vars.thread.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) % JOB_ID_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;
|
||||
}
|
||||
}
|
||||
|
||||
Linux_Semaphore_Handle* h = (Linux_Semaphore_Handle*)&(queue->semaphore);
|
||||
pthread_cond_broadcast(h->cond_p);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||
// TODO(allen): Implement
|
||||
AllowLocal(id);
|
||||
// printf("%s: id: %d\n", __PRETTY_FUNCTION__, id);
|
||||
pthread_mutex_lock(&linuxvars.locks[id].mutex);
|
||||
//pthread_cond_wait(&linuxvars.locks[id].cond, &linuxvars.locks[id].mutex);
|
||||
pthread_mutex_unlock(&linuxvars.locks[id].mutex);
|
||||
}
|
||||
|
||||
Sys_Release_Lock_Sig(system_release_lock){
|
||||
// TODO(allen): Implement
|
||||
AllowLocal(id);
|
||||
//printf("%s: id: %d\n", __PRETTY_FUNCTION__, id);
|
||||
pthread_mutex_lock(&linuxvars.locks[id].mutex);
|
||||
pthread_cond_broadcast(&linuxvars.locks[id].cond);
|
||||
pthread_mutex_unlock(&linuxvars.locks[id].mutex);
|
||||
}
|
||||
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
DBG_FN;
|
||||
AllowLocal(group_id);
|
||||
AllowLocal(job_id);
|
||||
|
||||
Work_Queue *queue = exchange_vars.thread.queues + group_id;
|
||||
Thread_Group *group = linuxvars.groups + group_id;
|
||||
|
||||
u32 job_index;
|
||||
u32 thread_id;
|
||||
Full_Job_Data *full_job;
|
||||
Thread_Context *thread;
|
||||
|
||||
job_index = job_id % QUEUE_WRAP;
|
||||
full_job = queue->jobs + job_index;
|
||||
|
||||
Assert(full_job->id == job_id);
|
||||
thread_id =
|
||||
__sync_val_compare_and_swap(&full_job->running_thread,
|
||||
THREAD_NOT_ASSIGNED, 0);
|
||||
|
||||
if (thread_id != THREAD_NOT_ASSIGNED){
|
||||
system_acquire_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread = group->threads + thread_id - 1;
|
||||
pthread_kill(thread->handle, SIGINT); //NOTE(inso) SIGKILL if you really want it to die.
|
||||
pthread_create(&thread->handle, NULL, &ThreadProc, thread);
|
||||
system_release_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread->running = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Sys_Grow_Thread_Memory_Sig(system_grow_thread_memory){
|
||||
void *old_data;
|
||||
i32 old_size, new_size;
|
||||
|
@ -402,6 +563,7 @@ INTERNAL_Sys_Sentinel_Sig(internal_sentinel){
|
|||
|
||||
INTERNAL_Sys_Get_Thread_States_Sig(internal_get_thread_states){
|
||||
// TODO(allen): Implement
|
||||
DBG_FN;
|
||||
AllowLocal(id);
|
||||
AllowLocal(running);
|
||||
AllowLocal(pending);
|
||||
|
@ -502,10 +664,44 @@ out:
|
|||
internal
|
||||
Sys_Save_File_Sig(system_save_file){
|
||||
b32 result = 0;
|
||||
// TODO(allen): Implement
|
||||
AllowLocal(filename);
|
||||
AllowLocal(data);
|
||||
AllowLocal(size);
|
||||
DBG_FN;
|
||||
|
||||
const size_t save_fsz = strlen(filename);
|
||||
const char tmp_end[] = ".4ed.XXXXXX";
|
||||
char* tmp_fname = (char*) alloca(save_fsz + sizeof(tmp_end));
|
||||
|
||||
memcpy(tmp_fname, filename, save_fsz);
|
||||
memcpy(tmp_fname + save_fsz, tmp_end, sizeof(tmp_end));
|
||||
|
||||
int tmp_fd = mkstemp(tmp_fname);
|
||||
if(tmp_fd == -1){
|
||||
perror("system_save_file: mkstemp");
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t remaining = size;
|
||||
do {
|
||||
ssize_t written = write(tmp_fd, data, size);
|
||||
if(written == -1){
|
||||
if(errno == EINTR){
|
||||
continue;
|
||||
} else {
|
||||
perror("system_save_file: write");
|
||||
unlink(tmp_fname);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
remaining -= written;
|
||||
}
|
||||
} while(remaining);
|
||||
|
||||
if(rename(tmp_fname, filename) == -1){
|
||||
perror("system_save_file: rename");
|
||||
unlink(tmp_fname);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = 1;
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
@ -1060,7 +1256,8 @@ InitializeXInput(Display *dpy, Window XWindow)
|
|||
PointerMotionMask |
|
||||
FocusChangeMask |
|
||||
StructureNotifyMask |
|
||||
MappingNotify
|
||||
MappingNotify |
|
||||
ExposureMask
|
||||
);
|
||||
|
||||
result.input_method = XOpenIM(dpy, 0, 0, 0);
|
||||
|
@ -1231,6 +1428,37 @@ main(int argc, char **argv)
|
|||
|
||||
// TODO(allen): Setup background threads and locks
|
||||
|
||||
Thread_Context background[4] = {};
|
||||
linuxvars.groups[BACKGROUND_THREADS].threads = background;
|
||||
linuxvars.groups[BACKGROUND_THREADS].count = ArrayCount(background);
|
||||
|
||||
Thread_Memory thread_memory[ArrayCount(background)];
|
||||
linuxvars.thread_memory = thread_memory;
|
||||
|
||||
pthread_mutex_init(&linuxvars.thread_locks[BACKGROUND_THREADS].mutex, NULL);
|
||||
pthread_cond_init(&linuxvars.thread_locks[BACKGROUND_THREADS].cond, NULL);
|
||||
|
||||
exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore =
|
||||
LinuxSemToHandle(&linuxvars.thread_locks[BACKGROUND_THREADS]);
|
||||
|
||||
for(i32 i = 0; i < linuxvars.groups[BACKGROUND_THREADS].count; ++i){
|
||||
Thread_Context *thread = linuxvars.groups[BACKGROUND_THREADS].threads + i;
|
||||
thread->id = i + 1;
|
||||
|
||||
Thread_Memory *memory = linuxvars.thread_memory + i;
|
||||
*memory = {};
|
||||
memory->id = thread->id;
|
||||
|
||||
thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS];
|
||||
pthread_create(&thread->handle, NULL, &ThreadProc, thread);
|
||||
}
|
||||
|
||||
Assert(linuxvars.locks);
|
||||
for(i32 i = 0; i < LOCK_COUNT; ++i){
|
||||
pthread_mutex_init(&linuxvars.locks[i].mutex, NULL);
|
||||
pthread_cond_init(&linuxvars.locks[i].cond, NULL);
|
||||
}
|
||||
|
||||
LinuxLoadRenderCode();
|
||||
linuxvars.target.max = Mbytes(1);
|
||||
linuxvars.target.push_buffer = (byte*)system_get_memory(linuxvars.target.max);
|
||||
|
@ -1400,17 +1628,11 @@ main(int argc, char **argv)
|
|||
push_key(0, 0, 0, &mods, is_hold);
|
||||
}
|
||||
}
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case KeyRelease: {
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case MotionNotify: {
|
||||
linuxvars.mouse_data.x = Event.xmotion.x;
|
||||
linuxvars.mouse_data.y = Event.xmotion.y;
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case ButtonPress: {
|
||||
|
@ -1424,7 +1646,6 @@ main(int argc, char **argv)
|
|||
linuxvars.mouse_data.right_button = 1;
|
||||
} break;
|
||||
}
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case ButtonRelease: {
|
||||
|
@ -1438,24 +1659,20 @@ main(int argc, char **argv)
|
|||
linuxvars.mouse_data.right_button = 0;
|
||||
} break;
|
||||
}
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case EnterNotify: {
|
||||
linuxvars.mouse_data.out_of_window = 0;
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case LeaveNotify: {
|
||||
linuxvars.mouse_data.out_of_window = 1;
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case FocusIn:
|
||||
case FocusOut: {
|
||||
linuxvars.mouse_data.left_button = 0;
|
||||
linuxvars.mouse_data.right_button = 0;
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
|
||||
case ConfigureNotify: {
|
||||
|
@ -1559,6 +1776,10 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
case Expose: {
|
||||
linuxvars.redraw = 1;
|
||||
}break;
|
||||
}
|
||||
|
||||
PrevEvent = Event;
|
||||
|
@ -1582,6 +1803,11 @@ main(int argc, char **argv)
|
|||
mouse = linuxvars.mouse_data;
|
||||
|
||||
result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT;
|
||||
|
||||
if(__sync_bool_compare_and_swap(&exchange_vars.thread.force_redraw, 1, 0)){
|
||||
linuxvars.redraw = 1;
|
||||
}
|
||||
|
||||
result.redraw = linuxvars.redraw;
|
||||
result.lctrl_lalt_is_altgr = 0;
|
||||
|
||||
|
@ -1613,6 +1839,62 @@ main(int argc, char **argv)
|
|||
linuxvars.mouse_data.left_button_released = 0;
|
||||
linuxvars.mouse_data.right_button_pressed = 0;
|
||||
linuxvars.mouse_data.right_button_released = 0;
|
||||
|
||||
ProfileStart(OS_file_process);
|
||||
{
|
||||
File_Slot *file;
|
||||
int d = 0;
|
||||
|
||||
for (file = exchange_vars.file.active.next;
|
||||
file != &exchange_vars.file.active;
|
||||
file = file->next){
|
||||
++d;
|
||||
|
||||
if (file->flags & FEx_Save){
|
||||
Assert((file->flags & FEx_Request) == 0);
|
||||
file->flags &= (~FEx_Save);
|
||||
if (system_save_file(file->filename, (char*)file->data, file->size)){
|
||||
file->flags |= FEx_Save_Complete;
|
||||
}
|
||||
else{
|
||||
file->flags |= FEx_Save_Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->flags & FEx_Request){
|
||||
Assert((file->flags & FEx_Save) == 0);
|
||||
file->flags &= (~FEx_Request);
|
||||
Data sysfile =
|
||||
system_load_file(file->filename);
|
||||
if (sysfile.data == 0){
|
||||
file->flags |= FEx_Not_Exist;
|
||||
}
|
||||
else{
|
||||
file->flags |= FEx_Ready;
|
||||
file->data = sysfile.data;
|
||||
file->size = sysfile.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert(d == exchange_vars.file.num_active);
|
||||
|
||||
for (file = exchange_vars.file.free_list.next;
|
||||
file != &exchange_vars.file.free_list;
|
||||
file = file->next){
|
||||
if (file->data){
|
||||
system_free_memory(file->data);
|
||||
}
|
||||
}
|
||||
|
||||
if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){
|
||||
ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev,
|
||||
&exchange_vars.file.available);
|
||||
}
|
||||
|
||||
ex__check(&exchange_vars.file);
|
||||
}
|
||||
ProfileEnd(OS_file_process);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue