Skip to content
fork.lisp 2.87 KiB
Newer Older
;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
;;;;; Forking

(in-package :philip-jose)

#-sbcl
(progn
  (defvar *expected-children 2.1)
  (defvar *expected-space* 16000000))

#+sbcl
(progn
  ;; Simple heuristic: if we have allocated more than the given ratio
  ;; of what is allowed between GCs, then trigger the GC.
  ;; note: can possibly modify parameters and reset in sb-ext:*after-gc-hooks*
  (defparameter *prefork-allocation-reserve-ratio* .10) ; default ratio: 10%
  (defun should-i-gc-p ()
    (let ((available-bytes (- (sb-alien:extern-alien "auto_gc_trigger" sb-alien:long)
                              (sb-kernel:dynamic-usage)))
          (allocation-threshhold (sb-ext:bytes-consed-between-gcs)))
      (< available-bytes (* *prefork-allocation-reserve-ratio* allocation-threshhold)))))

(defun pre-fork-hook ()
  #+sbcl
  (when (should-i-gc-p)
    (sb-ext:gc))
  nil)

(defun do-fork ()
  #-sbcl (et:fork)
  #+sbcl (sb-posix:fork))

(defun post-fork-child-cleanup ()
  nil)

(defun post-fork-parent-hook (pid)
  pid)

(defun fork ()
  (pre-fork-hook)
  (let ((pid (do-fork)))
    (if (zerop pid)
        (post-fork-child-cleanup)
        (post-fork-parent-hook pid))
    pid))


(defvar *cleanup-pusher* nil
  "dynamically-scoped function for declaring cleanups")
(defun push-cleanup (cleanup)
  (if *cleanup-pusher*
      (funcall *cleanup-pusher* cleanup)
      (error "No cleanup pusher declared")))
(defun call-with-cleanups (thunk)
  (let ((cleanups nil))
    (flet ((push-cleanup (cleanup) (push cleanup cleanups)))
      (unwind-protect
	   (funcall thunk #'push-cleanup)
	(dolist (cleanup cleanups)
	  (funcall cleanup))))))
(defun

(defun call-with-foreign-temporaries (thunk)
  (let (temporaries)
    (flet ((alloc (s)
	     (push s temporaries)))
      (unwind-protect
	   (funcall thunk alloc)
	(loop for s in temporaries do
	      (apply #'cffi:free-converted-object s)))))))

(defmacro with-foreign-temporaries (&body body)
  (with-gensyms (s)
    `(call-with-foreign-temporaries
      (lambda (,s)
	(macrolet ()
	  ,@body)))))

(cffi:defcenum frobork-kode
  :return
  :execve
  :dup2
  :close
  :fchdir
  :setuid
  :setgid
  :signal
  :setsid
  :setpgid
  :tcsetpgrp)

(cffi:defcfun (c-frobork "frobork") :int (kode :pointer))

(defun frobork-convert (v)
  (typecase v
    (integer
     v)
    (keyword
     
    (string
     (cffi:convert-to-foreign v :string))
    (integer
     v)



(defun frobork (kl)
  (let ((l (length kl)))
    (with-foreign-object (kode :int (1+ l))
      (let ((alloc-state
	     (loop with converted = nil
		   with state = nil
		   for i below l
		   for v in kl
		   do (multiple-value-setq (converted state)
			(frobork-convert v))
		   (setf (mem-aref kode :int i) converted)
		   when state
		   collect state)))
	(setf (mem-aref kode :int l) 0)
	(prog1
	    (c-frobork kode)
	  (loop for s in alloc-state
		do (apply #'cffi:free-converted-object s)))))))