Extended maintenance of Ruby versions 1.8.7 and 1.9.2 ended on July 31, 2014. Read more

In Files

  • shell/process-controller.rb
  • shell/system-command.rb

Shell::ProcessController

Constants

USING_AT_EXIT_WHEN_PROCESS_EXIT

for shell-command complete finish at this process exit.

Attributes

shell[R]

Public Class Methods

new(shell) click to toggle source
 
               # File shell/process-controller.rb, line 93
def initialize(shell)
  @shell = shell
  @waiting_jobs = []
  @active_jobs = []
  @jobs_sync = Sync.new

  @job_monitor = Mutex.new
  @job_condition = ConditionVariable.new
end
            

Public Instance Methods

activate(pc) click to toggle source
 
               # File shell/process-controller.rb, line 38
def activate(pc)
  process_controllers_exclusive do
    @ProcessControllers[pc] ||= 0
    @ProcessControllers[pc] += 1
  end
end
            
active_job?(job) click to toggle source
 
               # File shell/process-controller.rb, line 182
def active_job?(job)
  @jobs_sync.synchronize(:SH) do
    @active_jobs.include?(job)
  end
end
            
active_jobs() click to toggle source
 
               # File shell/process-controller.rb, line 114
def active_jobs
  @active_jobs
end
            
active_jobs_exist?() click to toggle source
 
               # File shell/process-controller.rb, line 128
def active_jobs_exist?
  @jobs_sync.synchronize(:SH) do
    @active_jobs.empty?
  end
end
            
active_process_controllers() click to toggle source
 
               # File shell/process-controller.rb, line 32
def active_process_controllers
  process_controllers_exclusive do
    @ProcessControllers.dup
  end
end
            
add_schedule(command) click to toggle source

schedule a command

 
               # File shell/process-controller.rb, line 141
def add_schedule(command)
  @jobs_sync.synchronize(:EX) do
    ProcessController.activate(self)
    if @active_jobs.empty?
      start_job command
    else
      @waiting_jobs.push(command)
    end
  end
end
            
block_output_synchronize(&b) click to toggle source
 
               # File shell/process-controller.rb, line 64
def block_output_synchronize(&b)
  @BlockOutputMonitor.synchronize(&b)
end
            
each_active_object() click to toggle source
 
               # File shell/process-controller.rb, line 56
def each_active_object
  process_controllers_exclusive do
    for ref in @ProcessControllers.keys
      yield ref
    end
  end
end
            
inactivate(pc) click to toggle source
 
               # File shell/process-controller.rb, line 45
def inactivate(pc)
  process_controllers_exclusive do
    if @ProcessControllers[pc]
      if (@ProcessControllers[pc] -= 1) == 0
        @ProcessControllers.delete(pc)
        @ProcessControllersCV.signal
      end
    end
  end
end
            
jobs() click to toggle source
 
               # File shell/process-controller.rb, line 105
def jobs
  jobs = []
  @jobs_sync.synchronize(:SH) do
    jobs.concat @waiting_jobs
    jobs.concat @active_jobs
  end
  jobs
end
            
jobs_exist?() click to toggle source
 
               # File shell/process-controller.rb, line 122
def jobs_exist?
  @jobs_sync.synchronize(:SH) do
    @active_jobs.empty? or @waiting_jobs.empty?
  end
end
            
kill_job(sig, command) click to toggle source

kill a job

 
               # File shell/process-controller.rb, line 201
def kill_job(sig, command)
  @jobs_sync.synchronize(:EX) do
    if @waiting_jobs.delete command
      ProcessController.inactivate(self)
      return
    elsif @active_jobs.include?(command)
      begin
        r = command.kill(sig)
        ProcessController.inactivate(self)
      rescue
        print "Shell: Warn: $!\n" if @shell.verbose?
        return nil
      end
      @active_jobs.delete command
      r
    end
  end
end
            
sfork(command, &block) click to toggle source

