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!
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!
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.
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...)
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...
So there is trivial-signal as mentioned. Here's how I catch a C-c in my code:
(handler-case
(my-app-main-function)
;; AFAIK trivial-signal is supposed to handle the implementation differences.
(#+sbcl sb-sys:interactive-interrupt
#+ccl ccl:interrupt-signal-condition
#+clisp system::simple-interrupt-condition
#+ecl ext:interactive-interrupt
#+allegro excl:interrupt-signal
() (progn
(format *error-output* "Aborting.~&")
(exit)))
(error (c) (format t "Woops, an unknown error occured:~&~a~&" c)))
Related
When serving large files from Clack/Hunchentoot with Slime connected, I sometimes see error messages like SB-IMPL::SIMPLE-STREAM-PERROR "Couldn't write to ~s"... Those are caused by the browser prematurely dropping connections (which is totally OK). The problem is that each time it happens, SLDB pops up. Which is annoying.
Is there a way I can inhibit certain errors in SLDB such as the above? I still would like to see them in an error log, but definitely not in SLDB.
You can subclass PROCESS-CONNECTION for your acceptor and do your own error handling for this error.
Let's start by defining a custom acceptor:
(defclass no-error-acceptor (hunchentoot:acceptor)
())
Then we can create a wrapper around PROCESS-CONNECTION that inhibits printing of a message for this specific error:
(defmethod hunchentoot:process-connection ((acceptor no-error-acceptor) (socket t))
(handler-case
(call-next-method)
(sb-impl::simple-stream-perror (condition)
;; Perhaps log the error here?
nil)))
Make sure you actually start the server using this acceptor in order for it to be used.
UPDATED
Since your system uses Hunchentoot, you could set the global variable HUNCHENTOOT:*CATCH-ERRORS-P* to T. This should guarantee that the all the conditions arising in code managed by Hunchentoot are catched by Hanchentoot itself and not passed to the debugger.
To disable the debugger in any Common Lisp implementation (both inside a shell REPL as well as the Slime REPL inside Emacs) you could use the predefined global variable *debugger-hook*, by assigning to it a two argument function. The function will receive the condition and the current value of *debugger-hook* when it is called, and can handle the condition or return normally, and in this case the debugger is invoked. For instance, you could simply print the condition:
* (defun my-debug(condition hook)
(declare (ignore hook))
(print condition)
(abort))
DEBUG-IGNORE
* (setf *debugger-hook* #'my-debug)
#<FUNCTION MY-DEBUG>
This second method however cannot work when using Hunchentoot together with Slime, due to the way the two packages interact with respect to the debugging strategies.
In this case one could adopt the solution found by Mike Ivanov, that redefines the swank-debugger-hook function before starting Swank:
(in-package swank)
(setq swank-debugger-hook-orig #'swank-debugger-hook)
(defun swank-debugger-hook (condition hook)
(etypecase condition
(sb-int:simple-stream-error
(progn
(princ "*** Stream error" *error-output*)
(abort)))
(t (funcall swank-debugger-hook-orig condition hook))))
(in-package cl-user)
(swank:create-server :port 4008 :dont-close t)
I get this message when starting SLIME:
; loading #P"d:/lisp/slime-2.12/swank-loader.lisp"
STYLE-WARNING: redefining EMACS-INSPECT (#<SB-PCL:SYSTEM-CLASS T>) in DEFMETHOD
The REPL works normal.
I am totally new to EMACS and SLIME and I'd like to know what does this mean and how to fix it.
I use Windows 8 (64-bit), GNU Emacs 25.0.50.1 (x86_64-w64-mingw32), SLIME 2.12, and SBCL 1.2.7
I addressed folks in GitHub and jackcarrozzo replied
with this post:
Good question - it took a bit of spelunking to find a full answer. The short answer is that emacs-inspect stores handlers for inspecting objects; when a particular object is inspected, the relevant generic function (based on type) will match and be evaluated. From http://lisp-book.org/contents/chslime.pdf page 16, you can run this to see the currently-attached generics:
M-. swank-backend:emacs-inspect
That pdf also describes creating your own inspector as well as additional features that look pretty cool.
Regarding your second point: lots of stuff gets printed to the slime-events buffer; unless you're having a slime-specific issue, you probably don't need to even have it open in a window. Warnings and so forth relevant to your code and interactions will come out either directly in the REPL, in the inferior-lisp buffer, or in one of a few other buffers that emacs/slime will auto-open for you when needed.
CL-USER> (use-package :elk)
; Evaluation aborted on #<SB-KERNEL:SIMPLE-PACKAGE-ERROR "The name ~S does not designate any package." {1002C9D683}>.
CL-USER> (defun moose (a) (+ a 7))
MOOSE
CL-USER> (defun moose (a) (+ a 8))
STYLE-WARNING: redefining COMMON-LISP-USER::MOOSE in DEFUN
MOOSE
CL-USER>
So, in summary: don't worry about it. Slime makes interfacing Common Lisp in emacs simple, and it does a great job of staying out of the way. Slime does admittedly have a ton of features but it doesn't force you to use them. Note to self: I should really get around to learning them some day...
I'm exploring Scheme macros, but I've been unable to find a portable way of writing anaphoric macros.
I'm trying to write an each-it macro, such that this code:
(each-it (list 1 2 3)
(display it))
Expands to this:
(for-each (lambda (it)
(display it))
(list 1 2 3))
I've written a macro with syntax-rules, but this gives me an error about an undefined identifier when I try to use it.
(define-syntax each-it
(syntax-rules ()
((each-it lst body)
(for-each (lambda (it) body)
lst))))
This SO question mentions define-syntax-parameter, which seems to be Racket only. This blog post gives some Scheme code samples, but the code samples don't run in DrRacket in R5RS mode (I think it's the square brackets?).
R4RS has an interesting macro appendix but it is not present in R5RS and I don't know if I can depend on it.
Can I write my each-it macro in a completely portable way? If not, what are the most widely available macro system features for writing my macro?
This should be portable, at least in R6RS:
(define-syntax each-it
(lambda (x)
(syntax-case x ()
((_ lst body)
(with-syntax ((it (datum->syntax x 'it)))
#'(for-each (lambda (it) body) lst))))))
Yes, you can write it in a portable way assuming that R6RS is portable enough for you. (The same cannot be said on R7RS, which currently has nothing more than just syntax-rules, and it's unclear what will be included in the large language, or when it will happen.) See uselpa's for how to do that.
So why am I writing another answer? Because actually doing that is going to be a bad idea. A bad idea not in some vague academic sense that doesn't matter for most real world code -- bad in a sense that is likely to bite you later on. I know that "paper" makes it look intimidating, but read at least the first two sections of the paper mentioned in the other SO question you've seen. Specifically, Section 1.2 shows the problem you'll be running against. Then, Section 2 shows how to do it "properly", in a way that makes it tedious to write macros that expand to uses of your macro. At this point, it will be appealing to take the "just keep it hygienic", but at the end of Section 2 you'll see why that's not working either.
The bottom line, IMO, is to just not do it unless you have syntax parameters or something similar. Maybe the only exception to that (which might be your case) is when the macro is something that you intend to use yourself, and you will never provide it to others.
How can you go about debugging an error with a defadvice involved?
Searching for solutions all I can find is recommendations not to use defadvice because of the debugging difficulties. Amen to that, but other peoples defadvices are everywhere and I'm always running into bugs I can't even begin to track down.
One more thing I could think of:
Temporary rename defadvice into defadvice-old.
Write this new version of defadvice:
(defmacro defadvice (function args &rest body)
`(progn
(put ',(cadr args) 'source-position
(cons byte-compile-current-file byte-compile-read-position))
(defadvice-old ,function ,args ,#body)))
Examine the (symbol-plist <<name of advice>>) once you need it, it would have the position in the file of the file that used the macro.
One option is to make the advice body call a function to do its work, and then you can debug the function instead.
Note that you can evaluate (ad-deactivate 'function) to deactivate all advice for the specified function (this will revert the function to its unadvised state). This might help if some advice is causing you serious problems while you are trying to track it down.
What problem can happen if the goto-line function is used in a non-interactive elisp program? Its docstring gives a warning saying that:
This function is usually the wrong thing to use in a Lisp program.
What you probably want instead is something like:
(goto-char (point-min)) (forward-line (1- N))
Moreover, when I try to byte-compile-file my init file including goto-line, I get a unpleasant warning like this once again:
.emacs:170:19:Warning: `goto-line' used from Lisp code
That command is designed for interactive use only
Is using goto-line in a non-interactive program really so dangerous? Relatedly, why is the suggested forward-line solution preferable?
Firstly, this prevents Elisp programmers from fall into bad habits -- writing
inefficient code in a line-number centric way. i.e. instead of using
(forward-line 1) calculating the current line number, incrementing, and using
goto-line.
From this mailing list article:
In a nutshell, the reason why goto-line should not be a frequently
used command is that normally there's no reason to want to get to line
number N unless you have a program that told you there's something
interesting on that line.
Secondly, goto-line manipulates the user's environment in addition to moving
the point (i.e. push-mark). For non-interactive use, this may not be what
you want. On the other hand if having considered all this, you believe
goto-line is exactly what you need, then just call it like this:
(defun foo ()
(interactive)
(with-no-warnings
(goto-line N)))
And you won't get any compiler warnings.
in addition to what was said:
"goto-line" finally recurs onto "(forward-line (1- line)", which in effect does the work. All other of the 43 lines of "goto-line" command body deal with interactive use. For example considering a possibly universal argument.
When writing a program resp. when running it, your computer is in another state than following an interactive call. Thus you should address this state by using "forward-line" straight on.