In Files

  • shell/process-controller.rb

Shell::ProcessController

Public Class 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
            
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
            
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
            
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
            

Public Instance Methods

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
            
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
            
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