-
Notifications
You must be signed in to change notification settings - Fork 226
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
Ability to execute code upon SIGINT and SIGTERM signals. #1262
Comments
Related: #1030 We don't have support for signal handlers in the core. Given the continued addition of posix only functionality, and the addition of a signal argument to |
Perhaps known already, but for reference, there was some related work here: https://github.com/andrewchambers/janet-ctrl-c |
Pushed to the sigaction branch with an initial implementation of Still hashing out the exact interface though, and signals should play well with the rest of Janet (threads, sandbox, ev, busy loops, etc.). I think a binding for sigprocmask/pthread_sigmask may also be warranted. |
So it looks like there is an example. Adapting that: (defn action []
(print "Handled SIGINT, waiting 5 seconds before...")
(os/sleep 5)
(os/exit 1))
(defn main
[_]
(os/sigaction :int action true)
(forever)) Trying it out:
Followed by Ctrl-C:
After a brief wait I got a prompt and then:
@amano-kenji Is it feasible for you to give the code a try to see if it works for the kind of situation you have in mind? |
I just tried to use There is one little problem which is lack of proper documentation. If |
I found one issue.
I can't close this script with
|
I didn't have luck with However, the posted sample script (for
|
I'm on gentoo linux. |
Also works on Debian 12. |
The script also worked with Void Linux and NetBSD (janet commit: 70a467d). |
SIGINT and SIGTERM both work for me. Btw, I don't recommend using the interrupt interpreter example in most cases, instead it is better to change the busy loop to something like (forever (ev/sleep 100)). The interrupt interpreter is sort of a last resort to make sure cleanup code runs (so I guess makes sense for sigint?), but doing anything safely is hard because the current executing fiber can be interrupted at any random instruction instead of the usual places where control is yielded to the event loop |
I've tried the following for (defn action
[]
(print "Handled SIGTERM!")
(flush)
(os/sleep 1000)
(os/exit 1))
(defn main
[_]
(os/sigaction :term action true)
(forever (ev/sleep 100))) Does the code look problematic? Or perhaps the behavior is explained by:
|
What is interrupt interpreter? |
Possibly some hints from these lines of the example: # Set the interrupt-interpreter argument to `true` to allow
# interrupting the busy loop `(forever)`. By default, will not
# interrupt the interpreter. |
According to my experiment, these cannot be interrupted by signal handler.
But,
|
So the (var a 0)
(forever
(++ a)) this loop will block events from being handled forever (unless you manually add something like |
Python has it. Haskell has it. Raku has it. Why is it dangerous in janet? Is it still safe to interrupt |
Update example to have 4 cases - case 3 was previously broken but should now work.
It's not "dangerous", it is perfectly memory safe either way. It's just not usually needed and can lead to confusing behavior, and things might not be handled in the order that you expect. I've added a more complete example that has 4 cases the should help illustrate what is going on here. Python's signals do not interact well with asyncio, and I don't know anything about Raku or Haskell here. |
I just read 21eab7e
It seems only |
Works on my machine ™️ . Anyway, that is strange, I'm going to let this feature cook a little more and see if I can make it work better / clean-up the scheduling code to be a bit more straight-forward. If it is not satisfactory I may need to remove the interpreter interrupt functionality but I think it is a useful tool to have. |
I got the expected results:
So it seems to be working as advertised here. I used I wasn't doing so much earlier in the issue and perhaps that explains why it seemed |
I just read meson_options.txt which has
So, interpreter interrupt is disabled by default. |
After executing
Lesson: Don't mess with meson. |
Instead of setting a flag, each interrupt increments an atomic counter. When the interrupt is finally handled, either by scheduling code to run on the event loop or executing some out of band code, the user must now decrement the interrupt counter with janet_interpreter_interrupt_handled. While this counter is non-zero, the event loop will not enter the interpreter. This changes the API a bit but makes it possible and easy to handle signals without race conditions or scheduler hacks, as the runtime can ensure that high priority code is run before re-entering possibly blocking interpreter code again. Also included is a new function janet_schedule_soon, which prepends to the task queue instead of appending, allowing interrupt handler to skip ahead of all other scheduled fibers. Lastly, also update meson default options to include the interpreter_interrupt code and raise a runtime error if os/sigaction is used with interpreter interrupt but that build option is not enabled.
Made some improvements to the implementation and fixed the default meson build options. Closing this as now implemented. |
defer
andedefer
do not handle SIGINT and SIGTERM.I'd like to handle these signals in my programs.
The text was updated successfully, but these errors were encountered: