Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL_Process created with pipe_stdio set to true hangs on large output. #11645

Open
failedev17 opened this issue Dec 13, 2024 · 3 comments
Open
Milestone

Comments

@failedev17
Copy link

failedev17 commented Dec 13, 2024

int main(){
    const char* args[] {"clang++", "--help", nullptr};
    SDL_Process* p = SDL_CreateProcess(args, true);
    SDL_WaitProcess(p, true, nullptr);
    SDL_DestroyProcess(p);
}

Side note, Using SDL_ReadIO and SDL_LoadFile_IO on p.stream before and after flushing/closing doesn't give the output that was written to the file. I don't know if this is intended or not.

	Process p;
	p.stream = SDL_IOFromFile("temp.txt", "w+b");
	SDL_PropertiesID props = SDL_CreateProperties();
	SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)args.data());
	SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_REDIRECT);
	SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_POINTER, p.stream);
	p.process = SDL_CreateProcessWithProperties(props);
	if(!p.process){
		printf("%s\n", SDL_GetError());
	}
	SDL_DestroyProperties(props);

OS : Windows 10.

@slouken slouken added this to the 3.2.0 milestone Dec 13, 2024
@madebr
Copy link
Contributor

madebr commented Dec 13, 2024

Your code also blocks on Linux.
clang's help is very long and will fill the pipe buffer (64kiB on Linux).
What's happening is that the kernel suspends the process (because write(2) is a blocking write) until the pipe buffer is drained.

Use SDL_ReadProcess to read all stdout in one go:

#include <SDL3/SDL.h>
int main(){
    const char* args[]= {"clang++", "--help", NULL};
    SDL_Process *p = SDL_CreateProcess(args, true);
    int ec;
    size_t s;
    void *d = SDL_ReadProcess(p, &s, &ec);
    SDL_Log("Got %p s=%u", d, (unsigned int)s);
    SDL_Log("%s", (const char *)d);
    SDL_free(d);
    SDL_WaitProcess(p, true, NULL);
    SDL_DestroyProcess(p);
    return 0;
}

Alternatively, you read chunks of data when it becomes available as long as the process is alive:

#include <SDL3/SDL.h>
int main(){
    const char* args[]= {"clang++", "--help", NULL};
    SDL_Process *p = SDL_CreateProcess(args, true);
    SDL_IOStream *clang_output = SDL_GetProcessOutput(p);
    
    while (!SDL_WaitProcess(p, false, NULL)) {
      char buffer[4096];
      size_t nb = SDL_ReadIO(clang_output, buffer, sizeof(buffer)-1);
      buffer[nb] = '\0';
      if (nb) {
        SDL_Log("nb=%u", (unsigned)nb);
        SDL_Log("Got %s", buffer);
      }
    }
    int rc;
    SDL_WaitProcess(p, true, &rc);
    SDL_Log("rc=%d", rc);
    SDL_DestroyProcess(p);
    return 0;
}

@failedev17
Copy link
Author

Thanks for the info. I guess it should be mentioned in the SDL_WaitProcess docs somewhere. I thought what I had to do was, SDL_WaitProcess() then do a SDL_ReadProcess() and not the other way around.

@madebr
Copy link
Contributor

madebr commented Dec 13, 2024

The process subsystem is relatively very prone to a deadlock. My code above would lock when clang would read from stdin (close stdin of the subprocess after startup to avoid this. I have to check myself now what would happen if a subprocess opens /dev/tty after having closed stdin)
You need to code very careful to avoid this.

You're right about the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants