Обработка сигналов Unix в (общем) lisp

Я немного поработал над этой темой, и я открываю пробелы. По-видимому, существуют способы реализации обработки Unix-сигналов, зависящие от реализации, в Common Lisp, но есть ли пакет, который дает кросс-реализацию способ обработки сигналов?

В основном я хотел бы слушать SIGINT и делать изящное завершение работы в моем приложении. Я использую Clozure CL 1.7 на linux... как уже упоминалось, это было бы здорово для пакета для этого, но если мне нужно прибегнуть к конкретному приложению коду, это прекрасно.

Я также не совсем женат на использовании SIGINT (хотя он идеален). При необходимости я могу использовать другой сигнал.

Если это будет беспорядочно, есть ли у кого-нибудь другие предложения для изящного закрытия приложения lisp извне приложения? Одна из моих идей заключалась в том, чтобы создать файл, на который отслеживает приложение, и если он обнаруживает файл, он отключается... вроде хакерский.

Спасибо!

Ответ 1

Я не могу найти общую библиотеку для обработки сигналов. Однако Slime реализует "создать пользовательский обработчик SIGINT" для большинства реализаций Lisp. Посмотрев на CCL-код этого кода, я нашел ccl:*break-hook*. ccl:*break-hook* отсутствует в документации, но фиксация, введенная в нее, находится здесь.

Этот тривиальный примерный код работает в моей системе (CCL 1.8, linux x86):

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

После того, как этот код будет введен в не-Slime REPL, отправка SIGINT заставит программу печатать "Очистка..." и выйти.

Ответ 2

Хотя из-за незнания я изначально скептически относился к комментарию Даймрода (первый комментарий по вопросу) об использовании CFFI, я немного оглянулся и нашел http://clozure.com/pipermail/openmcl-devel/2010-July/011675.html, Я адаптировал его для использования CFFI и подтвердил, что это работает на SBCL/CCL/clisp (возможно, другие) на Linux довольно хорошо:

(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))

Обратите внимание, что из того, что я понимаю, все, что находится в теле обратного вызова, должно быть коротким и сладким! Нет длительной обработки. В связанной статье макрос фактически создает отдельный поток только для обработки сигнала, который является излишним для моих целей, поскольку я просто устанавливаю глобальную переменную от nil до t и возвращает.

В любом случае, надеюсь, это полезно другим!

Ответ 3

Это поздний ответ, но для других, кто ищет это, посмотрите тривиальный сигнал, доступный в Quicklisp. Это основано на CFFI.

Пример

(signal-handler-bind ((:int  (lambda (signo)
                               (declare (ignorable signo))
                               ...handler...)))
  ...body...)

Ответ 4

Если вы используете SBCL, вы не можете изменить маску сигнала, не вызывая сбой SBCL. Спросите о его советах о том, как исправить SBCL...