MiniZinc/minizinc-python

On Windows, need to terminate the minizinc subprocess with CTRL_C_EVENT

aklein3 opened this issue · 2 comments

When a solver instance is cancelled due to a timeout, control-C, SIGTERM, etc., the Python driver cancels the solver instance by calling proc.terminate(). On Linux, it sends SIGTERM to the child process, which does a graceful shutdown of the minizinc app as expected.

Windows does not support SIGTERM. Instead, proc.terminate() nukes the child process by calling the Win32 API TerminateProcess on it, which is equivalent to kill -9 SIGKILL. It results in a very abrupt termination of the minizinc app. This in turn can fail to stop the underlying solver child subprocess.

On Windows, the minizinc app listens for a CTRL_C_EVENT in lieu of SIGTERM. The fix is to send CTRL_C_EVENT via proc.send_signal() instead of nuking the process via proc.terminate():

--- a/src/minizinc/instance.py
+++ b/src/minizinc/instance.py
@@ -452,7 +452,11 @@ class Instance(Model):
                 # Process was cancelled by the user, a MiniZincError occurred, or
                 # an unexpected Python exception occurred
                 # First, terminate the process
-                proc.terminate()
+                if sys.platform == "win32":
+                    import signal
+                    proc.send_signal(signal.CTRL_C_EVENT)
+                else:
+                    proc.terminate()
                 _ = await proc.wait()
                 # Then, reraise the error that occurred
                 raise

For additional information, see the Python documentation for proc.terminate() and proc.send_signal()

Note that minizinc-python sets the CREATE_NEW_CONSOLE flag in the creationflags parameter to create the isolated child process group, so CTRL_C_EVENT works as expected.

That certainly seems the right approach. (I do find it frustrating that Python's standard library essentially makes proc.terminate() a proc.kill() on windows). I will adjust this now.

Thank you!