Bladeren bron

tools: kill runtime if disconnection takes too long

Daniele Bartolini 6 dagen geleden
bovenliggende
commit
9946d981ca
3 gewijzigde bestanden met toevoegingen van 54 en 12 verwijderingen
  1. 1 0
      docs/changelog.rst
  2. 30 11
      tools/level_editor/launcher.vala
  3. 23 1
      tools/level_editor/level_editor.vala

+ 1 - 0
docs/changelog.rst

@@ -16,6 +16,7 @@ Changelog
 * Tools: added the ability to choose which external tool to use for opening models, sounds and fonts.
 * Tools: added the ability to reset properties to default by right-clicking on them.
 * Tools: the Level Editor will now automatically open a new temporary project when the Projects List is empty.
+* Tools: the game will now be killed if it takes to long to exit when testing it from the Level Editor.
 * Runtime: Linux: switched to Vulkan for rendering.
 * Runtime: added support to stencil testing in shaders.
 * Data Compile: resource packages are now LZ4-compressed.

+ 30 - 11
tools/level_editor/launcher.vala

@@ -48,23 +48,18 @@ public class SubprocessLauncherServer : Object
 	/// Waits for @a process_id to terminate and returns its exit status.
 	public int wait(uint32 process_id) throws GLib.Error
 	{
-		int ii;
-		for (ii = 0; ii < subprocesses.size; ++ii) {
-			uint32 id = subprocesses[ii].get_data<uint32>("id");
-			if (id == process_id)
-				break;
-		}
+		int ind = subprocess_index(process_id);
 
-		if (ii == subprocesses.size)
+		if (ind == subprocesses.size)
 			throw new SubprocessLauncherError.SUBPROCESS_NOT_FOUND("Process ID %u not found".printf(process_id));
 
 		try {
-			if (!subprocesses[ii].wait())
+			if (!subprocesses[ind].wait())
 				throw new SubprocessLauncherError.SUBPROCESS_CANCELLED("Process ID %u was cancelled".printf(process_id));
 
-			if (subprocesses[ii].get_if_exited()) {
-				int exit_status = subprocesses[ii].get_exit_status();
-				subprocesses.remove_at(ii);
+			if (subprocesses[ind].get_if_exited()) {
+				int exit_status = subprocesses[ind].get_exit_status();
+				subprocesses.remove_at(ind);
 				return exit_status;
 			}
 		} catch (GLib.Error e) {
@@ -73,6 +68,29 @@ public class SubprocessLauncherServer : Object
 
 		return int.MAX;
 	}
+
+	/// Kills the process identified by @a process_id.
+	public void kill(uint32 process_id) throws GLib.Error
+	{
+		int ind = subprocess_index(process_id);
+
+		if (ind == subprocesses.size)
+			throw new SubprocessLauncherError.SUBPROCESS_NOT_FOUND("Process ID %u not found".printf(process_id));
+
+		subprocesses[ind].force_exit();
+	}
+
+	public int subprocess_index(uint32 process_id)
+	{
+		int ind;
+		for (ind = 0; ind < subprocesses.size; ++ind) {
+			uint32 id = subprocesses[ind].get_data<uint32>("id");
+			if (id == process_id)
+				break;
+		}
+
+		return ind;
+	}
 }
 
 [DBus (name = "org.crownengine.SubprocessLauncher")]
@@ -80,6 +98,7 @@ public interface SubprocessLauncher : Object
 {
 	public abstract uint32 spawnv_async(GLib.SubprocessFlags flags, string[] argv, string working_dir) throws GLib.SpawnError, GLib.Error;
 	public abstract int wait(uint32 process_id) throws GLib.Error;
+	public abstract void kill(uint32 process_id) throws GLib.Error;
 }
 
 public static void on_bus_acquired(GLib.DBusConnection conn)

+ 23 - 1
tools/level_editor/level_editor.vala

@@ -178,8 +178,11 @@ public enum TargetArch
 
 public class RuntimeInstance
 {
+	public const int QUIT_TIMEOUT_MS = 4000;
+
 	public string _name;
 	public uint32 _process_id;
+	public bool _stuck;
 	public uint _revision;
 	public GLib.SourceFunc _stop_callback;
 	public GLib.SourceFunc _refresh_callback;
@@ -195,6 +198,7 @@ public class RuntimeInstance
 	{
 		_name = name;
 		_process_id = uint32.MAX;
+		_stuck = false;
 		_revision = 0;
 		_stop_callback = null;
 		_refresh_callback = null;
@@ -269,14 +273,32 @@ public class RuntimeInstance
 			if (_client.is_connected()) {
 				_stop_callback = stop.callback;
 				_client.send(RuntimeApi.quit());
+
+				// Call it stuck if not disconnected before a while.
+				GLib.Timeout.add_full(GLib.Priority.HIGH, QUIT_TIMEOUT_MS, () => {
+						if (_stop_callback != null) {
+							_stuck = true;
+							_stop_callback();
+						}
+
+						return GLib.Source.REMOVE;
+					});
+
 				yield; // Wait for _client to disconnect.
 				_stop_callback = null;
 			}
 		}
 
 		try {
-			if (_process_id != uint32.MAX)
+			if (_process_id != uint32.MAX) {
+				if (_stuck) {
+					_subprocess_launcher.kill(_process_id);
+					_stuck = false;
+					logw("Process %u took more than %d ms to quit: killed".printf(_process_id, QUIT_TIMEOUT_MS));
+				}
+
 				_subprocess_launcher.wait(_process_id);
+			}
 			_process_id = uint32.MAX;
 		} catch (GLib.Error e) {
 			loge(e.message);