Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
;;; -*- 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)))))))