command outputs; ipc command output reception & writing to stdout

This commit is contained in:
Ryan Fleury
2025-06-05 16:08:53 -07:00
parent 3d7bfb41b8
commit c282e7d4be
7 changed files with 164 additions and 69 deletions
+134 -64
View File
@@ -295,9 +295,12 @@ struct IPCInfo
//- rjf: IPC resources
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4)
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
global OS_Handle ipc_signal_semaphore = {0};
global OS_Handle ipc_lock_semaphore = {0};
global U8 *ipc_shared_memory_base = 0;
global OS_Handle ipc_sender2main_signal_semaphore = {0};
global OS_Handle ipc_sender2main_lock_semaphore = {0};
global U8 *ipc_sender2main_shared_memory_base = 0;
global OS_Handle ipc_main2sender_signal_semaphore = {0};
global OS_Handle ipc_main2sender_lock_semaphore = {0};
global U8 *ipc_main2sender_shared_memory_base = 0;
global U8 ipc_s2m_ring_buffer[MB(4)] = {0};
global U64 ipc_s2m_ring_write_pos = 0;
global U64 ipc_s2m_ring_read_pos = 0;
@@ -313,11 +316,11 @@ ipc_signaler_thread__entry_point(void *p)
ThreadNameF("[rd] ipc signaler thread");
for(;;)
{
if(os_semaphore_take(ipc_signal_semaphore, max_U64))
if(os_semaphore_take(ipc_sender2main_signal_semaphore, max_U64))
{
if(os_semaphore_take(ipc_lock_semaphore, max_U64))
if(os_semaphore_take(ipc_sender2main_lock_semaphore, max_U64))
{
IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base;
IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base;
String8 msg = str8((U8 *)(ipc_info+1), ipc_info->msg_size);
msg.size = Min(msg.size, IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo));
OS_MutexScope(ipc_s2m_ring_mutex) for(;;)
@@ -335,7 +338,7 @@ ipc_signaler_thread__entry_point(void *p)
os_condition_variable_broadcast(ipc_s2m_ring_cv);
os_send_wakeup_event();
ipc_info->msg_size = 0;
os_semaphore_drop(ipc_lock_semaphore);
os_semaphore_drop(ipc_sender2main_lock_semaphore);
}
}
}
@@ -367,42 +370,6 @@ entry_point(CmdLine *cmd_line)
{
Temp scratch = scratch_begin(0, 0);
//- rjf: windows -> turn off output handles, as we need to control those for target processes
#if OS_WINDOWS
HANDLE output_handles[3] =
{
GetStdHandle(STD_INPUT_HANDLE),
GetStdHandle(STD_OUTPUT_HANDLE),
GetStdHandle(STD_ERROR_HANDLE),
};
for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1)
{
B32 duplicate = 0;
for(U64 idx2 = 0; idx2 < idx; idx2 += 1)
{
if(output_handles[idx2] == output_handles[idx])
{
duplicate = 1;
break;
}
}
if(duplicate)
{
output_handles[idx] = 0;
}
}
for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1)
{
if(output_handles[idx] != 0)
{
CloseHandle(output_handles[idx]);
}
}
SetStdHandle(STD_INPUT_HANDLE, 0);
SetStdHandle(STD_OUTPUT_HANDLE, 0);
SetStdHandle(STD_ERROR_HANDLE, 0);
#endif
//- rjf: unpack command line arguments
ExecMode exec_mode = ExecMode_Normal;
B32 auto_run = 0;
@@ -446,6 +413,42 @@ entry_point(CmdLine *cmd_line)
default:
case ExecMode_Normal:
{
//- rjf: windows -> turn off output handles, as we need to control those for target processes
#if OS_WINDOWS
HANDLE output_handles[3] =
{
GetStdHandle(STD_INPUT_HANDLE),
GetStdHandle(STD_OUTPUT_HANDLE),
GetStdHandle(STD_ERROR_HANDLE),
};
for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1)
{
B32 duplicate = 0;
for(U64 idx2 = 0; idx2 < idx; idx2 += 1)
{
if(output_handles[idx2] == output_handles[idx])
{
duplicate = 1;
break;
}
}
if(duplicate)
{
output_handles[idx] = 0;
}
}
for(U64 idx = 0; idx < ArrayCount(output_handles); idx += 1)
{
if(output_handles[idx] != 0)
{
CloseHandle(output_handles[idx]);
}
}
SetStdHandle(STD_INPUT_HANDLE, 0);
SetStdHandle(STD_OUTPUT_HANDLE, 0);
SetStdHandle(STD_ERROR_HANDLE, 0);
#endif
//- rjf: manual layer initialization
{
r_init(cmd_line);
@@ -521,21 +524,35 @@ entry_point(CmdLine *cmd_line)
{
Temp scratch = scratch_begin(0, 0);
U32 instance_pid = os_get_process_info()->pid;
String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", instance_pid);
String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", instance_pid);
String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", instance_pid);
OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name);
ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name);
ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name);
// rjf: set up cross-process sender -> main ring buffer
String8 ipc_sender2main_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_shared_memory_%i_", instance_pid);
String8 ipc_sender2main_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_signal_semaphore_%i_", instance_pid);
String8 ipc_sender2main_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_lock_semaphore_%i_", instance_pid);
OS_Handle ipc_sender2main_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_sender2main_shared_memory_name);
ipc_sender2main_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_sender2main_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_sender2main_signal_semaphore = os_semaphore_alloc(0, 1, ipc_sender2main_signal_semaphore_name);
ipc_sender2main_lock_semaphore = os_semaphore_alloc(1, 1, ipc_sender2main_lock_semaphore_name);
// rjf: set up cross-process main -> sender ring buffer
String8 ipc_main2sender_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_shared_memory_%i_", instance_pid);
String8 ipc_main2sender_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_signal_semaphore_%i_", instance_pid);
String8 ipc_main2sender_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_lock_semaphore_%i_", instance_pid);
OS_Handle ipc_main2sender_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_main2sender_shared_memory_name);
ipc_main2sender_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_main2sender_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_main2sender_signal_semaphore = os_semaphore_alloc(0, 1, ipc_main2sender_signal_semaphore_name);
ipc_main2sender_lock_semaphore = os_semaphore_alloc(1, 1, ipc_main2sender_lock_semaphore_name);
// rjf: set up ipc-receiver -> main thread ring buffer; launch signaler thread
ipc_s2m_ring_mutex = os_mutex_alloc();
ipc_s2m_ring_cv = os_condition_variable_alloc();
IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base;
if(ipc_shared_memory_base != 0)
IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base;
if(ipc_sender2main_shared_memory_base != 0)
{
MemoryZeroStruct(ipc_info);
os_thread_launch(ipc_signaler_thread__entry_point, 0, 0);
}
scratch_end(scratch);
}
@@ -544,6 +561,7 @@ entry_point(CmdLine *cmd_line)
for(B32 quit = 0; !quit;)
{
//- rjf: consume IPC messages, dispatch UI commands
B32 ipc_command_frame = 0;
{
Temp scratch = scratch_begin(0, 0);
B32 consumed = 0;
@@ -554,6 +572,7 @@ entry_point(CmdLine *cmd_line)
if(unconsumed_size >= sizeof(U64))
{
consumed = 1;
ipc_command_frame = 1;
ipc_s2m_ring_read_pos += ring_read_struct(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_read_pos, &msg.size);
msg.size = Min(msg.size, unconsumed_size);
msg.str = push_array(scratch.arena, U8, msg.size);
@@ -632,6 +651,24 @@ entry_point(CmdLine *cmd_line)
jit_attach = 0;
rd_cmd(RD_CmdKind_Attach, .pid = jit_pid);
}
//- rjf: gather command outputs & write them
if(ipc_command_frame)
{
if(ipc_main2sender_shared_memory_base != 0 &&
os_semaphore_take(ipc_main2sender_lock_semaphore, os_now_microseconds()+5000000))
{
IPCInfo *ipc_info = (IPCInfo *)ipc_main2sender_shared_memory_base;
U8 *buffer = (U8 *)(ipc_info+1);
U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo);
StringJoin join = {str8_lit(""), str8_lit("\0"), str8_lit("")};
String8 msg = str8_list_join(scratch.arena, &rd_state->cmd_outputs, &join);
ipc_info->msg_size = Min(buffer_max, msg.size);
MemoryCopy(buffer, msg.str, ipc_info->msg_size);
os_semaphore_drop(ipc_main2sender_signal_semaphore);
os_semaphore_drop(ipc_main2sender_lock_semaphore);
}
}
}
}
@@ -674,29 +711,62 @@ entry_point(CmdLine *cmd_line)
}
//- rjf: grab destination instance's shared memory resources
String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", dst_pid);
String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", dst_pid);
String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", dst_pid);
OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name);
ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name);
ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name);
String8 ipc_sender2main_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_shared_memory_%i_", dst_pid);
String8 ipc_sender2main_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_signal_semaphore_%i_", dst_pid);
String8 ipc_sender2main_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_sender2main_lock_semaphore_%i_", dst_pid);
OS_Handle ipc_sender2main_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_sender2main_shared_memory_name);
ipc_sender2main_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_sender2main_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_sender2main_signal_semaphore = os_semaphore_alloc(0, 1, ipc_sender2main_signal_semaphore_name);
ipc_sender2main_lock_semaphore = os_semaphore_alloc(1, 1, ipc_sender2main_lock_semaphore_name);
String8 ipc_main2sender_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_shared_memory_%i_", dst_pid);
String8 ipc_main2sender_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_signal_semaphore_%i_", dst_pid);
String8 ipc_main2sender_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_main2sender_lock_semaphore_%i_", dst_pid);
OS_Handle ipc_main2sender_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_main2sender_shared_memory_name);
ipc_main2sender_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_main2sender_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE));
ipc_main2sender_signal_semaphore = os_semaphore_alloc(0, 1, ipc_main2sender_signal_semaphore_name);
ipc_main2sender_lock_semaphore = os_semaphore_alloc(1, 1, ipc_main2sender_lock_semaphore_name);
//- rjf: got resources -> write message
if(ipc_shared_memory_base != 0 &&
os_semaphore_take(ipc_lock_semaphore, max_U64))
B32 wrote_message = 0;
if(ipc_sender2main_shared_memory_base != 0 &&
os_semaphore_take(ipc_sender2main_lock_semaphore, max_U64))
{
IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base;
wrote_message = 1;
IPCInfo *ipc_info = (IPCInfo *)ipc_sender2main_shared_memory_base;
U8 *buffer = (U8 *)(ipc_info+1);
U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo);
StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")};
String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join);
ipc_info->msg_size = Min(buffer_max, msg.size);
MemoryCopy(buffer, msg.str, ipc_info->msg_size);
os_semaphore_drop(ipc_signal_semaphore);
os_semaphore_drop(ipc_lock_semaphore);
os_semaphore_drop(ipc_sender2main_signal_semaphore);
os_semaphore_drop(ipc_sender2main_lock_semaphore);
}
//- rjf: wrote message -> wait for outputs, read outputs
String8List outputs = {0};
if(wrote_message &&
ipc_main2sender_shared_memory_base != 0 &&
os_semaphore_take(ipc_main2sender_signal_semaphore, os_now_microseconds()+10000000))
{
if(os_semaphore_take(ipc_main2sender_lock_semaphore, max_U64))
{
IPCInfo *ipc_info = (IPCInfo *)ipc_main2sender_shared_memory_base;
String8 msg = str8((U8 *)(ipc_info+1), ipc_info->msg_size);
msg.size = Min(msg.size, IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo));
U8 split_char = 0;
outputs = str8_split(scratch.arena, msg, &split_char, 1, 0);
os_semaphore_drop(ipc_main2sender_lock_semaphore);
}
}
//- rjf: write outputs to stdout
for(String8Node *n = outputs.first; n != 0; n = n->next)
{
fwrite(n->string.str, 1, n->string.size, stdout);
}
fflush(stdout);
scratch_end(scratch);
}break;