[Openmcl-devel] creating a daemon
gb at clozure.com
Mon Jul 5 16:53:03 UTC 2004
On Mon, 5 Jul 2004, Eric Blood wrote:
> [Long post follows]
> I am trying to create an application to run as a daemon at machine
> startup. It is going to include allegro serve, swank, and some of my
> own components. Here is my starting point:
> ;;; openmcl -l astest.lisp -e '(make-server)'
> (eval-when (:compile-toplevel :load-toplevel :execute)
> (require :aserve)
> (require :swank))
> (in-package :cl-user)
> (defclass server-application (ccl::lisp-development-system)
> (defmethod ccl::toplevel-function ((app server-application)
> (declare (ignore init-file))
> (swank:create-server :port 8001 :dont-close t)
> (net.aserve:start :port 8000)
> (process-suspend *current-process*))
> (defun make-server ()
> (ccl:save-application "aserver"
> :application-class (find-class 'server-application)
> :prepend-kernel t))
> First question, is doing a process suspend on the Initial process at
> the end of the toplevel-function a good thing?
QUIT is basically implemented as:
(process-interrupt *initial-process* #'(lambda (...)
If the initial process is suspended, it won't be able to respond to this
interrupt ... (There are some other reasons for wanting to avoid
PROCESS-SUSPEND unless it's really, really necessary.)
In the standard LISP-DEVELOPMENT-SYSTEM toplevel function, the initial
thread calls CCL::HOUSEKEEPING (which does some fairly important things
in the background.) In the next release, the things that it does will
probably be less critical, but it's probably desirable to follow that
> If I don't, the
> toplevel-function will be repeatedly called. This is mostly
> working--swank is opening a port, but not responding to the inital
> handshake, but I am looking into that.
> To go a step further, what is the best way to disassociate lisp from
> the terminal? Forcibly close the 0, 1, and 2 file descriptors? Or,
> is there something I can do with *terminal-io*.
You probably don't need to mess with *terminal-io*: it's basically
a two-way stream connected to file descriptors 0 and 1. If you
use something like #_dup2 to manipulate these descriptors, the lisp
streams will (probably) not know or care.
> I also have been playing around with forking the process:
> (defun fork-test (&optional exit)
> (let ((pid (#_getpid)))
> (dotimes (n 5)
> (format t "~A: ~A" pid n)
> (sleep 1)))
> (when exit
> (#_exit 0)))
> The two things that I observe is that the output from the parent
> process is displayed over 5 seconds, and then the child process's
> output follows immediately afterward. Some sort of locking?
I think that it's buffering: try calling FORCE-OUTPUT after TERPRI.
The HOUSEKEEPING function that the initial thread runs ordinarily
wakes up a few times a second and forces output on *TERMINAL-IO*.
This seems to only be happening in the parent process; apparently,
#_fork only clones the calling thread (so the child process doesn't
-have- an initial thread to do this. Or an excecption handling thread.
I have a hunch that if we tried harder we could force an unhandled
exception in the child.)
> And if I
> exit from the parent process, both the parent and child close. Is
> this behavior also terminal related? If so, I can understand the
> blocking of the child output, but why would the child process exit
> when the parent process exits?
If your FORK-TEST function is called with "exit" true, won't both
processes call #_exit ?
That said, I'm very skeptical that you can reliably do much in the
child (besides #_exit or some flavor of #_exec) after a #_fork in
Darwin. This may be true in general, but it's especially true in
OpenMCL (which depends on Mach thread-level exception handling and
other things that #_fork seems blissfully unaware of.)
More information about the Openmcl-devel