1 ;;; RCLG: R-CommonLisp Gateway
4 ;;; Copyright (c) 2005--2007, <rif@mit.edu>
5 ;;; AJ Rossini <blindglobe@gmail.com>
6 ;;; All rights reserved.
8 ;;; Redistribution and use in source and binary forms, with or without
9 ;;; modification, are permitted provided that the following conditions are
12 ;;; * Redistributions of source code must retain the above copyright
13 ;;; notice, this list of conditions and the following disclaimer.
14 ;;; * Redistributions in binary form must reproduce the above
15 ;;; copyright notice, this list of conditions and the following disclaimer
16 ;;; in the documentation and/or other materials provided with the
18 ;;; * The names of the contributors may not be used to endorse or
19 ;;; promote products derived from this software without specific
20 ;;; prior written permission.
22 ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 ;;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 ;;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 ;;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 ;;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 ;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 ;;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 ;;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 ;;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 ;;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 ;;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 ;;; Author: rif@mit.edu
35 ;;; Maintainers: rif@mit.edu,
36 ;;; AJ Rossini <blindglobe@gmail.com>
38 ;;; Intent: R evaluator process initialization and maintenance. A
39 ;;; good deal of this is SBCL specific, and is flagged if so.
40 ;;; At some point, a means of handling non-SBCL variants will
42 ;;; But first things first.
45 ;; (start-rclg) ;; initializes RCLG functions.
46 ;; (update-R) ;; sync all threads
49 (defpackage :rclg-init
50 (:use
:common-lisp
:rclg-foreigns
:cffi
)
51 (:export
:start-rclg
:update-R
:*r-started
*
52 :start-rclg-update-thread
:stop-rclg-update-thread
53 :with-R-traps
:with-r-mutex
))
55 (in-package :rclg-init
)
58 (defvar *r-default-argv
*
59 '("rclg" "-q" "--vanilla" "--max-ppsize=50000")) ; last term to incr stack
60 (defvar *r-started
* nil
)
63 (defvar *do-rclg-updates-p
* nil
)
64 (defvar *rclg-update-sleep-time
* .1)
65 (defvar *rclg-update-mutex
*
66 #+sbcl
(sb-thread:make-mutex
)
71 (defmacro with-r-traps
(&body body
)
72 "Protect against R signaling wierdness to initialize the R REPL."
73 `(sb-int:with-float-traps-masked
(:invalid
:divide-by-zero
)
77 (defmacro with-r-mutex
(&body body
)
78 "FIXME:AJR: eval body in an mutex thread, updating as necessary. AJR is
79 not clear about the use-case for this macro."
80 `(sb-thread:with-mutex
(*rclg-update-mutex
*)
84 "Update and sync all SBCL threads containing R processes."
87 (%r-run-handlers
*r-input-handlers
*
88 (%r-check-activity
10000 0)))))
90 (defun start-rclg-update-thread ()
92 FIXME:AJR add use case for when/if needed at by a user."
93 (setf *do-rclg-updates-p
* t
)
95 (sb-thread:make-thread
97 (loop while
*do-rclg-updates-p
*
101 (sleep *rclg-update-sleep-time
*)))))
102 #+clisp
(error "not implemented yet")
103 #+cmu
(error "not implemented yet"))
106 (defun stop-rclg-update-thread ()
107 "FIXME: this was initially flagged as SBCL only, but it is more
108 generic. However, it isn't useful until implemented on other CL
110 (setf *do-rclg-updates-p
* nil
))
112 (defun string-sequence-to-foreign-string-array (string-sequence)
113 "CFFI-based conversion. Isn't there a new CFFI function for this?
114 FIXME:AJR: need to check."
115 (let ((n (length string-sequence
)))
116 (let ((foreign-array (foreign-alloc :pointer
:count n
)))
118 (setf (mem-aref foreign-array
:pointer i
)
119 (foreign-string-alloc (elt string-sequence i
))))
120 (values foreign-array n
))))
122 (defmacro with-foreign-string-array
123 ((name length str-array
) &body body
)
124 "CFFI-based conversion. Isn't this implemented in CFFI? FIXME:AJR:
126 (let ((ctr (gensym)))
127 `(multiple-value-bind (,name
,length
)
128 (string-sequence-to-foreign-string-array ,str-array
)
132 (dotimes (,ctr
,length
)
134 (mem-aref ,name
:pointer
,ctr
)))
135 (foreign-free ,name
))))))
137 ;; FIXME:AJR what is the point of the equiv comments? i.e. signed-long?
138 (defcvar ( "R_CStackLimit" *R-CSTACKLIMIT
*)
139 #-
:x86-64
:unsigned-long
140 #+:x86-64
:unsigned-long-long
)
141 (defcvar "R_SignalHandlers"
142 #-
:x86-64
:unsigned-long
143 #+:x86-64
:unsigned-long-long
)
145 (defun r-turn-off-signal-handling ()
146 "Turn of stack checking, based on changes present in 2.3.1 release."
147 (setf *R-SIGNALHANDLERS
* 0))
149 (defun r-turn-off-stack-checking ()
150 ;; (setf *R-CSTACKLIMIT* -1))
151 ;; This following is a complete hack since CFFI currently doesn't
152 ;; believe the above (it thinks that it's unsigned so upchucks)
153 (setf *R-CSTACKLIMIT
*
154 #-
:x86-64
#.
(- (expt 2 32) 1)
155 #+:x86-64
#.
(- (expt 2 64) 1)))
157 (defun check-stack ()
158 (format t
"STACK: LIMIT ~A, HANDLERS ~A~%"
159 *R-CSTACKLIMIT
* *R-SIGNALHANDLERS
*)
164 (defun start-rclg (&optional
(argv *r-default-argv
*))
165 "Initial the first R thread, perhaps with different arguments."
166 (r-turn-off-signal-handling)
169 #+sbcl
(sb-int:set-floating-point-modes
:traps
(list :overflow
))
172 (with-foreign-string-array (foreign-argv n argv
)
173 (%rf-initialize-r n foreign-argv
)
174 (r-turn-off-stack-checking)
176 #+sbcl
(start-rclg-update-thread)))))))
178 ;; FIXME:AJR: Do we really want to force this, or should we wait and
179 ;; let the user do this when appropriate?
180 ;; We let the user do it when ready.
182 ;;(eval-when (:load-toplevel)