reading process stdout/stderr for POSIX-compliant platforms
This commit is contained in:
parent
4c898662e0
commit
f9667732d0
10
src/raylib.h
10
src/raylib.h
|
|
@ -961,20 +961,20 @@ typedef enum {
|
||||||
NPATCH_THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles
|
NPATCH_THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles
|
||||||
} NPatchLayout;
|
} NPatchLayout;
|
||||||
|
|
||||||
// Process info
|
// Process resources
|
||||||
typedef struct Process {
|
typedef struct Process {
|
||||||
int pid; // Process unique identifier
|
int pid; // Process unique identifier
|
||||||
|
struct ProcessInternal *internal; // Platform-specific process data
|
||||||
void *pipeStdoutRead; // Process stdout and stderr read pipe [Windows only]
|
|
||||||
void *pipeStdinWrite; // Process stdin write pipe [Windows only]
|
|
||||||
} Process;
|
} Process;
|
||||||
|
|
||||||
|
// Process state
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PROCESS_STATE_NONE = 0, // No state information
|
PROCESS_STATE_NONE = 0, // No state information
|
||||||
PROCESS_STATE_RUNNING, // Process is running
|
PROCESS_STATE_RUNNING, // Process is running
|
||||||
PROCESS_STATE_FINISHED // Process has exited
|
PROCESS_STATE_FINISHED // Process has exited
|
||||||
} ProcessState;
|
} ProcessState;
|
||||||
|
|
||||||
|
// Process information for CheckProcess() function
|
||||||
typedef struct ProcessInfo {
|
typedef struct ProcessInfo {
|
||||||
ProcessState state; // Process state (PROCESS_STATE_*)
|
ProcessState state; // Process state (PROCESS_STATE_*)
|
||||||
int exitCode; // Process exit code (if finished)
|
int exitCode; // Process exit code (if finished)
|
||||||
|
|
|
||||||
83
src/rcore.c
83
src/rcore.c
|
|
@ -281,6 +281,7 @@
|
||||||
#include <sys/wait.h> // Required for: waitpid() [Used in CheckProcess()]
|
#include <sys/wait.h> // Required for: waitpid() [Used in CheckProcess()]
|
||||||
#include <signal.h> // Required for: kill() [Used in PauseProcess(), ResumeProcess(), CloseProcess()]
|
#include <signal.h> // Required for: kill() [Used in PauseProcess(), ResumeProcess(), CloseProcess()]
|
||||||
#include <sys/types.h> // Required for: pid_t [Used as function local variable type and for Process PID type]
|
#include <sys/types.h> // Required for: pid_t [Used as function local variable type and for Process PID type]
|
||||||
|
#include <poll.h> // Required for: pollfd, poll() [Used in ReadProcessOutput()]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
@ -4289,6 +4290,11 @@ int GetTouchPointCount(void)
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
struct ProcessInternal {
|
||||||
|
void *pipeStdoutRead; // Process stdout and stderr read pipe
|
||||||
|
void *pipeStdinWrite; // Process stdin write pipe
|
||||||
|
};
|
||||||
|
|
||||||
static bool CreatePipeWindows(void** readPipe, void** writePipe) {
|
static bool CreatePipeWindows(void** readPipe, void** writePipe) {
|
||||||
struct _SECURITY_ATTRIBUTES sa = { 0 };
|
struct _SECURITY_ATTRIBUTES sa = { 0 };
|
||||||
sa.nLength = sizeof(struct _SECURITY_ATTRIBUTES);
|
sa.nLength = sizeof(struct _SECURITY_ATTRIBUTES);
|
||||||
|
|
@ -4302,6 +4308,17 @@ static void CloseAllPipesWindows(void** pipes, int count) {
|
||||||
if (pipes[i] != NULL) CloseHandle(pipes[i]);
|
if (pipes[i] != NULL) CloseHandle(pipes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
|
struct ProcessInternal {
|
||||||
|
int pipefdStdout[2]; // Process stdout and stderr pipe file descriptors
|
||||||
|
int pipefdStdin[2]; // Process stdin pipe file descriptors
|
||||||
|
};
|
||||||
|
|
||||||
|
static void CloseAllPipesUnix(int* pipefds, int count) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (pipefds[i] != -1) close(pipefds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialize a new process, returns a Process struct
|
// Initialize a new process, returns a Process struct
|
||||||
|
|
@ -4366,8 +4383,9 @@ RLAPI Process InitProcess(const char *command, char *const args[])
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
|
|
||||||
process.pipeStdoutRead = pipeStdoutRead;
|
process.internal = (struct ProcessInternal *)RL_MALLOC(sizeof(struct ProcessInternal));
|
||||||
process.pipeStdinWrite = pipeStdinWrite;
|
process.internal->pipeStdoutRead = pipeStdoutRead;
|
||||||
|
process.internal->pipeStdinWrite = pipeStdinWrite;
|
||||||
|
|
||||||
// Free parent process handles
|
// Free parent process handles
|
||||||
CloseHandle(pipeStdoutWrite);
|
CloseHandle(pipeStdoutWrite);
|
||||||
|
|
@ -4380,15 +4398,46 @@ RLAPI Process InitProcess(const char *command, char *const args[])
|
||||||
|
|
||||||
return process;
|
return process;
|
||||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
|
// Initialize fd to -1 for error checking
|
||||||
|
int pipefd[4] = { -1, -1, -1, -1 };
|
||||||
|
|
||||||
|
if ((pipe(&pipefd[0]) == -1) ||
|
||||||
|
(pipe(&pipefd[2]) == -1))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "PROCESS: Failed to create pipes");
|
||||||
|
CloseAllPipesUnix(pipefd, 4);
|
||||||
|
return process;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.internal = (struct ProcessInternal *)RL_MALLOC(sizeof(struct ProcessInternal));
|
||||||
|
memcpy(process.internal->pipefdStdout, &pipefd[0], sizeof(int) * 2);
|
||||||
|
memcpy(process.internal->pipefdStdin, &pipefd[2], sizeof(int) * 2);
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "PROCESS: Failed to create process");
|
TRACELOG(LOG_WARNING, "PROCESS: Failed to create process");
|
||||||
|
CloseAllPipesUnix(pipefd, 4);
|
||||||
|
RL_FREE(process.internal);
|
||||||
|
return process;
|
||||||
}
|
}
|
||||||
else if (pid == 0)
|
else if (pid == 0)
|
||||||
{
|
{
|
||||||
// Child process
|
// Child process
|
||||||
|
|
||||||
|
// Close pipe read end, redirect stdout and stderr to pipe write end
|
||||||
|
close(process.internal->pipefdStdout[0]);
|
||||||
|
dup2(process.internal->pipefdStdout[1], STDOUT_FILENO);
|
||||||
|
dup2(process.internal->pipefdStdout[1], STDERR_FILENO);
|
||||||
|
close(process.internal->pipefdStdout[1]);
|
||||||
|
|
||||||
|
// Close pipe write end, redirect stdin to pipe read end
|
||||||
|
close(process.internal->pipefdStdin[1]);
|
||||||
|
dup2(process.internal->pipefdStdin[0], STDIN_FILENO);
|
||||||
|
close(process.internal->pipefdStdin[0]);
|
||||||
|
|
||||||
|
// Execute command
|
||||||
execvp(command, args);
|
execvp(command, args);
|
||||||
|
|
||||||
// If execvp returns, it must have failed
|
// If execvp returns, it must have failed
|
||||||
|
|
@ -4396,7 +4445,12 @@ RLAPI Process InitProcess(const char *command, char *const args[])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Parent process
|
||||||
process.pid = pid;
|
process.pid = pid;
|
||||||
|
|
||||||
|
// Close stdout pipe write end and stdin pipe read end
|
||||||
|
close(process.internal->pipefdStdout[1]);
|
||||||
|
close(process.internal->pipefdStdin[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return process;
|
return process;
|
||||||
|
|
@ -4564,7 +4618,7 @@ RLAPI const char *ReadProcessOutput(Process process, int *length)
|
||||||
// NOTE: This will read whatever in the pipe buffer
|
// NOTE: This will read whatever in the pipe buffer
|
||||||
|
|
||||||
unsigned long bytesRead = 0;
|
unsigned long bytesRead = 0;
|
||||||
if (!ReadFile(process.pipeStdoutRead, output, sizeof(output), &bytesRead, NULL))
|
if (!ReadFile(process.internal->pipeStdoutRead, output, sizeof(output), &bytesRead, NULL))
|
||||||
{
|
{
|
||||||
*length = 0;
|
*length = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -4573,7 +4627,22 @@ RLAPI const char *ReadProcessOutput(Process process, int *length)
|
||||||
*length = (int)bytesRead;
|
*length = (int)bytesRead;
|
||||||
return output;
|
return output;
|
||||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
TRACELOG(LOG_WARNING, "PROCESS: Reading process output not supported on this platform");
|
struct pollfd fds[1];
|
||||||
|
fds[0].fd = process.internal->pipefdStdout[0];
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
|
||||||
|
// No timeout, just check if there is data to read
|
||||||
|
int pollResult = poll(fds, 1, 0);
|
||||||
|
if ((pollResult > 0) && (fds[0].revents & POLLIN))
|
||||||
|
{
|
||||||
|
ssize_t bytesRead = read(process.internal->pipefdStdout[0], output, sizeof(output));
|
||||||
|
if (bytesRead > 0)
|
||||||
|
{
|
||||||
|
*length = (int)bytesRead;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*length = 0;
|
*length = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#else
|
||||||
|
|
@ -4704,7 +4773,7 @@ RLAPI void CloseProcess(Process process)
|
||||||
CloseHandle(hProcess);
|
CloseHandle(hProcess);
|
||||||
|
|
||||||
// Clean up pipes
|
// Clean up pipes
|
||||||
void* pipes[] = { process.pipeStdoutRead, process.pipeStdinWrite };
|
void *pipes[] = { process.internal->pipeStdoutRead, process.internal->pipeStdinWrite };
|
||||||
CloseAllPipesWindows(pipes, sizeof(pipes) / sizeof(pipes[0]));
|
CloseAllPipesWindows(pipes, sizeof(pipes) / sizeof(pipes[0]));
|
||||||
|
|
||||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||||
|
|
@ -4728,6 +4797,10 @@ RLAPI void CloseProcess(Process process)
|
||||||
|
|
||||||
// Wait process termination
|
// Wait process termination
|
||||||
waitpid(process.pid, NULL, 0);
|
waitpid(process.pid, NULL, 0);
|
||||||
|
|
||||||
|
int pipefd[2] = { process.internal->pipefdStdout[0], process.internal->pipefdStdin[1] };
|
||||||
|
CloseAllPipesUnix(pipefd, 2);
|
||||||
|
RL_FREE(process.internal);
|
||||||
#else
|
#else
|
||||||
TRACELOG(LOG_WARNING, "PROCESS: Process management not supported on this platform");
|
TRACELOG(LOG_WARNING, "PROCESS: Process management not supported on this platform");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user