Permalink
Browse files

jvm improvements. allow forms successfully evaled before exceptions t…

…o be passed through in error or read-error response
  • Loading branch information...
1 parent 8a1405d commit d7891fec0d112018fe3471bbd9a30fe685a6460d @ninjudd ninjudd committed Jul 10, 2011
Showing with 71 additions and 45 deletions.
  1. +8 −5 client/ruby/portal.rb
  2. +31 −24 client/ruby/portal/jvm.rb
  3. +8 −0 client/ruby/portal/platform.rb
  4. +24 −16 src/portal/server.clj
View
@@ -1,9 +1,10 @@
require 'socket'
+require 'portal/platform'
+require 'portal/jvm'
require 'pp'
class Portal
class Error < StandardError; end
- class ReadError < Error; end
class ProtocolError < Error; end
RESULT_WAIT = 0.01
BLOCK_SIZE = 1024
@@ -71,10 +72,12 @@ def eval(form, id = @id || rand)
sleep(RESULT_WAIT)
end
type, form = context[:results][count - 1]
- case type
- when "error" then raise Error, form
- when "read-error" then raise ReadError, form
- when "result" then form.split("\n")
+ if type == "result"
+ form.split("\n")
+ else
+ vals = form.split("\n")
+ vals[-1] = {type.to_sym => vals[-1]}
+ vals
end
end
end
@@ -1,50 +1,57 @@
-require 'portal'
-require 'portal/platform'
-require 'pp'
-
class Portal
class JVM
attr_reader :args, :pidfile, :pid, :port
def initialize(pidfile, *args)
@pidfile = pidfile
@args = args
- refresh
- Process.kill(0, @pid) # make sure pid is valid
- TCPSocket.new("localhost", @port).close if @port # make sure jvm is running on port
- rescue Errno::ECONNREFUSED
- kill(true) # connection refused
- rescue Errno::ENOENT, Errno::ESRCH, Errno::ECONNREFUSED, Errno::EBADF, Errno::EPERM, Process::Error => e
- reset! # no pidfile or invalid pid
+ start
end
- def refresh
- _, @pid, @port = IO.read(pidfile).split("\n").collect {|n| n.to_i}
+ def start
+ init
+ return if @pid
+
+ @pid = daemon(cmd)
+ File.open(pidfile, 'w') {|f| f.write("#{cmd.join(' ')}\n#{@pid}\n")}
+
+ while @port.nil?
+ sleep 0.1
+ refresh
+ end
end
- def kill(force = false)
+ def stop(force = false)
if @pid
signal = force ? KILL : TERM
Process.kill(signal, @pid)
reset!
end
+ rescue Errno::ESRCH, Process::Error
+ end
+
+ def restart
+ stop
+ start
end
def cmd
@cmd ||= ["java", args, "-Dportal.pidfile=#{pidfile}", "clojure.main", "-e",
"(require 'portal.jvm) (portal.jvm/init)"].flatten.compact
end
- def start
- return if @pid
-
- @pid = daemon(cmd)
- File.open(pidfile, 'w') {|f| f.write("#{cmd.join(' ')}\n#{@pid}\n")}
+ def refresh
+ _, @pid, @port = IO.read(pidfile).split("\n").collect {|n| n.to_i}
+ end
- while @port.nil?
- sleep 0.1
- refresh
- end
+ def init
+ refresh
+ Process.kill(0, @pid) # make sure pid is valid
+ TCPSocket.new("localhost", @port).close if @port # make sure jvm is running on port
+ rescue Errno::ECONNREFUSED
+ kill(true) # connection refused
+ rescue Errno::ENOENT, Errno::ESRCH, Errno::ECONNREFUSED, Errno::EBADF, Errno::EPERM, Process::Error
+ reset! # no pidfile or invalid pid
end
def portal
@@ -55,7 +62,7 @@ def portal
def reset!
File.unlink(pidfile) if File.exists?(pidfile)
- @pid, @port = []
+ @pid, @port, @portal = []
end
end
@@ -2,12 +2,20 @@
require 'rubygems'
require 'win32/process'
+ TERM = 1
+ KILL = 'KILL'
+ PATH_SEP = ';'
+
USER_HOME = File.expand_path(ENV['HOMEDRIVE'] + ENV['HOMEPATH'])
def daemon(cmd)
Process.create(:app_name => cmd.join(' ')).process_id
end
else
+ TERM = 'TERM'
+ KILL = 'KILL'
+ PATH_SEP = ':'
+
USER_HOME = File.expand_path(ENV['HOME'])
class Process::Error; end
View
@@ -41,22 +41,30 @@
(dissoc contexts id)
contexts)))
-(defn prn-val [val]
- (set! *3 *2)
- (set! *2 *1)
- (set! *1 val)
- (prn-str val))
+(defn read-eval-print []
+ (try (let [form (read *in* false ::EOF)]
+ (when (not= ::EOF form)
+ (try (let [val (eval form)]
+ (set! *3 *2)
+ (set! *2 *1)
+ (set! *1 val)
+ (prn-str val))
+ (catch Exception e
+ (set! *e e)
+ (let [e (root-cause e)]
+ {:error (str (.getName (class e)) " " (.getMessage e))})))))
+ (catch LispReader$ReaderException e
+ (set! *e e)
+ {:read-error (.getMessage (root-cause e))})))
-(defn read-eval-print [data]
- (try (let [forms (read-seq data)]
- (try ["result" (apply str (map (comp prn-val eval) forms))]
- (catch Exception e
- (set! *e e)
- (let [e (root-cause e)]
- ["error" (str (.getName (class e)) " " (.getMessage e))]))))
- (catch LispReader$ReaderException e
- (set! *e e)
- ["read-error" (.getMessage (root-cause e))])))
+(defn read-eval-print-loop [string]
+ (with-in-str string
+ (let [[vals [{:keys [error read-error]}]]
+ (split-with string? (repeatedly read-eval-print))
+ result (apply str vals)]
+ (cond error ["error" (str result error)]
+ read-error ["read-error" (str result read-error)]
+ :else ["result" result]))))
(defn handler [channel client-info]
(receive-all channel
@@ -66,7 +74,7 @@
(print data)
(flush))
"eval" (with-context channel id
- (enqueue channel (apply vector id (read-eval-print data))))
+ (enqueue channel (apply vector id (read-eval-print-loop data))))
"fork" (swap! contexts
#(assoc % data (get % id)))
"close" (swap! contexts close-context channel id)

0 comments on commit d7891fe

Please sign in to comment.