simple fork

 
               # File shell/process-controller.rb, line 237
    def sfork(command, &block)
      pipe_me_in, pipe_peer_out = IO.pipe
      pipe_peer_in, pipe_me_out = IO.pipe


      pid = nil
      pid_mutex = Mutex.new
      pid_cv = ConditionVariable.new

      Thread.start do
        ProcessController.block_output_synchronize do
          STDOUT.flush
          ProcessController.each_active_object do |pc|
            for jobs in pc.active_jobs
              jobs.flush
            end
          end

          pid = fork {
            Thread.list.each do |th|
#             th.kill unless [Thread.main, Thread.current].include?(th)
              th.kill unless Thread.current == th
            end

            STDIN.reopen(pipe_peer_in)
            STDOUT.reopen(pipe_peer_out)

            ObjectSpace.each_object(IO) do |io|
              if ![STDIN, STDOUT, STDERR].include?(io)
                io.close unless io.closed?
              end
            end

            yield
          }
        end
        pid_cv.signal

        pipe_peer_in.close
        pipe_peer_out.close
        command.notify "job(%name:##{pid}) start", @shell.debug?

        begin
          _pid = nil
          command.notify("job(%id) start to waiting finish.", @shell.debug?)
          _pid = Process.waitpid(pid, nil)
        rescue Errno::ECHILD
          command.notify "warn: job(%id) was done already waitpid."
          _pid = true
          #    rescue
          #      STDERR.puts $!
        ensure
          command.notify("Job(%id): Wait to finish when Process finished.", @shell.debug?)
          # when the process ends, wait until the command terminates
          if USING_AT_EXIT_WHEN_PROCESS_EXIT or _pid
          else
            command.notify("notice: Process finishing...",
                           "wait for Job[%id] to finish.",
                           "You can use Shell#transact or Shell#check_point for more safe execution.")
            redo
          end

#         command.notify "job(%id) pre-pre-finish.", @shell.debug?
          @job_monitor.synchronize do
#           command.notify "job(%id) pre-finish.", @shell.debug?
            terminate_job(command)
#           command.notify "job(%id) pre-finish2.", @shell.debug?
            @job_condition.signal
            command.notify "job(%id) finish.", @shell.debug?
          end
        end
      end

      pid_mutex.synchronize do
        while !pid
          pid_cv.wait(pid_mutex)
        end
      end

      return pid, pipe_me_in, pipe_me_out
    end
            
start_job(command = nil) click to toggle source

start a job

 
               # File shell/process-controller.rb, line 153
    def start_job(command = nil)
      @jobs_sync.synchronize(:EX) do
        if command
          return if command.active?
          @waiting_jobs.delete command
        else
          command = @waiting_jobs.shift
#         command.notify "job(%id) pre-start.", @shell.debug?

          return unless command
        end
        @active_jobs.push command
        command.start
#       command.notify "job(%id) post-start.", @shell.debug?

        # start all jobs that input from the job
        for job in @waiting_jobs.dup
          start_job(job) if job.input == command
        end
#       command.notify "job(%id) post2-start.", @shell.debug?
      end
    end
            
terminate_job(command) click to toggle source

terminate a job

 
               # File shell/process-controller.rb, line 189
def terminate_job(command)
  @jobs_sync.synchronize(:EX) do
    @active_jobs.delete command
    ProcessController.inactivate(self)
    if @active_jobs.empty?
      command.notify("start_job in terminate_job(%id)", Shell::debug?)
      start_job
    end
  end
end
            
wait_all_jobs_execution() click to toggle source

wait for all jobs to terminate

 
               # File shell/process-controller.rb, line 221
def wait_all_jobs_execution
  @job_monitor.synchronize do
    begin
      while !jobs.empty?
        @job_condition.wait(@job_monitor)
        for job in jobs
          job.notify("waiting job(%id)", Shell::debug?)
        end
      end
    ensure
      redo unless jobs.empty?
    end
  end
end
            
wait_to_finish_all_process_controllers() click to toggle source
 
               # File shell/process-controller.rb, line 68
def wait_to_finish_all_process_controllers
  process_controllers_exclusive do
    while !@ProcessControllers.empty?
      Shell::notify("Process finishing, but active shell exists",
                    "You can use Shell#transact or Shell#check_point for more safe execution.")
      if Shell.debug?
        for pc in @ProcessControllers.keys
          Shell::notify(" Not finished jobs in "+pc.shell.to_s)
          for com in pc.jobs
            com.notify("  Jobs: %id")
          end
        end
      end
      @ProcessControllersCV.wait(@ProcessControllersMonitor)
    end
  end
end
            
waiting_job?(job) click to toggle source
 
               # File shell/process-controller.rb, line 176
def waiting_job?(job)
  @jobs_sync.synchronize(:SH) do
    @waiting_jobs.include?(job)
  end
end
            
waiting_jobs() click to toggle source
 
               # File shell/process-controller.rb, line 118
def waiting_jobs
  @waiting_jobs
end
            
waiting_jobs_exist?() click to toggle source
 
               # File shell/process-controller.rb, line 134
def waiting_jobs_exist?
  @jobs_sync.synchronize(:SH) do
    @waiting_jobs.empty?
  end
end
            

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus