ruby_process 0.0.9 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +98 -0
- data/Rakefile +2 -2
- data/RubyProcess.gemspec +88 -0
- data/VERSION +1 -1
- data/cmds/blocks.rb +18 -18
- data/cmds/marshal.rb +2 -2
- data/cmds/new.rb +13 -13
- data/cmds/numeric.rb +4 -4
- data/cmds/static.rb +10 -10
- data/cmds/str_eval.rb +4 -4
- data/cmds/system.rb +11 -11
- data/examples/example_csv.rb +13 -0
- data/examples/example_file_write.rb +2 -2
- data/examples/example_knj_db_dump.rb +7 -7
- data/examples/example_strscan.rb +3 -3
- data/include/args_handeling.rb +21 -21
- data/lib/ruby_process.rb +111 -105
- data/lib/{ruby_process_cproxy.rb → ruby_process/class_proxy.rb} +35 -35
- data/lib/{ruby_process_proxyobj.rb → ruby_process/proxy_object.rb} +18 -18
- data/ruby_process.gemspec +17 -10
- data/scripts/ruby_process_script.rb +7 -7
- data/shippable.yml +7 -0
- data/spec/class_proxy_spec.rb +95 -0
- data/spec/hard_load_spec.rb +13 -17
- data/spec/leaks_spec.rb +7 -7
- data/spec/ruby_process_spec.rb +75 -77
- data/spec/spec_helper.rb +3 -1
- metadata +60 -60
- data/README.rdoc +0 -19
- data/spec/cproxy_spec.rb +0 -101
    
        data/cmds/str_eval.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 | 
            -
            class  | 
| 1 | 
            +
            class RubyProcess
         | 
| 2 2 | 
             
              #Evalulates the given string in the process.
         | 
| 3 3 | 
             
              #===Examples
         | 
| 4 4 | 
             
              # rp.str_eval("return 10").__rp_marshal #=> 10
         | 
| 5 5 | 
             
              def str_eval(str)
         | 
| 6 | 
            -
                send(: | 
| 6 | 
            +
                send(cmd: :str_eval, str: str)
         | 
| 7 7 | 
             
              end
         | 
| 8 | 
            -
             | 
| 8 | 
            +
             | 
| 9 9 | 
             
              #Process-method for 'str_eval'.
         | 
| 10 10 | 
             
              def cmd_str_eval(obj)
         | 
| 11 11 | 
             
                #Lamda is used here because 'return' might be used in evalled code and thereby return an unhandeled object.
         | 
| @@ -13,4 +13,4 @@ class Ruby_process | |
| 13 13 | 
             
                  eval(obj[:str])
         | 
| 14 14 | 
             
                }.call)
         | 
| 15 15 | 
             
              end
         | 
| 16 | 
            -
            end
         | 
| 16 | 
            +
            end
         | 
    
        data/cmds/system.rb
    CHANGED
    
    | @@ -1,9 +1,9 @@ | |
| 1 | 
            -
            class  | 
| 1 | 
            +
            class RubyProcess
         | 
| 2 2 | 
             
              #Closes the process by executing exit.
         | 
| 3 3 | 
             
              def cmd_exit(obj)
         | 
| 4 4 | 
             
                exit
         | 
| 5 5 | 
             
              end
         | 
| 6 | 
            -
             | 
| 6 | 
            +
             | 
| 7 7 | 
             
              #Flushes various collected object-IDs to the subprocess, where they will be garbage-collected.
         | 
| 8 8 | 
             
              def flush_finalized
         | 
| 9 9 | 
             
                @flush_mutex.synchronize do
         | 
| @@ -11,37 +11,37 @@ class Ruby_process | |
| 11 11 | 
             
                  ids = @proxy_objs_unsets.shift(500)
         | 
| 12 12 | 
             
                  debug "IDS: #{ids} #{@proxy_objs_unsets}\n" if @debug
         | 
| 13 13 | 
             
                  return nil if ids.empty?
         | 
| 14 | 
            -
             | 
| 14 | 
            +
             | 
| 15 15 | 
             
                  debug "Ruby-process-debug: Finalizing (#{ids}).\n" if @debug
         | 
| 16 | 
            -
                  send(: | 
| 16 | 
            +
                  send(cmd: :flush_finalized, ids: ids)
         | 
| 17 17 | 
             
                  @finalize_count += ids.length
         | 
| 18 18 | 
             
                  return nil
         | 
| 19 19 | 
             
                end
         | 
| 20 20 | 
             
              end
         | 
| 21 | 
            -
             | 
| 21 | 
            +
             | 
| 22 22 | 
             
              #Flushes references to the given object IDs.
         | 
| 23 23 | 
             
              def cmd_flush_finalized(obj)
         | 
| 24 24 | 
             
                debug "Command-flushing finalized: '#{obj[:ids]}'.\n" if @debug
         | 
| 25 25 | 
             
                obj[:ids].each do |id|
         | 
| 26 | 
            -
                  raise "Unknown ID: '#{id}' (#{id.class.name})."  | 
| 26 | 
            +
                  raise "Unknown ID: '#{id}' (#{id.class.name})." unless @objects.key?(id)
         | 
| 27 27 | 
             
                  @objects.delete(id)
         | 
| 28 28 | 
             
                end
         | 
| 29 | 
            -
             | 
| 29 | 
            +
             | 
| 30 30 | 
             
                return nil
         | 
| 31 31 | 
             
              end
         | 
| 32 | 
            -
             | 
| 32 | 
            +
             | 
| 33 33 | 
             
              #Starts garbage-collecting and then flushes the finalized objects to the sub-process. Does the same thing in the sub-process.
         | 
| 34 34 | 
             
              def garbage_collect
         | 
| 35 35 | 
             
                GC.start
         | 
| 36 36 | 
             
                self.flush_finalized
         | 
| 37 | 
            -
                send(: | 
| 37 | 
            +
                send(cmd: :garbage_collect)
         | 
| 38 38 | 
             
                return nil
         | 
| 39 39 | 
             
              end
         | 
| 40 | 
            -
             | 
| 40 | 
            +
             | 
| 41 41 | 
             
              #The sub-process-side execution of 'garbage_collect'.
         | 
| 42 42 | 
             
              def cmd_garbage_collect(obj)
         | 
| 43 43 | 
             
                GC.start
         | 
| 44 44 | 
             
                self.flush_finalized
         | 
| 45 45 | 
             
                return nil
         | 
| 46 46 | 
             
              end
         | 
| 47 | 
            -
            end
         | 
| 47 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "rubygems"
         | 
| 4 | 
            +
            require "ruby_process"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            RubyProcess.new.spawn_process do |rp|
         | 
| 7 | 
            +
              rp.static(:Object, :require, "csv")
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              rp.static(:CSV, :open, "test.csv", "w") do |csv|
         | 
| 10 | 
            +
                csv << ["ID", "Name"]
         | 
| 11 | 
            +
                csv << [1, "Kasper"]
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -4,7 +4,7 @@ require "rubygems" | |
| 4 4 | 
             
            require "ruby_process"
         | 
| 5 5 |  | 
| 6 6 | 
             
            fpath = "/tmp/somefile"
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            RubyProcess.new.spawn_process do |rp|
         | 
| 8 8 | 
             
              #Opens file in subprocess.
         | 
| 9 9 | 
             
              rp.static(:File, :open, fpath, "w") do |fp|
         | 
| 10 10 | 
             
                #Writes to file in subprocess.
         | 
| @@ -12,4 +12,4 @@ Ruby_process.new.spawn_process do |rp| | |
| 12 12 | 
             
              end
         | 
| 13 13 | 
             
            end
         | 
| 14 14 |  | 
| 15 | 
            -
            print "Content of '#{fpath}': #{File.read(fpath)}\n"
         | 
| 15 | 
            +
            print "Content of '#{fpath}': #{File.read(fpath)}\n"
         | 
| @@ -23,17 +23,17 @@ threads = [] | |
| 23 23 | 
             
              threads << Thread.new do
         | 
| 24 24 | 
             
                begin
         | 
| 25 25 | 
             
                  thread_tables = tables.shift(tables_per_thread)
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                   | 
| 26 | 
            +
             | 
| 27 | 
            +
                  RubyProcess.new(debug: true).spawn_process do |rp|
         | 
| 28 28 | 
             
                    rp.static(:Object, :require, "rubygems")
         | 
| 29 29 | 
             
                    rp.static(:Object, :require, "knjrbfw")
         | 
| 30 | 
            -
             | 
| 30 | 
            +
             | 
| 31 31 | 
             
                    fpath = "/tmp/dbdump_#{i}.sql"
         | 
| 32 | 
            -
             | 
| 32 | 
            +
             | 
| 33 33 | 
             
                    thread_tables.each do |thread_db|
         | 
| 34 34 | 
             
                      rp_db = rp.new("Knj::Db", $db_settings)
         | 
| 35 | 
            -
                      rp_dump = rp.new("Knj::Db::Dump", : | 
| 36 | 
            -
             | 
| 35 | 
            +
                      rp_dump = rp.new("Knj::Db::Dump", db: rp_db, tables: thread_tables)
         | 
| 36 | 
            +
             | 
| 37 37 | 
             
                      rp.static(:File, :open, fpath, "w") do |rp_fp|
         | 
| 38 38 | 
             
                        print "#{i} dumping #{thread_db}\n"
         | 
| 39 39 | 
             
                        rp_dump.dump(rp_fp)
         | 
| @@ -49,4 +49,4 @@ end | |
| 49 49 |  | 
| 50 50 | 
             
            threads.each do |thread|
         | 
| 51 51 | 
             
              thread.join
         | 
| 52 | 
            -
            end
         | 
| 52 | 
            +
            end
         | 
    
        data/examples/example_strscan.rb
    CHANGED
    
    | @@ -3,12 +3,12 @@ | |
| 3 3 | 
             
            require "rubygems"
         | 
| 4 4 | 
             
            require "ruby_process"
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 6 | 
            +
            RubyProcess.new.spawn_process do |rp|
         | 
| 7 7 | 
             
              #Spawns string in the subprocess.
         | 
| 8 8 | 
             
              str = rp.new(:String, "Kasper is 26 years old")
         | 
| 9 | 
            -
             | 
| 9 | 
            +
             | 
| 10 10 | 
             
              #Scans with regex in subprocess, but yields proxy-objects in the current process.
         | 
| 11 11 | 
             
              str.scan(/is (\d+) years old/) do |match|
         | 
| 12 12 | 
             
                puts match.__rp_marshal
         | 
| 13 13 | 
             
              end
         | 
| 14 | 
            -
            end
         | 
| 14 | 
            +
            end
         | 
    
        data/include/args_handeling.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            class  | 
| 1 | 
            +
            class RubyProcess
         | 
| 2 2 | 
             
              #Recursivly parses arrays and hashes into proxy-object-hashes.
         | 
| 3 3 | 
             
              def parse_args(args)
         | 
| 4 4 | 
             
                if args.is_a?(Array)
         | 
| @@ -6,14 +6,14 @@ class Ruby_process | |
| 6 6 | 
             
                  args.each do |val|
         | 
| 7 7 | 
             
                    newarr << parse_args(val)
         | 
| 8 8 | 
             
                  end
         | 
| 9 | 
            -
             | 
| 9 | 
            +
             | 
| 10 10 | 
             
                  return newarr
         | 
| 11 11 | 
             
                elsif args.is_a?(Hash)
         | 
| 12 12 | 
             
                  newh = {}
         | 
| 13 13 | 
             
                  args.each do |key, val|
         | 
| 14 14 | 
             
                    newh[parse_args(key)] = parse_args(val)
         | 
| 15 15 | 
             
                  end
         | 
| 16 | 
            -
             | 
| 16 | 
            +
             | 
| 17 17 | 
             
                  return newh
         | 
| 18 18 | 
             
                elsif @args_allowed.index(args.class) != nil
         | 
| 19 19 | 
             
                  debug "Allowing type '#{args.class}' as an argument: '#{args}'.\n" if @debug
         | 
| @@ -23,38 +23,38 @@ class Ruby_process | |
| 23 23 | 
             
                  return handle_return_object(args)
         | 
| 24 24 | 
             
                end
         | 
| 25 25 | 
             
              end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            private
         | 
| 28 | 
            +
             | 
| 29 29 | 
             
              #Returns a special hash instead of an actual object. Some objects will be returned in their normal form (true, false and nil).
         | 
| 30 30 | 
             
              def handle_return_object(obj, pid = @my_pid)
         | 
| 31 31 | 
             
                #Dont proxy these objects.
         | 
| 32 32 | 
             
                return obj if obj.is_a?(TrueClass) or obj.is_a?(FalseClass) or obj.is_a?(NilClass)
         | 
| 33 | 
            -
             | 
| 33 | 
            +
             | 
| 34 34 | 
             
                #The object is a proxy-obj - just return its arguments that contains the true 'my_pid'.
         | 
| 35 | 
            -
                if obj.is_a?( | 
| 35 | 
            +
                if obj.is_a?(RubyProcess::ProxyObject)
         | 
| 36 36 | 
             
                  debug "Returning from proxy-obj: (ID: #{obj.args[:id]}, PID: #{obj.__rp_pid}).\n" if @debug
         | 
| 37 | 
            -
                  return {: | 
| 37 | 
            +
                  return {type: :proxy_obj, id: obj.__rp_id, pid: obj.__rp_pid}
         | 
| 38 38 | 
             
                end
         | 
| 39 | 
            -
             | 
| 39 | 
            +
             | 
| 40 40 | 
             
                #Check if object has already been spawned. If not: spawn id. Then returns hash for it.
         | 
| 41 41 | 
             
                id = obj.__id__
         | 
| 42 42 | 
             
                @objects[id] = obj if !@objects.key?(id)
         | 
| 43 | 
            -
             | 
| 43 | 
            +
             | 
| 44 44 | 
             
                debug "Proxy-object spawned (ID: #{id}, PID: #{pid}).\n" if @debug
         | 
| 45 | 
            -
                return {: | 
| 45 | 
            +
                return {type: :proxy_obj, id: id, pid: pid}
         | 
| 46 46 | 
             
              end
         | 
| 47 | 
            -
             | 
| 47 | 
            +
             | 
| 48 48 | 
             
              #Parses an argument array to proxy-object-hashes.
         | 
| 49 49 | 
             
              def handle_return_args(arr)
         | 
| 50 50 | 
             
                newa = []
         | 
| 51 51 | 
             
                arr.each do |obj|
         | 
| 52 52 | 
             
                  newa << handle_return_object(obj)
         | 
| 53 53 | 
             
                end
         | 
| 54 | 
            -
             | 
| 54 | 
            +
             | 
| 55 55 | 
             
                return newa
         | 
| 56 56 | 
             
              end
         | 
| 57 | 
            -
             | 
| 57 | 
            +
             | 
| 58 58 | 
             
              #Recursivly scans arrays and hashes for proxy-object-hashes and replaces them with actual proxy-objects.
         | 
| 59 59 | 
             
              def read_args(args)
         | 
| 60 60 | 
             
                if args.is_a?(Array)
         | 
| @@ -62,11 +62,11 @@ class Ruby_process | |
| 62 62 | 
             
                  args.each do |val|
         | 
| 63 63 | 
             
                    newarr << read_args(val)
         | 
| 64 64 | 
             
                  end
         | 
| 65 | 
            -
             | 
| 65 | 
            +
             | 
| 66 66 | 
             
                  return newarr
         | 
| 67 | 
            -
                elsif args.is_a?(Hash)  | 
| 67 | 
            +
                elsif args.is_a?(Hash) && args.length == 3 && args[:type] == :proxy_obj && args.key?(:id) && args.key?(:pid)
         | 
| 68 68 | 
             
                  debug "Comparing PID (#{args[:pid]}, #{@my_pid}).\n" if @debug
         | 
| 69 | 
            -
             | 
| 69 | 
            +
             | 
| 70 70 | 
             
                  if args[:pid] == @my_pid
         | 
| 71 71 | 
             
                    debug "Same!\n" if @debug
         | 
| 72 72 | 
             
                    return proxyobj_object(args[:id])
         | 
| @@ -79,10 +79,10 @@ class Ruby_process | |
| 79 79 | 
             
                  args.each do |key, val|
         | 
| 80 80 | 
             
                    newh[read_args(key)] = read_args(val)
         | 
| 81 81 | 
             
                  end
         | 
| 82 | 
            -
             | 
| 82 | 
            +
             | 
| 83 83 | 
             
                  return newh
         | 
| 84 84 | 
             
                end
         | 
| 85 | 
            -
             | 
| 85 | 
            +
             | 
| 86 86 | 
             
                return args
         | 
| 87 87 | 
             
              end
         | 
| 88 | 
            -
            end
         | 
| 88 | 
            +
            end
         | 
    
        data/lib/ruby_process.rb
    CHANGED
    
    | @@ -1,79 +1,85 @@ | |
| 1 1 | 
             
            require "rubygems"
         | 
| 2 | 
            -
            require "wref"  | 
| 3 | 
            -
            require "tsafe"  | 
| 2 | 
            +
            require "wref" unless Kernel.const_defined?(:Wref)
         | 
| 3 | 
            +
            require "tsafe" unless Kernel.const_defined?(:Tsafe)
         | 
| 4 4 | 
             
            require "base64"
         | 
| 5 | 
            +
            require "string-cases"
         | 
| 5 6 | 
             
            require "thread"
         | 
| 6 7 | 
             
            require "timeout"
         | 
| 7 8 |  | 
| 8 9 | 
             
            #This class can communicate with another Ruby-process. It tries to integrate the work in the other process as seamless as possible by using proxy-objects.
         | 
| 9 | 
            -
            class  | 
| 10 | 
            +
            class RubyProcess
         | 
| 10 11 | 
             
              attr_reader :finalize_count, :pid
         | 
| 11 | 
            -
             | 
| 12 | 
            +
             | 
| 12 13 | 
             
              #Require all the different commands.
         | 
| 13 14 | 
             
              dir = "#{File.dirname(__FILE__)}/../cmds"
         | 
| 14 15 | 
             
              Dir.foreach(dir) do |file|
         | 
| 15 16 | 
             
                require "#{dir}/#{file}" if file =~ /\.rb$/
         | 
| 16 17 | 
             
              end
         | 
| 17 | 
            -
             | 
| 18 | 
            +
             | 
| 18 19 | 
             
              #Methods for handeling arguments and proxy-objects in arguments.
         | 
| 19 20 | 
             
              require "#{File.dirname(__FILE__)}/../include/args_handeling.rb"
         | 
| 20 | 
            -
             | 
| 21 | 
            +
             | 
| 21 22 | 
             
              #Autoloader for subclasses.
         | 
| 22 23 | 
             
              def self.const_missing(name)
         | 
| 23 | 
            -
                 | 
| 24 | 
            -
             | 
| 25 | 
            -
                 | 
| 24 | 
            +
                file_path = "#{::File.realpath(::File.dirname(__FILE__))}/ruby_process/#{::StringCases.camel_to_snake(name)}.rb"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                if File.exists?(file_path)
         | 
| 27 | 
            +
                  require file_path
         | 
| 28 | 
            +
                  return const_get(name) if const_defined?(name)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                super
         | 
| 26 32 | 
             
              end
         | 
| 27 | 
            -
             | 
| 33 | 
            +
             | 
| 28 34 | 
             
              #Constructor.
         | 
| 29 35 | 
             
              #===Examples
         | 
| 30 | 
            -
              #  | 
| 36 | 
            +
              # RubyProcess.new.spawn_process do |rp|
         | 
| 31 37 | 
             
              #   str = rp.new(:String, "Kasper")
         | 
| 32 38 | 
             
              # end
         | 
| 33 39 | 
             
              def initialize(args = {})
         | 
| 34 40 | 
             
                @args = args
         | 
| 35 41 | 
             
                @debug = @args[:debug]
         | 
| 36 42 | 
             
                @pid = @args[:pid]
         | 
| 37 | 
            -
             | 
| 43 | 
            +
             | 
| 38 44 | 
             
                #These classes are allowed in call-arguments. They can be marshalled without any errors.
         | 
| 39 45 | 
             
                @args_allowed = [FalseClass, Fixnum, Integer, NilClass, String, Symbol, TrueClass]
         | 
| 40 | 
            -
             | 
| 46 | 
            +
             | 
| 41 47 | 
             
                #Set IO variables if given.
         | 
| 42 | 
            -
                @io_out = Tsafe::Proxy.new(: | 
| 48 | 
            +
                @io_out = Tsafe::Proxy.new(obj: @args[:out]) if @args[:out]
         | 
| 43 49 | 
             
                @io_in = @args[:in] if @args[:in]
         | 
| 44 50 | 
             
                @io_err = @args[:err] if @args[:err]
         | 
| 45 | 
            -
             | 
| 51 | 
            +
             | 
| 46 52 | 
             
                #This hash holds answers coming from the subprocess.
         | 
| 47 53 | 
             
                @answers = Tsafe::MonHash.new
         | 
| 48 | 
            -
             | 
| 54 | 
            +
             | 
| 49 55 | 
             
                #This hash holds objects that are referenced in the process.
         | 
| 50 56 | 
             
                @objects = Tsafe::MonHash.new
         | 
| 51 | 
            -
             | 
| 57 | 
            +
             | 
| 52 58 | 
             
                #This weak-map holds all proxy objects.
         | 
| 53 59 | 
             
                @proxy_objs = Wref_map.new
         | 
| 54 60 | 
             
                @proxy_objs_ids = Tsafe::MonHash.new
         | 
| 55 61 | 
             
                @proxy_objs_unsets = Tsafe::MonArray.new
         | 
| 56 62 | 
             
                @flush_mutex = Mutex.new
         | 
| 57 63 | 
             
                @finalize_count = 0
         | 
| 58 | 
            -
             | 
| 64 | 
            +
             | 
| 59 65 | 
             
                #Send ID is used to identify the correct answers.
         | 
| 60 66 | 
             
                @send_mutex = Mutex.new
         | 
| 61 67 | 
             
                @send_count = 0
         | 
| 62 | 
            -
             | 
| 68 | 
            +
             | 
| 63 69 | 
             
                #The PID is used to know which process proxy-objects belongs to.
         | 
| 64 70 | 
             
                @my_pid = Process.pid
         | 
| 65 71 | 
             
              end
         | 
| 66 | 
            -
             | 
| 72 | 
            +
             | 
| 67 73 | 
             
              #Spawns a new process in the same Ruby-inteterpeter as the current one.
         | 
| 68 74 | 
             
              #===Examples
         | 
| 69 | 
            -
              # rp =  | 
| 75 | 
            +
              # rp = RubyProcess.new.spawn_process
         | 
| 70 76 | 
             
              # rp.str_eval("return 10").__rp_marshal #=> 10
         | 
| 71 77 | 
             
              # rp.destroy
         | 
| 72 78 | 
             
              def spawn_process(args = nil)
         | 
| 73 79 | 
             
                #Used for printing debug-stuff.
         | 
| 74 80 | 
             
                @main = true
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                if args  | 
| 81 | 
            +
             | 
| 82 | 
            +
                if args && args[:exec]
         | 
| 77 83 | 
             
                  cmd = "#{args[:exec]}"
         | 
| 78 84 | 
             
                else
         | 
| 79 85 | 
             
                  if !ENV["rvm_ruby_string"].to_s.empty?
         | 
| @@ -82,82 +88,82 @@ class Ruby_process | |
| 82 88 | 
             
                    cmd = "ruby"
         | 
| 83 89 | 
             
                  end
         | 
| 84 90 | 
             
                end
         | 
| 85 | 
            -
             | 
| 91 | 
            +
             | 
| 86 92 | 
             
                cmd << " \"#{File.realpath(File.dirname(__FILE__))}/../scripts/ruby_process_script.rb\" --pid=#{@my_pid}"
         | 
| 87 93 | 
             
                cmd << " --debug" if @args[:debug]
         | 
| 88 94 | 
             
                cmd << " \"--title=#{@args[:title]}\"" if !@args[:title].to_s.strip.empty?
         | 
| 89 | 
            -
             | 
| 95 | 
            +
             | 
| 90 96 | 
             
                #Start process and set IO variables.
         | 
| 91 97 | 
             
                require "open3"
         | 
| 92 98 | 
             
                @io_out, @io_in, @io_err = Open3.popen3(cmd)
         | 
| 93 | 
            -
                @io_out = Tsafe::Proxy.new(: | 
| 99 | 
            +
                @io_out = Tsafe::Proxy.new(obj: @io_out)
         | 
| 94 100 | 
             
                @io_out.sync = true
         | 
| 95 101 | 
             
                @io_in.sync = true
         | 
| 96 102 | 
             
                @io_err.sync = true
         | 
| 97 | 
            -
             | 
| 103 | 
            +
             | 
| 98 104 | 
             
                started = false
         | 
| 99 105 | 
             
                @io_in.each_line do |str|
         | 
| 100 106 | 
             
                  if str == "ruby_process_started\n"
         | 
| 101 107 | 
             
                    started = true
         | 
| 102 108 | 
             
                    break
         | 
| 103 109 | 
             
                  end
         | 
| 104 | 
            -
             | 
| 110 | 
            +
             | 
| 105 111 | 
             
                  debug "Ruby-process-debug from stdout before started: '#{str}'\n" if @debug
         | 
| 106 112 | 
             
                end
         | 
| 107 | 
            -
             | 
| 108 | 
            -
                raise "Ruby-sub-process couldnt start: '#{@io_err.read}'."  | 
| 113 | 
            +
             | 
| 114 | 
            +
                raise "Ruby-sub-process couldnt start: '#{@io_err.read}'." unless started
         | 
| 109 115 | 
             
                self.listen
         | 
| 110 | 
            -
             | 
| 116 | 
            +
             | 
| 111 117 | 
             
                #Start by getting the PID of the process.
         | 
| 112 118 | 
             
                begin
         | 
| 113 119 | 
             
                  @pid = self.static(:Process, :pid).__rp_marshal
         | 
| 114 | 
            -
                  raise "Unexpected PID: '#{@pid}'." if !@pid.is_a?(Fixnum)  | 
| 120 | 
            +
                  raise "Unexpected PID: '#{@pid}'." if !@pid.is_a?(Fixnum) && !@pid.is_a?(Integer)
         | 
| 115 121 | 
             
                rescue => e
         | 
| 116 122 | 
             
                  self.destroy
         | 
| 117 123 | 
             
                  raise e
         | 
| 118 124 | 
             
                end
         | 
| 119 | 
            -
             | 
| 125 | 
            +
             | 
| 120 126 | 
             
                if block_given?
         | 
| 121 127 | 
             
                  begin
         | 
| 122 128 | 
             
                    yield(self)
         | 
| 123 129 | 
             
                  ensure
         | 
| 124 130 | 
             
                    self.destroy
         | 
| 125 131 | 
             
                  end
         | 
| 126 | 
            -
             | 
| 132 | 
            +
             | 
| 127 133 | 
             
                  return self
         | 
| 128 134 | 
             
                else
         | 
| 129 135 | 
             
                  return self
         | 
| 130 136 | 
             
                end
         | 
| 131 137 | 
             
              end
         | 
| 132 | 
            -
             | 
| 138 | 
            +
             | 
| 133 139 | 
             
              #Starts listening on the given IO's. It is useally not needed to call this method manually.
         | 
| 134 140 | 
             
              def listen
         | 
| 135 141 | 
             
                #Start listening for input.
         | 
| 136 142 | 
             
                start_listen
         | 
| 137 | 
            -
             | 
| 143 | 
            +
             | 
| 138 144 | 
             
                #Start listening for errors.
         | 
| 139 145 | 
             
                start_listen_errors
         | 
| 140 146 | 
             
              end
         | 
| 141 | 
            -
             | 
| 147 | 
            +
             | 
| 142 148 | 
             
              #First tries to make the sub-process exit gently. Then kills it with "TERM" and 9 afterwards to make sure its dead. If 'spawn_process' is given a block, this method is automatically ensured after the block is run.
         | 
| 143 149 | 
             
              def destroy
         | 
| 144 150 | 
             
                return nil if self.destroyed?
         | 
| 145 | 
            -
             | 
| 151 | 
            +
             | 
| 146 152 | 
             
                debug "Destroying Ruby-process (#{caller}).\n" if @debug
         | 
| 147 153 | 
             
                pid = @pid
         | 
| 148 154 | 
             
                tries = 0
         | 
| 149 | 
            -
             | 
| 155 | 
            +
             | 
| 150 156 | 
             
                #Make main kill it and make sure its dead...
         | 
| 151 157 | 
             
                begin
         | 
| 152 | 
            -
                  if @main  | 
| 158 | 
            +
                  if @main && @pid
         | 
| 153 159 | 
             
                    tries += 1
         | 
| 154 160 | 
             
                    Process.kill("TERM", pid) rescue Errno::ESRCH
         | 
| 155 | 
            -
             | 
| 161 | 
            +
             | 
| 156 162 | 
             
                    #Ensure subprocess is dead.
         | 
| 157 163 | 
             
                    begin
         | 
| 158 164 | 
             
                      Timeout.timeout(1) do
         | 
| 159 165 | 
             
                        sleep 0.01
         | 
| 160 | 
            -
             | 
| 166 | 
            +
             | 
| 161 167 | 
             
                        loop do
         | 
| 162 168 | 
             
                          begin
         | 
| 163 169 | 
             
                            Process.getpgid(pid)
         | 
| @@ -165,7 +171,7 @@ class Ruby_process | |
| 165 171 | 
             
                          rescue Errno::ESRCH
         | 
| 166 172 | 
             
                            alive = false
         | 
| 167 173 | 
             
                          end
         | 
| 168 | 
            -
             | 
| 174 | 
            +
             | 
| 169 175 | 
             
                          break if !alive
         | 
| 170 176 | 
             
                        end
         | 
| 171 177 | 
             
                      end
         | 
| @@ -178,74 +184,74 @@ class Ruby_process | |
| 178 184 | 
             
                  #Process is already dead - ignore.
         | 
| 179 185 | 
             
                ensure
         | 
| 180 186 | 
             
                  @pid = nil
         | 
| 181 | 
            -
             | 
| 187 | 
            +
             | 
| 182 188 | 
             
                  @io_out.close if @io_out && !@io_out.closed?
         | 
| 183 189 | 
             
                  @io_out = nil
         | 
| 184 | 
            -
             | 
| 190 | 
            +
             | 
| 185 191 | 
             
                  @io_in.close if @io_in && !@io_in.closed?
         | 
| 186 192 | 
             
                  @io_in = nil
         | 
| 187 | 
            -
             | 
| 193 | 
            +
             | 
| 188 194 | 
             
                  @io_err if @io_err && !@io_err.closed?
         | 
| 189 195 | 
             
                  @io_err = nil
         | 
| 190 | 
            -
             | 
| 196 | 
            +
             | 
| 191 197 | 
             
                  @main = nil
         | 
| 192 198 | 
             
                end
         | 
| 193 | 
            -
             | 
| 199 | 
            +
             | 
| 194 200 | 
             
                return nil
         | 
| 195 201 | 
             
              end
         | 
| 196 | 
            -
             | 
| 202 | 
            +
             | 
| 197 203 | 
             
              #Returns true if the Ruby process has been destroyed.
         | 
| 198 204 | 
             
              def destroyed?
         | 
| 199 | 
            -
                return true if !@pid  | 
| 205 | 
            +
                return true if !@pid && !@io_out && !@io_in && !@io_err && @main == nil
         | 
| 200 206 | 
             
                return false
         | 
| 201 207 | 
             
              end
         | 
| 202 | 
            -
             | 
| 208 | 
            +
             | 
| 203 209 | 
             
              #Joins the listen thread and error-thread. This is useually only called on the sub-process side, but can also be useful, if you are waiting for a delayed callback from the subprocess.
         | 
| 204 210 | 
             
              def join
         | 
| 205 211 | 
             
                debug "Joining listen-thread.\n" if @debug
         | 
| 206 212 | 
             
                @thr_listen.join if @thr_listen
         | 
| 207 213 | 
             
                raise @listen_err if @listen_err
         | 
| 208 | 
            -
             | 
| 214 | 
            +
             | 
| 209 215 | 
             
                debug "Joining error-thread.\n" if @debug
         | 
| 210 216 | 
             
                @thr_err.join if @thr_join
         | 
| 211 217 | 
             
                raise @listen_err_err if @listen_err_err
         | 
| 212 218 | 
             
              end
         | 
| 213 | 
            -
             | 
| 219 | 
            +
             | 
| 214 220 | 
             
              #Sends a command to the other process. This should not be called manually, but is used by various other parts of the framework.
         | 
| 215 221 | 
             
              def send(obj, &block)
         | 
| 216 222 | 
             
                alive_check!
         | 
| 217 | 
            -
             | 
| 223 | 
            +
             | 
| 218 224 | 
             
                #Sync ID stuff so they dont get mixed up.
         | 
| 219 225 | 
             
                id = nil
         | 
| 220 226 | 
             
                @send_mutex.synchronize do
         | 
| 221 227 | 
             
                  id = @send_count
         | 
| 222 228 | 
             
                  @send_count += 1
         | 
| 223 229 | 
             
                end
         | 
| 224 | 
            -
             | 
| 230 | 
            +
             | 
| 225 231 | 
             
                #Parse block.
         | 
| 226 232 | 
             
                if block
         | 
| 227 | 
            -
                  block_proxy_res = self.send(: | 
| 233 | 
            +
                  block_proxy_res = self.send(cmd: :spawn_proxy_block, id: block.__id__, answer_id: id)
         | 
| 228 234 | 
             
                  block_proxy_res_id = block_proxy_res[:id]
         | 
| 229 | 
            -
                  raise "No block ID was returned?"  | 
| 235 | 
            +
                  raise "No block ID was returned?" unless block_proxy_res_id
         | 
| 230 236 | 
             
                  raise "Invalid block-ID: '#{block_proxy_res_id}'." if block_proxy_res_id.to_i <= 0
         | 
| 231 237 | 
             
                  @proxy_objs[block_proxy_res_id] = block
         | 
| 232 238 | 
             
                  @proxy_objs_ids[block.__id__] = block_proxy_res_id
         | 
| 233 239 | 
             
                  ObjectSpace.define_finalizer(block, self.method(:proxyobj_finalizer))
         | 
| 234 240 | 
             
                  obj[:block] = {
         | 
| 235 | 
            -
                    : | 
| 236 | 
            -
                    : | 
| 241 | 
            +
                    id: block_proxy_res_id,
         | 
| 242 | 
            +
                    arity: block.arity
         | 
| 237 243 | 
             
                  }
         | 
| 238 244 | 
             
                end
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                flush_finalized  | 
| 241 | 
            -
             | 
| 245 | 
            +
             | 
| 246 | 
            +
                flush_finalized unless obj[:cmd] == :flush_finalized
         | 
| 247 | 
            +
             | 
| 242 248 | 
             
                debug "Sending(#{id}): #{obj}\n" if @debug
         | 
| 243 249 | 
             
                line = Base64.strict_encode64(Marshal.dump(
         | 
| 244 | 
            -
                  : | 
| 245 | 
            -
                  : | 
| 246 | 
            -
                  : | 
| 250 | 
            +
                  id: id,
         | 
| 251 | 
            +
                  type: :send,
         | 
| 252 | 
            +
                  obj: obj
         | 
| 247 253 | 
             
                ))
         | 
| 248 | 
            -
             | 
| 254 | 
            +
             | 
| 249 255 | 
             
                begin
         | 
| 250 256 | 
             
                  @answers[id] = Queue.new
         | 
| 251 257 | 
             
                  @io_out.puts(line)
         | 
| @@ -255,7 +261,7 @@ class Ruby_process | |
| 255 261 | 
             
                  @answers.delete(id)
         | 
| 256 262 | 
             
                end
         | 
| 257 263 | 
             
              end
         | 
| 258 | 
            -
             | 
| 264 | 
            +
             | 
| 259 265 | 
             
              #Returns true if the child process is still running. Otherwise false.
         | 
| 260 266 | 
             
              def alive?
         | 
| 261 267 | 
             
                begin
         | 
| @@ -265,9 +271,9 @@ class Ruby_process | |
| 265 271 | 
             
                  return false
         | 
| 266 272 | 
             
                end
         | 
| 267 273 | 
             
              end
         | 
| 268 | 
            -
             | 
| 274 | 
            +
             | 
| 269 275 | 
             
              private
         | 
| 270 | 
            -
             | 
| 276 | 
            +
             | 
| 271 277 | 
             
              #Raises an error if the subprocess is no longer alive.
         | 
| 272 278 | 
             
              def alive_check!
         | 
| 273 279 | 
             
                raise "Has been destroyed." if self.destroyed?
         | 
| @@ -276,14 +282,14 @@ class Ruby_process | |
| 276 282 | 
             
                raise "'io_in' was closed." if @io_in.closed?
         | 
| 277 283 | 
             
                raise "No listen thread." if !@thr_listen
         | 
| 278 284 | 
             
                #raise "Listen thread wasnt alive?" if !@thr_listen.alive?
         | 
| 279 | 
            -
             | 
| 285 | 
            +
             | 
| 280 286 | 
             
                return nil
         | 
| 281 287 | 
             
              end
         | 
| 282 | 
            -
             | 
| 288 | 
            +
             | 
| 283 289 | 
             
              #Prints the given string to stderr. Raises error if debugging is not enabled.
         | 
| 284 290 | 
             
              def debug(str_full)
         | 
| 285 | 
            -
                raise "Debug not enabled?"  | 
| 286 | 
            -
             | 
| 291 | 
            +
                raise "Debug not enabled?" unless @debug
         | 
| 292 | 
            +
             | 
| 287 293 | 
             
                str_full.each_line do |str|
         | 
| 288 294 | 
             
                  if @main
         | 
| 289 295 | 
             
                    $stderr.print "(M#{@my_pid}) #{str}"
         | 
| @@ -292,54 +298,54 @@ class Ruby_process | |
| 292 298 | 
             
                  end
         | 
| 293 299 | 
             
                end
         | 
| 294 300 | 
             
              end
         | 
| 295 | 
            -
             | 
| 301 | 
            +
             | 
| 296 302 | 
             
              #Registers an object ID as a proxy-object on the host-side.
         | 
| 297 303 | 
             
              def proxyobj_get(id, pid = @my_pid)
         | 
| 298 304 | 
             
                if proxy_obj = @proxy_objs.get!(id)
         | 
| 299 305 | 
             
                  debug "Reuse proxy-obj (ID: #{id}, PID: #{pid}, fID: #{proxy_obj.args[:id]}, fPID: #{proxy_obj.args[:pid]})\n" if @debug
         | 
| 300 306 | 
             
                  return proxy_obj
         | 
| 301 307 | 
             
                end
         | 
| 302 | 
            -
             | 
| 308 | 
            +
             | 
| 303 309 | 
             
                @proxy_objs_unsets.delete(id)
         | 
| 304 | 
            -
                proxy_obj =  | 
| 310 | 
            +
                proxy_obj = RubyProcess::ProxyObject.new(self, id, pid)
         | 
| 305 311 | 
             
                @proxy_objs[id] = proxy_obj
         | 
| 306 312 | 
             
                @proxy_objs_ids[proxy_obj.__id__] = id
         | 
| 307 313 | 
             
                ObjectSpace.define_finalizer(proxy_obj, self.method(:proxyobj_finalizer))
         | 
| 308 | 
            -
             | 
| 314 | 
            +
             | 
| 309 315 | 
             
                return proxy_obj
         | 
| 310 316 | 
             
              end
         | 
| 311 | 
            -
             | 
| 317 | 
            +
             | 
| 312 318 | 
             
              #Returns the saved proxy-object by the given ID. Raises error if it doesnt exist.
         | 
| 313 319 | 
             
              def proxyobj_object(id)
         | 
| 314 320 | 
             
                if obj = @objects[id]
         | 
| 315 321 | 
             
                  return obj
         | 
| 316 322 | 
             
                end
         | 
| 317 | 
            -
             | 
| 323 | 
            +
             | 
| 318 324 | 
             
                raise "No object by that ID: '#{id}' (#{@objects})."
         | 
| 319 325 | 
             
              end
         | 
| 320 | 
            -
             | 
| 326 | 
            +
             | 
| 321 327 | 
             
              #Method used for detecting garbage-collected proxy-objects. This way we can also free references to them in the other process, so it doesnt run out of memory.
         | 
| 322 328 | 
             
              def proxyobj_finalizer(id)
         | 
| 323 329 | 
             
                debug "Finalized #{id}\n" if @debug
         | 
| 324 330 | 
             
                proxy_id = @proxy_objs_ids[id]
         | 
| 325 | 
            -
             | 
| 331 | 
            +
             | 
| 326 332 | 
             
                if !proxy_id
         | 
| 327 333 | 
             
                  debug "No such ID in proxy objects IDs hash: '#{id}'.\n" if @debug
         | 
| 328 334 | 
             
                else
         | 
| 329 335 | 
             
                  @proxy_objs_unsets << proxy_id
         | 
| 330 336 | 
             
                  debug "Done finalizing #{id}\n" if @debug
         | 
| 331 337 | 
             
                end
         | 
| 332 | 
            -
             | 
| 338 | 
            +
             | 
| 333 339 | 
             
                return nil
         | 
| 334 340 | 
             
              end
         | 
| 335 | 
            -
             | 
| 341 | 
            +
             | 
| 336 342 | 
             
              #Waits for an answer to appear in the answers-hash. Then deletes it from hash and returns it.
         | 
| 337 343 | 
             
              def answer_read(id)
         | 
| 338 344 | 
             
                loop do
         | 
| 339 345 | 
             
                  debug "Waiting for answer #{id}\n" if @debug
         | 
| 340 346 | 
             
                  answer = @answers[id].pop
         | 
| 341 347 | 
             
                  debug "Returning answer #{id}\n" if @debug
         | 
| 342 | 
            -
             | 
| 348 | 
            +
             | 
| 343 349 | 
             
                  if answer.is_a?(Hash) and type = answer[:type]
         | 
| 344 350 | 
             
                    if type == :error and class_str = answer[:class] and msg = answer[:msg] and bt_orig = answer[:bt]
         | 
| 345 351 | 
             
                      begin
         | 
| @@ -349,17 +355,17 @@ class Ruby_process | |
| 349 355 | 
             
                        bt_orig.each do |btline|
         | 
| 350 356 | 
             
                          bt << "(#{@pid}): #{btline}"
         | 
| 351 357 | 
             
                        end
         | 
| 352 | 
            -
             | 
| 358 | 
            +
             | 
| 353 359 | 
             
                        bt += e.backtrace
         | 
| 354 360 | 
             
                        e.set_backtrace(bt)
         | 
| 355 361 | 
             
                        raise e
         | 
| 356 362 | 
             
                      end
         | 
| 357 | 
            -
                    elsif type == :proxy_obj  | 
| 363 | 
            +
                    elsif type == :proxy_obj && id = answer[:id] and pid = answer[:pid]
         | 
| 358 364 | 
             
                      return proxyobj_get(id, pid)
         | 
| 359 365 | 
             
                    elsif type == :proxy_block_call and block = answer[:block] and args = answer[:args] and queue = answer[:queue]
         | 
| 360 366 | 
             
                      #Calls the block. This is used to call the block from the same thread that the answer is being read from. This can cause problems in Hayabusa, that uses thread-variables to determine output and such.
         | 
| 361 367 | 
             
                      block.call(*args)
         | 
| 362 | 
            -
             | 
| 368 | 
            +
             | 
| 363 369 | 
             
                      #Tells the parent thread that the block has been executed and it should continue.
         | 
| 364 370 | 
             
                      queue << true
         | 
| 365 371 | 
             
                    else
         | 
| @@ -369,19 +375,19 @@ class Ruby_process | |
| 369 375 | 
             
                    return answer
         | 
| 370 376 | 
             
                  end
         | 
| 371 377 | 
             
                end
         | 
| 372 | 
            -
             | 
| 378 | 
            +
             | 
| 373 379 | 
             
                raise "This should never be reached."
         | 
| 374 380 | 
             
              end
         | 
| 375 | 
            -
             | 
| 381 | 
            +
             | 
| 376 382 | 
             
              #Starts the listen-thread that listens for, and executes, commands. This is normally automatically called and should not be called manually.
         | 
| 377 383 | 
             
              def start_listen
         | 
| 378 384 | 
             
                @thr_listen = Thread.new do
         | 
| 379 385 | 
             
                  begin
         | 
| 380 386 | 
             
                    @io_in.each_line do |line|
         | 
| 381 | 
            -
                      raise "No line?" if !line  | 
| 387 | 
            +
                      raise "No line?" if !line || line.to_s.strip.empty?
         | 
| 382 388 | 
             
                      alive_check!
         | 
| 383 389 | 
             
                      debug "Received: #{line}" if @debug
         | 
| 384 | 
            -
             | 
| 390 | 
            +
             | 
| 385 391 | 
             
                      begin
         | 
| 386 392 | 
             
                        obj = Marshal.load(Base64.strict_decode64(line.strip))
         | 
| 387 393 | 
             
                        debug "Object received: #{obj}\n" if @debug
         | 
| @@ -389,28 +395,28 @@ class Ruby_process | |
| 389 395 | 
             
                        $stderr.puts "Base64Str: #{line}" if @debug
         | 
| 390 396 | 
             
                        $stderr.puts e.inspect if @debug
         | 
| 391 397 | 
             
                        $stderr.puts e.backtrace if @debug
         | 
| 392 | 
            -
             | 
| 398 | 
            +
             | 
| 393 399 | 
             
                        raise e
         | 
| 394 400 | 
             
                      end
         | 
| 395 | 
            -
             | 
| 401 | 
            +
             | 
| 396 402 | 
             
                      id = obj[:id]
         | 
| 397 403 | 
             
                      obj_type = obj[:type]
         | 
| 398 | 
            -
             | 
| 404 | 
            +
             | 
| 399 405 | 
             
                      if obj_type == :send
         | 
| 400 406 | 
             
                        Thread.new do
         | 
| 401 407 | 
             
                          #Hack to be able to do callbacks from same thread when using blocks. This should properly be cleaned a bit up in the future.
         | 
| 402 408 | 
             
                          obj[:obj][:send_id] = id
         | 
| 403 | 
            -
             | 
| 409 | 
            +
             | 
| 404 410 | 
             
                          begin
         | 
| 405 | 
            -
                            raise "Object was not a hash."  | 
| 406 | 
            -
                            raise "No ID was given?"  | 
| 411 | 
            +
                            raise "Object was not a hash." unless obj.is_a?(Hash)
         | 
| 412 | 
            +
                            raise "No ID was given?" unless id
         | 
| 407 413 | 
             
                            res = self.__send__("cmd_#{obj[:obj][:cmd]}", obj[:obj])
         | 
| 408 414 | 
             
                          rescue Exception => e
         | 
| 409 | 
            -
                            raise e if e.is_a?(SystemExit)  | 
| 410 | 
            -
                            res = {: | 
| 415 | 
            +
                            raise e if e.is_a?(SystemExit) || e.is_a?(Interrupt)
         | 
| 416 | 
            +
                            res = {type: :error, class: e.class.name, msg: e.message, bt: e.backtrace}
         | 
| 411 417 | 
             
                          end
         | 
| 412 | 
            -
             | 
| 413 | 
            -
                          data = Base64.strict_encode64(Marshal.dump(: | 
| 418 | 
            +
             | 
| 419 | 
            +
                          data = Base64.strict_encode64(Marshal.dump(type: :answer, id: id, answer: res))
         | 
| 414 420 | 
             
                          @io_out.puts(data)
         | 
| 415 421 | 
             
                        end
         | 
| 416 422 | 
             
                      elsif obj_type == :answer
         | 
| @@ -429,16 +435,16 @@ class Ruby_process | |
| 429 435 | 
             
                      debug "Error while listening: #{e.inspect}"
         | 
| 430 436 | 
             
                      debug e.backtrace.join("\n") + "\n"
         | 
| 431 437 | 
             
                    end
         | 
| 432 | 
            -
             | 
| 438 | 
            +
             | 
| 433 439 | 
             
                    @listen_err = e
         | 
| 434 440 | 
             
                  end
         | 
| 435 441 | 
             
                end
         | 
| 436 442 | 
             
              end
         | 
| 437 | 
            -
             | 
| 443 | 
            +
             | 
| 438 444 | 
             
              #Starts the listen thread that outputs the 'stderr' for the other process on this process's 'stderr'.
         | 
| 439 445 | 
             
              def start_listen_errors
         | 
| 440 446 | 
             
                return nil if !@io_err
         | 
| 441 | 
            -
             | 
| 447 | 
            +
             | 
| 442 448 | 
             
                @thr_err = Thread.new do
         | 
| 443 449 | 
             
                  begin
         | 
| 444 450 | 
             
                    @io_err.each_line do |str|
         | 
| @@ -449,4 +455,4 @@ class Ruby_process | |
| 449 455 | 
             
                  end
         | 
| 450 456 | 
             
                end
         | 
| 451 457 | 
             
              end
         | 
| 452 | 
            -
            end
         | 
| 458 | 
            +
            end
         |