Improve process logic
This commit is contained in:
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user