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

In Files

  • shell/process-controller.rb

Shell::ProcessController

Public Class Methods

new(shell) click to toggle source
 
               # File shell/process-controller.rb, line 60
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 34
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 143
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 79
def active_jobs
  @active_jobs
end
            
active_jobs_exist?() click to toggle source
 
               # File shell/process-controller.rb, line 93
def active_jobs_exist?
  @jobs_sync.synchronize(:SH) do
    @active_jobs.empty?
  end
end
            
add_schedule(command) click to toggle source

schedule a command

 
               # File shell/process-controller.rb, line 106
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
            
each_active_object() click to toggle source
 
               # File shell/process-controller.rb, line 51
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 41
def inactivate(pc)
  process_controllers_exclusive do
    if @ProcessControllers[pc]
      if (@ProcessControllers[pc] -= 1) == 0
        @ProcessControllers.delete(pc)
      end
    end
  end
end
            
jobs() click to toggle source
 
               # File shell/process-controller.rb, line 70
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 87
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 161
def kill_job(sig, command)
  @jobs_sync.synchronize(:SH) 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
            
process_controllers_exclusive() click to toggle source
 
               # File shell/process-controller.rb, line 25
def process_controllers_exclusive
  begin
    @ProcessControllers.lock unless Thread.critical 
    yield
  ensure
    @ProcessControllers.unlock unless Thread.critical 
  end
end
            
sfork(command, &block) click to toggle source

simple fork

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

  STDOUT.flush
  ProcessController.each_active_object do |pc|
    for jobs in pc.active_jobs
      jobs.flush
    end
  end
  
  pid = fork {
    Thread.critical = true

    Thread.list.each do |th| 
      th.kill unless [Thread.main, Thread.current].include?(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
  }

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

  th = Thread.start {
    Thread.critical = true
    begin
      _pid = nil
      command.notify("job(%id) start to waiting finish.", @shell.debug?)
      Thread.critical = false
      _pid = Process.waitpid(pid, nil)
    rescue Errno::ECHILD
      command.notify "warn: job(%id) was done already waitipd."
      _pid = true
    ensure
      # when the process ends, wait until the command termintes
      if _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
      Thread.exclusive do
        @job_monitor.synchronize do 
          terminate_job(command)
          @job_condition.signal
          command.notify "job(%id) finish.", @shell.debug?
        end
      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 118
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
      return unless command
    end
    @active_jobs.push command
    command.start

    # start all jobs that input from the job
    for job in @waiting_jobs
      start_job(job) if job.input == command
    end
  end
end
            
terminate_job(command) click to toggle source

terminate a job

 
               # File shell/process-controller.rb, line 150
def terminate_job(command)
  @jobs_sync.synchronize(:EX) do
    @active_jobs.delete command
    ProcessController.inactivate(self)
    if @active_jobs.empty?
      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 181
def wait_all_jobs_execution
  @job_monitor.synchronize do
    begin
      while !jobs.empty?
        @job_condition.wait(@job_monitor)
      end
    ensure
      redo unless jobs.empty?
    end
  end
end
            
waiting_job?(job) click to toggle source
 
               # File shell/process-controller.rb, line 137
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 83
def waiting_jobs
  @waiting_jobs
end
            
waiting_jobs_exist?() click to toggle source
 
               # File shell/process-controller.rb, line 99
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