OS.execute_with_pipe() not working as expected

Godot Version

4.4.1

Question

I’m trying to execute another instance of my Godot program with OS.execute_with_pipe(), and assigning the return value to a variable to access its “stdio” and “pid”. I’m also setting the blocking parameter to false. However, I believe the blocking parameter doesn’t seem to work as expected.

The return value IS set to variable correctly (like, it returns the right process ID of the excepted new process), and the main process continues to work normally, but the second instance doesn’t launch until I close the main process. And if I call the method without getting the return value, everything works fine.
I also tried calling the function without getting the return value, but setting the blocking parameter to true, and it works exactly the same way as if I set it to false. But if blocking is true AND I set the return value to a variable, then my app freezes, and only when I close it, the second instance launches.

How can I have the second instance launch upon calling the method, access its stdio and pid, and not block the main process? According to the documentation, setting the parameter blocking to false should allow me to get pipe information immediately… am I missing something?
I even tried using threads with no succes (probably my fault) back in 4.3, when the method did not have a blocking parameter, and was blocking by default. I thought that with this new addition, creating threads became not necessary, but I’m still having the same problem I had before.

For comparison, OS.execute_with_pipe() works similarly to OS.create_process(), which is also non-blocking, creates a process independent of the main one, and returns something (the process ID). That function worked perfectly for me, but in order to add a new feature, I need the “stdio”, but OS.execute_with_pipe() is just not working…

Code is not very relevant, but here it is… it runs on file dialog path selected, in the main thread:

MainUtils.process_info = OS.execute_with_pipe(
    OS.get_executable_path(),
    [EXPORT_SCENE,
    "--path", frame_save_dir,
    "--write-movie", png_filename + ".png",
    "--resolution", "1280x720",
    "--fixed-fps", "60",
    "--",
    "--load_preset=" + GlobalVariables.RENDER_PRESET_FILENAME
    ],
    false)

Are you doing nonblocking reads of stdio? It could be that your execute_with_pipe() is happening without blocking, but then you’re blocking trying to read its output.

I just commented out the setter for process_info (see code in the post), and any references to it, including a line that tries to access the pipe, and I’m still having the same problem. Sure, process_info still holds the return value of the function on the main thread, but just holding the value with nothing accessing it can’t be the problem, right?

Edit: reading the code example provided in the Godot PR that introduced the blocking parameter doesn’t have any threading happening either…

Which OS are you using? I tested this on Linux and seems to work fine:

extends Node


var info


func _ready() -> void:
	info = OS.execute_with_pipe(OS.get_executable_path(), ["knight.tscn", "--write-movie", "/home/mrcdk/Videos/knight.avi"], false)


func _process(delta: float) -> void:
	var stdio = info.get("stdio", null) as FileAccess
	var stderr = info.get("stderr", null) as FileAccess

	if stdio:
		var line = stdio.get_line()
		if stdio.get_error() == OK:
			print("STDIO: %s" % line)

	if stderr:
		var line = stdio.get_line()
		if stdio.get_error() == OK:
			print("STDERR: %s" % line)

Result:

1 Like

Hi, I’m on Windows 10.

I tried executing a different program (“cmd.exe” doesn’t work for some reason), getting the return value of the function, and running it in the same function as the original, and it worked.
So I went back to the same line in the post but removed all arguments… still doesn’t work. Every time I try, Windows appears to be loading something (I can tell by how the cursor changes for a moment), but then nothing happens.

Here’s a video of the problem. I start by showing what I describe in the post, the second process doesn’t launch unless the main one is closed. You can also see the cursor changing.
Then I show where the OS.execute_with_pipe() runs, then MainUtils.process_info and what’s linked to it in another script, then I show the script of the scene that launches on the second process, if that’s somehow relevant.
Not shown in the video, but if I were printing the value of MainUtils.process_info, it’d show you immediately the right process ID of the instance that has yet to appear after closing the main process.

Link to video (too large to upload here): https://www.youtube.com/watch?v=CEFSTOUuYj4

I’m not sure where the problem can be, sorry.

Did you try with the code I posted above in a new project? If that does not work you could try searching if there’s an issue opened in the issue tracker related to this or open a new one if needed.

I’ll give that a try, thanks for responding

Windows does have a mechanism for forcing an app to be single instance; more attempts to launch that app will just foreground the initial instance. I don’t know if Godot is maybe using that.

I assumed that… but also OS.create_process() worked fine, and the OS.execute_with_pipe() without getting the return value also worked… I thought the issue might’ve been the path, or blocking code that happens in the second instance, or the second instance trying to access the same file that the main process already is accessing, but it’s the same story.
I might try more ideas later but I’m losing hope. If I find anything I’ll share here.

I wonder if creating a trampoline process would help? As in, make an executable that launches your Godot app and just pipes stdin/stdout between the two. That way, you’d have some debug scaffolding, and could see what was happening between the two Godot instances.

You running the console version of Godot on windows you’re using ? The one that displays a console in a separate window?
If not try with that one.
The other variant used the windows subsystem which iirc knows nothing of pipes…
The, cheers !

I could try but aren’t they basically the same thing, and Godot with console just outputs to an external console? And shouldn’t this not be an issue on exports?