[Openmcl-devel] creating a daemon
Eric Blood
eblood at winkywooster.org
Mon Jul 5 16:26:30 PDT 2004
On Jul 5, 2004, at 10:53, Gary Byers wrote:
> On Mon, 5 Jul 2004, Eric Blood wrote:
>> First question, is doing a process suspend on the Initial process at
>> the end of the toplevel-function a good thing?
>
> No.
> ...
> 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
> example.
I understand--looking at both l1-application.lisp and cocoa-window.lisp
I see the use of %SET-TOPLEVEL and TOPLEVEL. I have redone my example,
and this is working as expected:
(in-package :ccl)
(defclass server-application (application)
())
(defmethod toplevel-function ((app application) init-file)
(declare (ignore init-file))
(format t "aserver started (~D) at ~A~%"
(#_getpid) (get-universal-time))
(force-output)
(swank:create-server :port 8001 :dont-close t)
(net.aserve:start :port 8000)
(%set-toplevel #'(lambda ()
(with-standard-abort-handling nil
(loop
(%nanosleep *periodic-task-seconds*
*periodic-task-nanoseconds*)
(housekeeping)))))
(toplevel))
(in-package :cl-user)
(defun make-server ()
(ccl:save-application "aserver"
:application-class (find-class
'ccl::server-application)
:prepend-kernel t))
>> 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.
Ok, the following works:
(fd-close 0)
(fd-open "/dev/null" #$O_RDONLY)
(fd-close 1)
(fd-open "/tmp/openmcl.log" (logior #$O_WRONLY #$O_CREAT #$O_APPEND))
(fd-close 2)
(fd-open "/tmp/openmcl.log" (logior #$O_WRONLY #$O_APPEND))
>> [FORK-TEST]
>
> If your FORK-TEST function is called with "exit" true, won't both
> processes call #_exit ?
Yes, you are right. I fixed it, and it does show the listener exiting,
and the child process goes on printing out:
(defun fork-test (&optional exit)
(let* ((forked (#_fork))
(child (= forked 0))
(cycles (if child 10 5)))
(dotimes (n cycles)
(format t "~A: ~A~%" (#_getpid) n)
(force-output)
(sleep 1))
(when (and (not child) exit)
(#_exit 0))))
I took this example a step further and combined the fork and IO
redirection and created the following:
(in-package :ccl)
(defun daemonize ()
(when (/= 0 (#_fork))
(quit))
(fd-close 0)
(fd-open "/dev/null" #$O_RDONLY)
(fd-close 1)
(fd-open "/tmp/openmcl.log" (logior #$O_WRONLY #$O_CREAT
#$O_APPEND))
(fd-close 2)
(fd-open "/tmp/openmcl.log" (logior #$O_WRONLY #$O_APPEND))
(while t
(print (get-universal-time))
(force-output)
(sleep 1)))
This works... from the listener. However when I combine this with my
earlier application (having DAEMONIZE return after the last FD-OPEN
instead of doing the while loop), the output file is being created, but
the rest of the TOPLEVEL-FUNCTION doesn't appear to be executing.
(defmethod toplevel-function ((app application) init-file)
(declare (ignore init-file))
(daemonize)
(format t "aserver started (~D) at ~A~%" .......
> 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.)
Ok, I will dig deeper. Is there a good reference to Mach threads, or
Mach threads and their interaction with the BSD layer? I searched the
Apple Documentation, but didn't find a lot of useful stuff. In the
meantime I will use detachtty. =) Thanks for your help.
--
eblood
More information about the Openmcl-devel
mailing list