Обработка сигналов 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...