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

OS.execute without blocking mode causes zombie processes (defunct) #51366

Closed
rennomarcus opened this issue Aug 7, 2021 · 3 comments
Closed

Comments

@rennomarcus
Copy link

rennomarcus commented Aug 7, 2021

Godot version

3.3.2

System information

Ubuntu 20.04.2 LTS, 64-bit

Issue description

When executing OS.execute with the blocking flag as false the process stays in zombie mode.

zombie

Because the process is already 'dead' I cannot kill it, thus remove from the process list.

Steps to reproduce

  1. run any command in OS.execute with the flag blocking as false. Example: var pid = OS.execute('pwd', [], false)
  2. go to your terminal and look for your processes and grep by keyword 'defunct'. Example: ps cax | grep defunct

You will see a list of processes executed by godot. If you keep running the command the list keeps growing. When you exit the application/game the processes are removed.

Minimal reproduction project

No response

@qrrk
Copy link

qrrk commented Aug 18, 2021

I ran into the same issue today. I start extracting an archive using tar, then sit in a loop checking if this process is still running (using ps, this time in blocking mode) before doing something with the extracted files. Well, with this issue the process never terminates, so that doesn't work. I'll try working around it using threads or maybe multiple nodes and signals, and post the results.

UPD. From my test project:

func _is_process_running(pid: int) -> bool:
	
	var exit_code = OS.execute("ps", ["-p", pid])
	return !exit_code


func _on_Button3_pressed() -> void:
	
	var fname = "REDACTED.tar.gz"
	var workdir = OS.get_executable_path().get_base_dir() + "/"
	var args = ["xzf", workdir + fname, "-C", workdir]
	
	var pid = OS.execute("tar", args, false)
	
	while _is_process_running(pid):
		yield(get_tree().create_timer(0.1), "timeout")
		
	print("Finished extracting ", fname)

@qrrk
Copy link

qrrk commented Aug 19, 2021

This will do the trick:

class_name OSExecWrapper
extends Object


signal process_exited

var _worker: Thread
var output = []
var exit_code = null


func _wrapper(path_and_args: Array) -> void:
	
	exit_code = OS.execute(path_and_args[0], path_and_args[1], true, output)
	emit_signal("process_exited")
	_worker.call_deferred("wait_to_finish")

func execute(path: String, args: PoolStringArray) -> void:
	
	_worker = Thread.new()
	_worker.start(self, "_wrapper", [path, args])

Usage example:

func _on_Button5_pressed() -> void:
	
	var oew = OSExecWrapper.new()
	print("Starting.")
	oew.execute("sh", ["-c", "sleep 1; ls /tmp"])
	yield(oew, "process_exited")
	print("Finished. Exit code: %s, output:\n%s" % [oew.exit_code, oew.output[0]])

@rsubtil
Copy link
Contributor

rsubtil commented Aug 30, 2021

For 4.0 this has been fixed by #44514

@akien-mga akien-mga added this to the 4.0 milestone Sep 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants