mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-30 15:08:31 +00:00
Added SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN
This commit is contained in:
@@ -175,6 +175,7 @@ typedef enum SDL_ProcessIO
|
|||||||
* output of the process should be redirected into the standard output of
|
* output of the process should be redirected into the standard output of
|
||||||
* the process. This property has no effect if
|
* the process. This property has no effect if
|
||||||
* `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set.
|
* `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set.
|
||||||
|
* - `SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN`: true if the process should run in the background. In this case the default input and output is `SDL_PROCESS_STDIO_NULL` and the exitcode of the process is not available, and will always be 0.
|
||||||
*
|
*
|
||||||
* On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and
|
* On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and
|
||||||
* SIGCHLD should not be ignored or handled because those would prevent SDL
|
* SIGCHLD should not be ignored or handled because those would prevent SDL
|
||||||
@@ -208,6 +209,7 @@ extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcessWithProperties(SDL_Pro
|
|||||||
#define SDL_PROP_PROCESS_CREATE_STDERR_NUMBER "SDL.process.create.stderr_option"
|
#define SDL_PROP_PROCESS_CREATE_STDERR_NUMBER "SDL.process.create.stderr_option"
|
||||||
#define SDL_PROP_PROCESS_CREATE_STDERR_POINTER "SDL.process.create.stderr_source"
|
#define SDL_PROP_PROCESS_CREATE_STDERR_POINTER "SDL.process.create.stderr_source"
|
||||||
#define SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN "SDL.process.create.stderr_to_stdout"
|
#define SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN "SDL.process.create.stderr_to_stdout"
|
||||||
|
#define SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN "SDL.process.create.background"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the properties associated with a process.
|
* Get the properties associated with a process.
|
||||||
@@ -218,6 +220,7 @@ extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcessWithProperties(SDL_Pro
|
|||||||
* - `SDL_PROP_PROCESS_STDIN_POINTER`: an SDL_IOStream that can be used to write input to the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
* - `SDL_PROP_PROCESS_STDIN_POINTER`: an SDL_IOStream that can be used to write input to the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
||||||
* - `SDL_PROP_PROCESS_STDOUT_POINTER`: a non-blocking SDL_IOStream that can be used to read output from the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
* - `SDL_PROP_PROCESS_STDOUT_POINTER`: a non-blocking SDL_IOStream that can be used to read output from the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
||||||
* - `SDL_PROP_PROCESS_STDERR_POINTER`: a non-blocking SDL_IOStream that can be used to read error output from the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
* - `SDL_PROP_PROCESS_STDERR_POINTER`: a non-blocking SDL_IOStream that can be used to read error output from the process, if it was created with `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
|
||||||
|
* - `SDL_PROP_PROCESS_BACKGROUND_BOOLEAN`: true if the process is running in the background.
|
||||||
*
|
*
|
||||||
* \param process the process to query.
|
* \param process the process to query.
|
||||||
* \returns a valid property ID on success or 0 on failure; call
|
* \returns a valid property ID on success or 0 on failure; call
|
||||||
@@ -236,6 +239,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDL_GetProcessProperties(SDL_Process *proce
|
|||||||
#define SDL_PROP_PROCESS_STDIN_POINTER "SDL.process.stdin"
|
#define SDL_PROP_PROCESS_STDIN_POINTER "SDL.process.stdin"
|
||||||
#define SDL_PROP_PROCESS_STDOUT_POINTER "SDL.process.stdout"
|
#define SDL_PROP_PROCESS_STDOUT_POINTER "SDL.process.stdout"
|
||||||
#define SDL_PROP_PROCESS_STDERR_POINTER "SDL.process.stderr"
|
#define SDL_PROP_PROCESS_STDERR_POINTER "SDL.process.stderr"
|
||||||
|
#define SDL_PROP_PROCESS_BACKGROUND_BOOLEAN "SDL.process.background"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all the output from a process.
|
* Read all the output from a process.
|
||||||
|
@@ -35,51 +35,44 @@ extern char **environ;
|
|||||||
|
|
||||||
bool SDL_SYS_OpenURL(const char *url)
|
bool SDL_SYS_OpenURL(const char *url)
|
||||||
{
|
{
|
||||||
const pid_t pid1 = fork();
|
SDL_Environment *env = NULL;
|
||||||
if (pid1 == 0) { // child process
|
char **process_env = NULL;
|
||||||
#ifdef USE_POSIX_SPAWN
|
const char *process_args[] = { "xdg-open", url, NULL };
|
||||||
pid_t pid2;
|
SDL_Process *process = NULL;
|
||||||
const char *args[] = { "xdg-open", url, NULL };
|
bool result = false;
|
||||||
|
|
||||||
|
env = SDL_CreateEnvironment(SDL_FALSE);
|
||||||
|
if (!env) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam
|
// Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam
|
||||||
SDL_unsetenv_unsafe("LD_PRELOAD");
|
SDL_UnsetEnvironmentVariable(env, "LD_PRELOAD");
|
||||||
if (posix_spawnp(&pid2, args[0], NULL, NULL, (char **)args, environ) == 0) {
|
|
||||||
// Child process doesn't wait for possibly-blocking grandchild.
|
process_env = SDL_GetEnvironmentVariables(env);
|
||||||
_exit(EXIT_SUCCESS);
|
if (!process_env) {
|
||||||
} else {
|
goto done;
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
pid_t pid2;
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
// Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam
|
if (!props) {
|
||||||
SDL_unsetenv_unsafe("LD_PRELOAD");
|
goto done;
|
||||||
// Notice this is vfork and not fork!
|
|
||||||
pid2 = vfork();
|
|
||||||
if (pid2 == 0) { // Grandchild process will try to launch the url
|
|
||||||
execlp("xdg-open", "xdg-open", url, NULL);
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
} else if (pid2 < 0) { // There was an error forking
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
// Child process doesn't wait for possibly-blocking grandchild.
|
|
||||||
_exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
#endif // USE_POSIX_SPAWN
|
|
||||||
} else if (pid1 < 0) {
|
|
||||||
return SDL_SetError("fork() failed: %s", strerror(errno));
|
|
||||||
} else {
|
|
||||||
int status;
|
|
||||||
if (waitpid(pid1, &status, 0) == pid1) {
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
if (WEXITSTATUS(status) == 0) {
|
|
||||||
return true; // success!
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("xdg-open reported error or failed to launch: %d", WEXITSTATUS(status));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("xdg-open failed for some reason");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return SDL_SetError("Waiting on xdg-open failed: %s", strerror(errno));
|
|
||||||
}
|
}
|
||||||
|
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, process_args);
|
||||||
|
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, process_env);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, true);
|
||||||
|
process = SDL_CreateProcessWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
if (!process) {
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
done:
|
||||||
|
SDL_free(process_env);
|
||||||
|
SDL_DestroyEnvironment(env);
|
||||||
|
SDL_DestroyProcess(process);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -54,12 +54,14 @@ SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props)
|
|||||||
if (!process) {
|
if (!process) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
process->background = SDL_GetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, false);
|
||||||
|
|
||||||
process->props = SDL_CreateProperties();
|
process->props = SDL_CreateProperties();
|
||||||
if (!process->props) {
|
if (!process->props) {
|
||||||
SDL_DestroyProcess(process);
|
SDL_DestroyProcess(process);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
SDL_SetBooleanProperty(process->props, SDL_PROP_PROCESS_BACKGROUND_BOOLEAN, process->background);
|
||||||
|
|
||||||
if (!SDL_SYS_CreateProcessWithProperties(process, props)) {
|
if (!SDL_SYS_CreateProcessWithProperties(process, props)) {
|
||||||
SDL_DestroyProcess(process);
|
SDL_DestroyProcess(process);
|
||||||
@@ -180,6 +182,9 @@ SDL_bool SDL_WaitProcess(SDL_Process *process, SDL_bool block, int *exitcode)
|
|||||||
if (SDL_SYS_WaitProcess(process, block, &process->exitcode)) {
|
if (SDL_SYS_WaitProcess(process, block, &process->exitcode)) {
|
||||||
process->alive = false;
|
process->alive = false;
|
||||||
if (exitcode) {
|
if (exitcode) {
|
||||||
|
if (process->background) {
|
||||||
|
process->exitcode = 0;
|
||||||
|
}
|
||||||
*exitcode = process->exitcode;
|
*exitcode = process->exitcode;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@@ -25,6 +25,7 @@ typedef struct SDL_ProcessData SDL_ProcessData;
|
|||||||
struct SDL_Process
|
struct SDL_Process
|
||||||
{
|
{
|
||||||
bool alive;
|
bool alive;
|
||||||
|
bool background;
|
||||||
int exitcode;
|
int exitcode;
|
||||||
SDL_PropertiesID props;
|
SDL_PropertiesID props;
|
||||||
SDL_ProcessData *internal;
|
SDL_ProcessData *internal;
|
||||||
|
@@ -137,6 +137,19 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||||||
goto posix_spawn_fail_attr;
|
goto posix_spawn_fail_attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background processes don't have access to the terminal
|
||||||
|
if (process->background) {
|
||||||
|
if (stdin_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stdin_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
if (stdout_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stdout_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
if (stderr_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stderr_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (stdin_option) {
|
switch (stdin_option) {
|
||||||
case SDL_PROCESS_STDIO_REDIRECT:
|
case SDL_PROCESS_STDIO_REDIRECT:
|
||||||
if (!GetStreamFD(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, &fd)) {
|
if (!GetStreamFD(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, &fd)) {
|
||||||
@@ -276,9 +289,38 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Spawn the new process
|
// Spawn the new process
|
||||||
if (posix_spawnp(&data->pid, args[0], &fa, &attr, args, env) != 0) {
|
if (process->background) {
|
||||||
SDL_SetError("posix_spawn failed: %s", strerror(errno));
|
int status = -1;
|
||||||
|
pid_t pid = vfork();
|
||||||
|
switch (pid) {
|
||||||
|
case -1:
|
||||||
|
SDL_SetError("vfork() failed: %s", strerror(errno));
|
||||||
goto posix_spawn_fail_all;
|
goto posix_spawn_fail_all;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
// Detach from the terminal and launch the process
|
||||||
|
setsid();
|
||||||
|
if (posix_spawnp(&data->pid, args[0], &fa, &attr, args, env) != 0) {
|
||||||
|
_exit(errno);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (waitpid(pid, &status, 0) < 0) {
|
||||||
|
SDL_SetError("waitpid() failed: %s", strerror(errno));
|
||||||
|
goto posix_spawn_fail_all;
|
||||||
|
}
|
||||||
|
if (status != 0) {
|
||||||
|
SDL_SetError("posix_spawn() failed: %s", strerror(status));
|
||||||
|
goto posix_spawn_fail_all;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (posix_spawnp(&data->pid, args[0], &fa, &attr, args, env) != 0) {
|
||||||
|
SDL_SetError("posix_spawn() failed: %s", strerror(errno));
|
||||||
|
goto posix_spawn_fail_all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SDL_SetNumberProperty(process->props, SDL_PROP_PROCESS_PID_NUMBER, data->pid);
|
SDL_SetNumberProperty(process->props, SDL_PROP_PROCESS_PID_NUMBER, data->pid);
|
||||||
|
|
||||||
@@ -353,8 +395,24 @@ bool SDL_SYS_KillProcess(SDL_Process *process, SDL_bool force)
|
|||||||
bool SDL_SYS_WaitProcess(SDL_Process *process, SDL_bool block, int *exitcode)
|
bool SDL_SYS_WaitProcess(SDL_Process *process, SDL_bool block, int *exitcode)
|
||||||
{
|
{
|
||||||
int wstatus = 0;
|
int wstatus = 0;
|
||||||
int ret = waitpid(process->internal->pid, &wstatus, block ? 0 : WNOHANG);
|
int ret;
|
||||||
|
pid_t pid = process->internal->pid;
|
||||||
|
|
||||||
|
if (process->background) {
|
||||||
|
// We can't wait on the status, so we'll poll to see if it's alive
|
||||||
|
if (block) {
|
||||||
|
while (kill(pid, 0) == 0) {
|
||||||
|
SDL_Delay(10);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (kill(pid, 0) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*exitcode = 0;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
ret = waitpid(pid, &wstatus, block ? 0 : WNOHANG);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return SDL_SetError("Could not waitpid(): %s", strerror(errno));
|
return SDL_SetError("Could not waitpid(): %s", strerror(errno));
|
||||||
}
|
}
|
||||||
@@ -374,6 +432,7 @@ bool SDL_SYS_WaitProcess(SDL_Process *process, SDL_bool block, int *exitcode)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SDL_SYS_DestroyProcess(SDL_Process *process)
|
void SDL_SYS_DestroyProcess(SDL_Process *process)
|
||||||
{
|
{
|
||||||
|
@@ -232,6 +232,20 @@ bool SDL_SYS_CreateProcessWithProperties(SDL_Process *process, SDL_PropertiesID
|
|||||||
security_attributes.bInheritHandle = TRUE;
|
security_attributes.bInheritHandle = TRUE;
|
||||||
security_attributes.lpSecurityDescriptor = NULL;
|
security_attributes.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
// Background processes don't have access to the terminal
|
||||||
|
// This isn't necessary on Windows, but we keep the same behavior as the POSIX implementation.
|
||||||
|
if (process->background) {
|
||||||
|
if (stdin_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stdin_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
if (stdout_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stdout_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
if (stderr_option == SDL_PROCESS_STDIO_INHERITED) {
|
||||||
|
stderr_option = SDL_PROCESS_STDIO_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (stdin_option) {
|
switch (stdin_option) {
|
||||||
case SDL_PROCESS_STDIO_REDIRECT:
|
case SDL_PROCESS_STDIO_REDIRECT:
|
||||||
if (!SetupRedirect(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, &startup_info.hStdInput)) {
|
if (!SetupRedirect(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, &startup_info.hStdInput)) {
|
||||||
|
Reference in New Issue
Block a user