[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