-The issue that single-threaded-ccl addresses is as follows.
+SINGLE-THREADED-CCL
+===================
+
+A simple patch to allow Clozure CL (CCL) to run in single-threaded mode.
+
+This is free software, available under the same license as CCL, LLGPL 2.1.
+
+
+Using It
+--------
+
+To create a single-threaded ccl, you may::
+
+ ${CCL_DEFAULT_DIRECTORY}/lx86cl64 --load make-single-threaded-ccl
+
+
+To test that indeed you can run code single-threaded mode, you may::
+
+ ./single-threaded-ccl --eval '(progn (format t "~S" ccl::*application*) (ccl::show-processes) (ccl:quit))'
+
+It your CCL is successfully single-threaded, only one process will show.
+
+
+Note that to be able to use many of the dynamically loaded features of CCL,
+you will need to either put your single-threaded-ccl in the same directory
+as the rest of CCL and use it from there, or you will need to::
+
+ export CCL_DEFAULT_DIRECTORY=/path/to/original-ccl
+
+
+If you build with ASDF, you may also depend on the system single-threaded-ccl,
+and when you next save an image, it will start single-threaded.
+
+
+Last Tested
+-----------
+
+It was last tested to run with this checkout of CCL, revision 15393.
+ http://svn.clozure.com/publicsvn/openmcl/trunk/linuxx86/ccl
+
+
+Won't Make It Upstream
+----------------------
+
+This was submitted for inclusion in the upstream CCL distribution.
+However, Gary Byers has expressed his disinterest in offering and maintaining
+an option for single-threaded startup in the upstream CCL,
+even when I proposed that I could do the porting and maintaining myself.
+
+
+
+Why We Need It
+--------------
CCL by default starts ancillary threads early during initialization,
-which makes any subsequent attempt to use fork (without a prompt exec
-as in run-program) almost guaranteed to lead to massive instability.
+which makes any subsequent attempt to use fork
+almost guaranteed to lead to massive instability
+(unless maybe it's promptly followed by exec, as in run-program,
+without a GC interrupt in between).
See my blog post:
http://fare.livejournal.com/148185.html
-However, I have been maintaining this "single-threaded CCL"
-modification that can create an image of CCL that doesn't start these
-ancillary threads (at the cost of having to manually flush output
-streams and of not being able to interrupt computations interactively
-with Ctrl-C).
-
-I use this single-threaded CCL for parallel build with POIU, and have
-had to update it once in a while as upstream upgrades sometimes break
-it. I also intend to use it in other situations where fork-based
-concurrency is called fork: pre-forking servers, robust erlang-style
-concurrency, isolating semi-trusted C libraries, etc.
-
-For the record, Gary Byers has expressed his disinterest in offering
-and maintaining an option for single-threaded startup in the upstream
-CCL, even when I proposed that I could do the porting and maintaining
-myself.
+However, I have been maintaining this "single-threaded CCL" modification
+that can create an image of CCL that doesn't start these ancillary threads
+(at the cost of having to manually flush output streams and
+of not being able to interrupt computations interactively with Ctrl-C).
+
+I use this single-threaded CCL for parallel build with POIU and XCVB,
+and have had to update it once in a while
+as upstream upgrades sometimes break it.
+I also intend to use it in other situations
+where fork-based concurrency is called for:
+pre-forking servers, robust erlang-style concurrency,
+isolating semi-trusted C libraries, etc.
--- /dev/null
+(module
+ (:fullname "single-threaded-ccl"
+ :depends-on ((:when (:featurep :clozure) "single-threaded-ccl"))
+ :supersedes-asdf ("single-threaded-ccl")))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; ;;;
-;;; Free Software under the GNU LLGPL 2.1 (same as CCL itself) ;;;
-;;; ;;;
-;;; Copyright (c) 2008-2011 ITA Software, Inc. All rights reserved. ;;;
-;;; ;;;
-;;; Original authors: Francois-Rene Rideau ;;;
-;;; ;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-#|
-This is a simple patch to allow Clozure CL (CCL) to run in single-threaded mode.
-
-It was last tested to run with this checkout of CCL, revision 13568 (same as 13679).
- http://svn.clozure.com/publicsvn/openmcl/branches/qres
-
-This is free software, available under the same license as CCL.
-
-Note: This was submitted for inclusion in the upstream CCL distribution.
-However, Gary Byers is unwilling to include and maintain this patch.
-
-To create a single-threaded ccl, you may:
- ${CCL_DEFAULT_DIRECTORY}/lx86cl64 --load make-single-threaded-ccl
-To test that indeed you can run code single-threaded mode, you may:
- ./single-threaded-ccl --eval '(progn (format t "~S" ccl::*application*) (ccl::show-processes) (ccl:quit))'
-
-Note that to be able to use many of the dynamically loaded features of CCL,
-you will need to either put your single-threaded-ccl in the same directory
-as the rest of CCL and use it from there, or you will need to
- export CCL_DEFAULT_DIRECTORY=/path/to/ccl
-|#
-
-(in-package :ccl)
-
-(defun finish-outputs ()
- (finish-output *standard-output*)
- (finish-output *error-output*)
- (finish-output *terminal-output*)
- (finish-output *trace-output*)
- (housekeeping))
-
-(defun show-processes ()
- (let ((p (all-processes)))
- (format t "~&Total number of running lisp processes: ~d~%~W~%" (length p) p)
- (finish-outputs)))
-
-(defun flushing-rep ()
- (print-listener-prompt *standard-output*)
- (finish-outputs)
- (let* ((eof '#.'#:eof)
- (sexp (read *standard-input* nil eof nil)))
- (when (eq sexp eof)
- (finish-outputs)
- (throw :flushing-rep-eof nil))
- ;; This use of eval is OK because it's part of the build infrastructure.
- (format t "~&~S~%" (eval sexp))
- (finish-outputs)))
-
-(defun flushing-repl ()
- (catch :flushing-rep-eof
- (loop (flushing-rep))))
-
-(defun single-threaded-toplevel ()
- (housekeeping)
- ;;(show-processes)
- ;;(flushing-repl)
- (listener-function)
- (quit 0))
-
-(defclass single-threaded-lisp-development-system (lisp-development-system)
- ())
-
-(defmethod repl-function-name ((a single-threaded-lisp-development-system))
- 'single-threaded-toplevel)
-
-(defmethod toplevel-function ((a single-threaded-lisp-development-system) init-file)
- (%set-toplevel (or (repl-function-name a) 'single-threaded-toplevel))
- (startup-ccl (and *load-lisp-init-file* init-file))
- (toplevel))
-
-(defparameter *application* (make-instance 'single-threaded-lisp-development-system))
+":" ; exec ccl --load "$@" ; exit 42
(in-package :cl-user)
-;;(save-application "single-threaded-ccl" :toplevel-function #'single-threaded-toplevel :prepend-kernel t)
+(load (merge-pathnames "single-threaded-ccl" *load-truename*))
-(save-application "single-threaded-ccl" :prepend-kernel t)
+(ccl:save-application
+ "single-threaded-ccl"
+ ;; :toplevel-function #'ccl::single-threaded-toplevel
+ :prepend-kernel t)
--- /dev/null
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; ;;;
+;;; Free Software under the GNU LLGPL 2.1 (same as CCL itself) ;;;
+;;; ;;;
+;;; Copyright (c) 2008-2011 ITA Software, Inc. All rights reserved. ;;;
+;;; Copyright (c) 2011-2012 Google, Inc. All rights reserved. ;;;
+;;; ;;;
+;;; Original authors: Francois-Rene Rideau ;;;
+;;; ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defsystem single-threaded-ccl
+ :license "LLGPL 2.1"
+ :components (#+clozure (:file "single-threaded-ccl")))
--- /dev/null
+#+xcvb (module ())
+
+(in-package :ccl)
+
+(defun finish-outputs ()
+ (finish-output *standard-output*)
+ (finish-output *error-output*)
+ (finish-output *terminal-output*)
+ (finish-output *trace-output*)
+ (housekeeping))
+
+(defun show-processes ()
+ (let ((p (all-processes)))
+ (format t "~&Total number of running lisp processes: ~d~%~W~%" (length p) p)
+ (finish-outputs)))
+
+(defun flushing-rep ()
+ (print-listener-prompt *standard-output*)
+ (finish-outputs)
+ (let* ((eof '#.'#:eof)
+ (sexp (read *standard-input* nil eof nil)))
+ (when (eq sexp eof)
+ (finish-outputs)
+ (throw :flushing-rep-eof nil))
+ ;; This use of eval is OK because it's part of the build infrastructure.
+ (format t "~&~S~%" (eval sexp))
+ (finish-outputs)))
+
+(defun flushing-repl ()
+ (catch :flushing-rep-eof
+ (loop (flushing-rep))))
+
+(defun single-threaded-toplevel ()
+ (housekeeping)
+ ;;(show-processes)
+ ;;(flushing-repl)
+ (listener-function)
+ (quit 0))
+
+(defclass single-threaded-lisp-development-system (lisp-development-system)
+ ())
+
+(defmethod repl-function-name ((a single-threaded-lisp-development-system))
+ 'single-threaded-toplevel)
+
+(defmethod toplevel-function ((a single-threaded-lisp-development-system) init-file)
+ (%set-toplevel (or (repl-function-name a) 'single-threaded-toplevel))
+ (startup-ccl (and *load-lisp-init-file* init-file))
+ (toplevel))
+
+(defparameter *application* (make-instance 'single-threaded-lisp-development-system))
+
+#|
+;; Use it as follows:
+(ccl::save-application
+ "single-threaded-ccl"
+ ;; :toplevel-function #'single-threaded-toplevel
+ :prepend-kernel t)
+|#