Help with on_signal and/or at_halt

Objective:

Perform some clean up while killing a prolog process (may be a deamon on Unix) by kill -SIG PID Unix command.

on_signal/3 and at_halt/1 seem not working as expected.

I’m using: SWI-Prolog version:
SWI-Prolog version 8.5.3 for x86_64-darwin

I want the code to: run the :predicate registered by on_signal/3 or at_halt/1.

It is called while running halt at top console. It did not get called while running kill -quit PID from a OS terminal.

My code looks like this:

  1. use on_signal/3:

on_signal(usr1, _, ip_channel_close:ip_channel_kill),

ip_channel_close:ip_channel_kill(SIG) :-
	print_message(error, format('signal caught: ~w', [SIG])).

kill -kill PID 

  1. use at_halt/1:
at_halt(ip_channel_close:ip_channel_close).

ip_channel_close:ip_channel_close :-
	print_message(error, format('signal caught', [])).

kill -quit PID

Any help is greatly appreciated.

This works fine:

:- on_signal(term, _, terminate).

terminate(SIG) :-
    format('signal caught: ~w~n', [SIG]),
    halt.

Save as e.g., s.pl, run swipl s.pl and kill using

kill -TERM PID

Some remarks:

  • Why use ip_channel_close:? Is that due to the documentation as :? This doc means the argument is module sensitive. One typically does not explicitly use Module:, but let the system fill this from the current context.
  • You trap SIGUSR1, but you kill using kill -quit (not sure what that means anyway). Normal convention is to use SIGTERM for termination and SIGHUP for reloading the server (e.g., call make/0, reload config, etc).
  • There was a regression in some 8.5.x versions where signal handling stopped working.
  • Note that if the application is multi-threaded the signal may be handled by any thread according to the POSIX specs. If you look at the library(http/http_unix_daemon) you’ll see the HTTP server runs in a thread and the main thread executes thread_get_message/1. The signal handler merely sends a thread signal to the main thread.
  • see also library(main).
1 Like

Thank you, Jan. Learned a lot from your remarks.

  1. FYI: on_signal(usr1, _, ip_channel_close:ip_channel_kill) was on_signal(quit, _, ip_channel_close:ip_channel_kill). A copy and paste error.

  2. FYI: The quit signal was used because of the document says:

hup, term, abrt, quit
Causes normal Prolog cleanup (e.g., at_halt/1) before terminating the process with the same signal.

I thought at_halt/1 will be called transparently. Added halt at the end of ip_channel_kill and it worked properly.

  1. Still a problem with deamon
    Modified my code according to your code snippet and it worked in non-deamon process. But for the http_unix_deamon process, it still does not work. Looked at main, http_unix_deamon and http_server, httpd and etc., I couldn’t figure out how to hookup ip_channel_kill/1 to be called by kill -TERM PID.

Further help is appreciated.

If you check out http_unix_daemon.pl you see it sets up signal handling, so your changes are overruled. See setup_signals/1 in that file. It calls halt(0) at the end, so using at_halt/1 should be enough to get something called as the server dies.

Jan, it works like a charm. You are great. Thank you again for all your help.