Unix signal handling in (common) lisp

2019-02-06 13:18发布

I've done a bit of research on this subject and am turning up blanks. There seem to be implementation-dependent ways of doing Unix signal handling in Common Lisp, but is there a package that gives a cross-implementation way of doing signal handling?

I would mainly like to listen for SIGINT and do a graceful shutdown in my app. I'm using Clozure CL 1.7 on linux...like mentioned, it would be great for a package for this, but if I have to resort to implementation-specific code, that's fine.

I'm also not completely married to using SIGINT (although it's ideal). I can use another signal if needed.

If this is going to be messy, does anyone have any other suggestions for gracefully shutting down a lisp app from outside the app? One idea I had is to create a file the app monitors for, and if it detects the file, it shuts down...kind of hacky, though.

Thanks!

4条回答
等我变得足够好
2楼-- · 2019-02-06 13:54

Although out of ignorance I was originally skeptical of Daimrod's comment (first comment under the question) about using CFFI, I looked around a bit more and found http://clozure.com/pipermail/openmcl-devel/2010-July/011675.html. I adapted it to use CFFI and have confirmed this works on SBCL/CCL/clisp (probably others) on linux pretty damn well:

(defmacro set-signal-handler (signo &body body)
  (let ((handler (gensym "HANDLER")))
    `(progn
       (cffi:defcallback ,handler :void ((signo :int))
         (declare (ignore signo))
         ,@body)
       (cffi:foreign-funcall "signal" :int ,signo :pointer (cffi:callback ,handler)))))

(set-signal-handler 2
  (format t "Quitting lol!!!11~%")
  ;; fictional function that lets the app know to quit cleanly (don't quit from callback)
  (signal-app-to-quit))

Note that from what I understand, whatever is in the body of the callback must be short and sweet! No lengthy processing. In the linked article, the macro actually creates a separate thread just for handling the signal, which is overkill for my purposes, since I'm just setting a global variable from nil to t and returning.

Anyway, hopefully this is helpful to others!

查看更多
放我归山
3楼-- · 2019-02-06 14:07

I can't find a general library for signal handling either. However, Slime implements "create a custom SIGINT handler" for most Lisp implementations. By looking at the CCL case of that code, I found ccl:*break-hook*. ccl:*break-hook* is not in the documentation, but the commit it was introduced in is located here.

This trivial example code works on my system (CCL 1.8, linux x86):

(setf ccl:*break-hook* 
  (lambda (cond hook)                              
    (declare (ignore cond hook))
    (format t "Cleaning up ...")
    (ccl:quit)))

After this code is entered into a non-Slime REPL, sending SIGINT will cause the program to print "Cleaning up ..." and exit.

查看更多
家丑人穷心不美
4楼-- · 2019-02-06 14:09

If you use SBCL, you cannot change the signal mask without causing SBCL to crash. Ask nyef about his tips on how to fix SBCL...

查看更多
老娘就宠你
5楼-- · 2019-02-06 14:10

This is a late answer, but for anybody else searching for this, have a look at trivial-signal, available on Quicklisp. This is based on CFFI.

Example

(signal-handler-bind ((:int  (lambda (signo)
                               (declare (ignorable signo))
                               ...handler...)))
  ...body...)
查看更多
登录 后发表回答