Improve process logic

This commit is contained in:
Krzosa Karol
2024-08-12 17:01:33 +02:00
parent 2b48f30cfe
commit fcabf96347
5 changed files with 92 additions and 206 deletions

View File

@@ -24,7 +24,7 @@ String GetAbsolutePath(Allocator arena, String relative);
bool IsValid(const FileIter &it);
void Advance(FileIter *it);
FileIter IterateFiles(Allocator allocator, String path);
bool InitOS();
void InitOS(void (*error_proc)(const char *, ...));
String GetExePath(Allocator allocator);
String GetExeDir(Allocator allocator);
@@ -34,26 +34,18 @@ bool IsFile(String path);
String GetWorkingDir(Allocator arena);
bool IsAbsolute(String path);
struct StdoutPollInfo {
int64_t size_read;
int64_t size_available;
};
struct Process {
bool is_valid;
String error_message;
bool exited;
int exit_code;
char platform[6 * 8];
bool is_valid;
int exit_code;
char platform[6 * 8];
int64_t view_id; // text editor view
bool scroll_to_end;
};
Process CreateCommandLineProcess(String command_line, String working_dir);
bool PollExitCode(Process *process);
void CloseProcess(Process *process);
void KillProcess(Process *process);
StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size);
void WriteStdin(Process *process, String string);
void CloseStdin(Process *process);
Process SpawnProcess(String command_line, String working_dir, String write_stdin = {});
bool IsValid(Process *process);
void KillProcess(Process *process);
String PollStdout(Allocator allocator, Process *process);
void WriteStdin(Process *process, String string);
void CloseStdin(Process *process);

View File

@@ -13,6 +13,8 @@
#include "win32_thread.cpp"
void (*Error)(const char *, ...);
// Basic begin
void *VReserve(size_t size) {
void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
@@ -35,26 +37,8 @@ bool VDecommit(void *p, size_t size) {
}
// Basic end
bool InitOS() {
SetConsoleOutputCP(CP_UTF8);
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE) {
DWORD dwMode = 0;
if (GetConsoleMode(hOut, &dwMode)) {
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (SetConsoleMode(hOut, dwMode)) {
return true;
} else {
printf("Failed to enable colored terminal output C\n");
}
} else {
printf("Failed to enable colored terminal output B\n");
}
} else {
printf("Failed to enable colored terminal output A\n");
}
return false;
void InitOS(void (*error_proc)(const char *, ...)) {
Error = error_proc;
}
String ReadFile(Allocator arena, String path) {
@@ -287,25 +271,17 @@ struct Win32Process {
};
static_assert(sizeof(Win32Process) < sizeof(Process::platform));
static String Win32GetPlatformError(String msg, String cmd) {
void Win32ReportError(String msg, String cmd) {
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
defer { LocalFree(lpMsgBuf); };
char *buff = (char *)lpMsgBuf;
size_t buffLen = strlen((const char *)buff);
if (buffLen > 0 && buff[buffLen - 1] == '\n') {
buff[buffLen - 1] = 0;
}
// @warning: leak! but we don't care
String r = Format(GetSystemAllocator(), "%.*s: %.*s! %s", FmtString(msg), FmtString(cmd), (char *)lpMsgBuf);
LocalFree(lpMsgBuf);
return r;
if (buffLen > 0 && buff[buffLen - 1] == '\n') buff[buffLen - 1] = 0;
Error("%.*s: %.*s! %s", FmtString(msg), FmtString(cmd), (char *)lpMsgBuf);
}
static void Win32CloseProcess(Process *process) {
void Win32CloseProcess(Process *process) {
Win32Process *p = (Win32Process *)process->platform;
if (p->handle != INVALID_HANDLE_VALUE) CloseHandle(p->handle);
if (p->child_stdout_write != INVALID_HANDLE_VALUE) CloseHandle(p->child_stdout_write);
@@ -316,12 +292,32 @@ static void Win32CloseProcess(Process *process) {
}
static void Win32ProcessError(Process *process, String msg, String cmd) {
Win32Process *p = (Win32Process *)process->platform;
process->error_message = Win32GetPlatformError(msg, cmd);
Win32Process *p = (Win32Process *)process->platform;
Win32ReportError(msg, cmd);
Win32CloseProcess(process);
}
Process CreateCommandLineProcess(String command_line, String working_dir) {
void WriteStdin(Process *process, String string) {
if (string.len == 0) return;
Assert(process->is_valid);
Win32Process *p = (Win32Process *)process->platform;
Assert(p->child_stdin_write != INVALID_HANDLE_VALUE);
DWORD written = 0;
bool write_error = WriteFile(p->child_stdin_write, string.data, (DWORD)string.len, &written, NULL) == 0;
Assert(write_error == false);
Assert(written == string.len);
}
void CloseStdin(Process *process) {
Win32Process *p = (Win32Process *)process->platform;
CloseHandle(p->child_stdin_write);
p->child_stdin_write = INVALID_HANDLE_VALUE;
}
Process SpawnProcess(String command_line, String working_dir, String write_stdin) {
Process process = {};
Win32Process *p = (Win32Process *)process.platform;
@@ -389,16 +385,21 @@ Process CreateCommandLineProcess(String command_line, String working_dir) {
p->handle = info.hProcess;
process.is_valid = true;
if (write_stdin.len) {
WriteStdin(&process, write_stdin);
CloseStdin(&process);
}
return process;
}
bool PollExitCode(Process *process) {
Assert(process->is_valid);
bool IsValid(Process *process) {
if (process->is_valid == false) return false;
Win32Process *p = (Win32Process *)process->platform;
if (process->exited) return process->exited;
if (WaitForSingleObject(p->handle, 0) != WAIT_OBJECT_0) {
return false;
return true;
}
DWORD exit_code;
@@ -407,13 +408,9 @@ bool PollExitCode(Process *process) {
exit_code = -1;
}
process->exited = true;
process->exit_code = (int)exit_code;
return true;
}
void CloseProcess(Process *process) {
Win32CloseProcess(process);
return false;
}
void KillProcess(Process *process) {
@@ -428,53 +425,30 @@ void KillProcess(Process *process) {
process->exit_code = -1;
}
StdoutPollInfo PollStdout(Process *process, char *buffer, int64_t buffer_size) {
String PollStdout(Allocator allocator, Process *process) {
Assert(process->is_valid);
Win32Process *p = (Win32Process *)process->platform;
DWORD bytes_avail = 0;
StdoutPollInfo result = {};
bool peek_error = PeekNamedPipe(p->child_stdout_read, NULL, 0, NULL, &bytes_avail, NULL) == 0;
bool peek_error = PeekNamedPipe(p->child_stdout_read, NULL, 0, NULL, &bytes_avail, NULL) == 0;
if (peek_error) {
process->error_message = Win32GetPlatformError("Failed to peek stdout of child process", "PeekNamedPipe");
return result;
return {};
} else if (bytes_avail == 0) {
return {};
}
if (!buffer) {
return {0, bytes_avail};
}
if (bytes_avail == 0) {
return result;
}
size_t buffer_size = ClampTop(bytes_avail, (DWORD)(4096 * 16));
char *buffer = AllocArray(allocator, char, buffer_size);
DWORD bytes_read = 0;
bool read_error = ReadFile(p->child_stdout_read, buffer, (DWORD)buffer_size, &bytes_read, 0) == 0;
if (read_error) {
process->error_message = Win32GetPlatformError("Failed to read the stdout of child process", "ReadFile");
return result;
Win32ReportError("Failed to read the stdout of child process", "ReadFile");
Dealloc(allocator, &buffer);
Win32CloseProcess(process);
return {};
}
result = {bytes_read, bytes_avail - bytes_read};
String result = {buffer, bytes_read};
return result;
}
void WriteStdin(Process *process, String string) {
if (string.len == 0) return;
Assert(process->is_valid);
Win32Process *p = (Win32Process *)process->platform;
DWORD written = 0;
bool write_error = WriteFile(p->child_stdin_write, string.data, (DWORD)string.len, &written, NULL) == 0;
Assert(write_error == false);
Assert(written == string.len);
}
void CloseStdin(Process *process) {
Win32Process *p = (Win32Process *)process->platform;
CloseHandle(p->child_stdin_write);
p->child_stdin_write = INVALID_HANDLE_VALUE;
}