-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add SDL_Process subsystem #10618
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
Add SDL_Process subsystem #10618
Conversation
Would it make sense to use SDL_IOStream for reading/writing from subprocesses? |
It would be possible to create a wrapper for it, but some functions wouldn't be meaningful (size, seek) and others would be hiding options which can vary from case to case (read from stdout, stderr, or a merge of both; close sending SIGTERM (which some apps choose to ignore) or SIGKILL; etc.), so I preferred to let users implement the interface themselves if they wanted to use processes as IOStreams, as they could make each of those decisions themselves. I can try to make a default IOStream interface if we can decide how to handle these cases by default, but it would be preferable to document those decisions to avoid surprises and questions downstream. |
|
One suggestion: The
or even:
Given that user will have separate strings for keys and values (that might come from some external configuration file), creating string like |
Another advantage of using Perhaps we can use the So I suggest to create a |
I did think about doing something like this, but I noticed that the Win32 API also uses the Also, from my habit, whenever environment variables are hardcoded or written in a file like |
@Semphriss Sure, I don't have strong feelings about either; although
Splitting is just a byte swap (replace |
If the strings are const, it would be one strchr(), one strndup(), one free(), and one pointer to the original string after the I'm currently stuck on const stuff like this, because I accept a full-const list of strings for arguments, but exec*() expects a const list of mutable strings :) |
Well, this nonsense is why I don't use |
@Semphriss |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on what I've seen in GLib's GSpawn
low-level interface and GSubprocess
high-level interface, this is the sort of topic where all the OS-level APIs are entirely made out of sharp edges, and it's possible to write useful code that doesn't have undefined behaviour, but only by making heroic efforts to do so.
The devil is in the details with this stuff, and I would suggest letting it take as long as it takes - I suspect that rushing this to get something into SDL 3.2 will only make it hard to fix API issues later.
Windows and Unix have very different models for process management, so trying to stabilize the API for this sort of thing without first getting it working on Windows is probably going to be a bad idea.
I'll leave some comments on implementation issues, but I'll also leave some comments on higher-level design stuff after.
A design decision: on Unix, if the parent process has any file descriptors open that do not have On modern Linux and FreeBSD, you can close fds with |
A design decision: on Unix, because of copy-on-write semantics, if your process has a lot of memory in use (I forget whether it's virtual or physical memory that matters), GLib's GSpawn interface eventually solved this for GNOME Shell by adding a fast-path that uses It might be worthwhile to look at the |
A design decision: Is this something that SDL needs to try to detect and handle somewhat gracefully? I think this should at least be documented - see the intimidating long list in https://docs.gtk.org/glib/func.child_watch_source_new.html for the sort of things I'm concerned about. |
I've merged @madebr's changed in this PR, I'll check to apply the suggestions in a while. |
Regarding copy-on-write, does a fail in exec*() immediately cause a copy, given that it sets |
In the GNOME Shell issue I was referring to, it never even got this far: according to https://gitlab.gnome.org/GNOME/glib/-/merge_requests/95 , |
After searching, I found as alternatives for
|
The cmake script can do tests for availability of symbols. You'll need to test for availability of (v)fork either ways. |
Individual functions like The main reason I brought up
|
It's worth noting that the Zenity implementation of dialogs uses fork/exec, so if the symbols aren't already detected for those, it might be good to check if they need to be added. I'm not sure if it was an oversight, or if the code is in some special situation where it doesn't need to detect fork/exec beforehand. |
Good point. |
The special situation is "runs on Unix" - any Unix OS worthy of the name has had |
Okay, I'm expanding the output options into an enum and adding process and file redirection. |
I think this is in a good place to merge. @Semphriss, @icculus, @madebr, @smcv, any feedback before that happens? |
e22d75a
to
64d395f
Compare
I'll read the latest version, there's been quite a few changes since I lasted checked completely so it might take a while, I'll try to be as fast as I can! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done a quick review. I haven't checked in-depth for bugs, memory issues and the like; those can be fixed after merging when they will be found.
* - `SDL_PROP_PROCESS_CREATE_STDERR_POINTER`: an SDL_IOStream pointer used for standard error when `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set to `SDL_PROCESS_STDIO_REDIRECT`. | ||
* - `SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN`: true if the error output of the process should be redirected into the standard output of the process. This property has no effect if `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set. | ||
* | ||
* On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and SIGCHLD should not be ignored or handled because those would prevent SDL from properly tracking the lifetime of the underlying process. You should use SDL_WaitProcess() instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be specified for SDL_CreateProcess() as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a bunch of details here that SDL_CreateProcess() just says go look at SDL_CreateProcessWithProperties() to find out. That's the simplified interface, with simplified documentation.
Also added SDL_PROP_IOSTREAM_FILE_DESCRIPTOR_NUMBER and refactored the internal API to be able to create SDL_IOStream objects from native file handles.
Oh man, can we get from a flush to an fdatasync on iostreams? That'll solve a pending async i/o issue. |
Okay, I've flattened this to 2 commits for merging. If everything looks good in CI, I'll go ahead and merge! |
f71e45d
to
35163f6
Compare
Huzzah! Finally merged! Thank you all for your hard work and feedback on this. |
Just hit this testprocess test failure in my fork: https://github.com/sezero/SDL/actions/runs/10856995459/job/30132725225 |
I'm working on environment changes now, we can come back to this after those go in, if it's still an issue. |
Note that there is not a failure in this PR's runs or in mainstream libsdl-org repo's CI runs -- i.e. I don't know how reproducible the failure is. |
The environment stuff has been reworked, please let me know if you run into this again! |
Here it goes again: https://github.com/sezero/SDL/actions/runs/10873602064/job/30169991920#step:25:47729 |
Yep, not sure what is happening there. I'll add some more logging, maybe we can see what's up. |
And here it shows its face in mainstream, meaning I'm not cursed: |
I can reproduce it reliably on ci: |
Description
I've created basic support for spawning processes, establishing communication with std{in,out,err}, setting environment variables and waiting/killing processes.
Progress
As of opening the PR, only Unix is supported. I would prefer to let someone else create the Windows version, since I'm not really familiar with Win32 and might end up doing rookie mistakes.
For the API, I went for the easiest interface I could make. It's probably riddled with Unix-isms; I suppose the implementation of the Windows version will expose that. Naturally, I'll remain attentive to the difficulties encountered on other platforms and I'll adapt the code to be convenient for all.
Generally speaking, I organized my code in the simplest way I could, but everything is open to discussion, whether it be enumeration names, API design decisions, choice of functions, supported features, and so on. I've taken great inspiration from the Dialog subsystem to design the Process one, but I'd like to let someone more familiar than me with SDL's internals review the design to make sure I didn't miss anything.
API
Existing Issue(s)
Closes #10599