Stop non terminating Python/Prolog programs with Ctrl-C

I have the following python/prolog program on a Linux(current Fedora) started in a bash:


import janus_swi as janus

for result in janus.query("length(_, X), X = []"):
  print(f'{result}')

Obviously this does not terminate.
So I tried to stop it typing Ctrl-C (sending Signal SIGINT).
But this does not work.
(It is possible to kill the program with sending SIGTERM.)

My expectation - as a python progammer - would be that I can kill running python programs with Ctrl-C.

Is it possible to implement stopping with Ctrl-C?
This will make development more convenient and in-line not only with python development, but also most Unix programs.

Thank you

I don’t know. SWI-Prolog can handle SIGINT gracefully, but if Python is the main program, Python is handling the signal. It would have to defer that to Prolog if Prolog is in control when the signal arrives.

Anyone know whether that is feasible?

For mixed code, i.e. Python and Prolog, like in
the example where there is a Python loop,
you could do this here in some place where
your Python code gets initialized:

    import signal

    signal.signal(signal.SIGINT, my_abort)

Implement my_abort() such that it doesn’t
throw anything, but instead tears down the
currently running SWI-Prolog interpreter, by
placing an interrupt on its interrupt queue.

But it won’t interrupt native code I guess, like
the Prolog execution of the conjunction in the
query, only Python byte code. So you need
auto-yield as in the JavaScript WASM?

1 Like

You can get something “kind of” running using this code

sig.py
import janus_swi as janus
import signal

def my_abort(sig, frame):
    print("Aborting by raising an exception")
    raise Exception("Aborting")

signal.signal(signal.SIGINT, my_abort)

def heartbeat():
    i = 1

janus.consult("heartbeat", """
prolog:heartbeat :-
    py_call('__main__':heartbeat()).
""")

def loop():
    janus.query_once("set_prolog_flag(heartbeat, 10000)")
    janus.query_once("between(1, 100 000 000, _),fail")

loop()

The idea is a bit similar to async yielding. We use the heartbeat facility (added to get yields to JavaScripts) to make a call to Python. That is enough to get Python byte code executed regularly and thus get Python signal handling executed. Now, to get out, we generate an exception.

This looks really ugly. Possibly we can call sys.exit(), which raises a SystemExit exception. Now if Prolog catches this it can raise an abort and if Python catches that it can do sys.exit() again, etc. Would that work?

1 Like