One of the truly wonderful things about programming in Common Lisp is
that the system is complete interactive: the programmer can manipulate
anything at run time, including the language itself. This is a really
powerful technique—but how does one preserve the state of the
system between reboots? And how does one get an image-based Lisp system
to play nice with Linux’s system service model?
Well, John
Wiegley published
a great technique a few years which I’ve adapted
for Tasting Notes. It’s
remarkably simple: create a user to run the system as (just like other
services like PostgreSQL or httpd); then create a standard init.d
script to run the system. The really clever thing he does is start
the system itself, a Swank listener and a kill port. Starting the
system is self-explanatory, but what about the rest?
Swank provides a live connexion to a running Lisp system via which
one can interact with the system’s internals. It’s pretty
cool, and Wiegley’s method gets the job done. So far this is
pretty standard stuff; I’ve used it in my own software.
The really clever bit is this bit of code here:
(sb-bsd-sockets:socket-bind socket #(127 0 0 1) *kill-port*)
(sb-bsd-sockets:socket-listen socket 1) (multiple-value-bind
(client-socket addr port) (sb-bsd-sockets:socket-accept socket) (let
((stream (sb-bsd-sockets:socket-make-stream client-socket :element-type
’character :input t :output t :buffering :none))) (princ "Saving
core and shutting down…" stream) (terpri stream))
;; Close up the sockets (sb-bsd-sockets:socket-close client-socket)
(sb-bsd-sockets:socket-close socket))
What this does is wait until someone connects to *KILL-PORT*, then
proceeds to shut down the system, kill all threads and cleanly exit.
Smart and very simple: all the shutdown script has to do
is telnet $KILL_PORT and the software shuts down.
Finally, it calls SB-EXT:SAVE-LISP-AND-DIE to save the current Lisp
environment to a file; the next time it starts up it will run that
image, so the software’s complete history is saved.
All in all, extremely nifty; I ported Tasting Notes to start using it
this weekend.