Class Shell::ProcessController
In: lib/shell/process-controller.rb
Parent: Object

Methods

Public Class methods

[Source]

    # File lib/shell/process-controller.rb, line 34
34:       def activate(pc)
35:         process_controllers_exclusive do
36:           @ProcessControllers[pc] ||= 0
37:           @ProcessControllers[pc] += 1
38:         end
39:       end

[Source]

    # File lib/shell/process-controller.rb, line 51
51:       def each_active_object
52:         process_controllers_exclusive do
53:           for ref in @ProcessControllers.keys
54:             yield ref
55:           end
56:         end
57:       end

[Source]

    # File lib/shell/process-controller.rb, line 41
41:       def inactivate(pc)
42:         process_controllers_exclusive do
43:           if @ProcessControllers[pc]
44:             if (@ProcessControllers[pc] -= 1) == 0
45:               @ProcessControllers.delete(pc)
46:             end
47:           end
48:         end
49:       end

[Source]

    # File lib/shell/process-controller.rb, line 60
60:     def initialize(shell)
61:       @shell = shell
62:       @waiting_jobs = []
63:       @active_jobs = []
64:       @jobs_sync = Sync.new
65: 
66:       @job_monitor = Mutex.new
67:       @job_condition = ConditionVariable.new
68:     end

[Source]

    # File lib/shell/process-controller.rb, line 25
25:       def process_controllers_exclusive
26:         begin
27:           @ProcessControllers.lock unless Thread.critical 
28:           yield
29:         ensure
30:           @ProcessControllers.unlock unless Thread.critical 
31:         end
32:       end

Public Instance methods

[Source]

     # File lib/shell/process-controller.rb, line 143
143:     def active_job?(job)
144:       @jobs_sync.synchronize(:SH) do
145:         @active_jobs.include?(job)
146:       end
147:     end

[Source]

    # File lib/shell/process-controller.rb, line 79
79:     def active_jobs
80:       @active_jobs
81:     end

[Source]

    # File lib/shell/process-controller.rb, line 93
93:     def active_jobs_exist?
94:       @jobs_sync.synchronize(:SH) do
95:         @active_jobs.empty?
96:       end
97:     end

schedule a command

[Source]

     # File lib/shell/process-controller.rb, line 106
106:     def add_schedule(command)
107:       @jobs_sync.synchronize(:EX) do
108:         ProcessController.activate(self)
109:         if @active_jobs.empty?
110:           start_job command
111:         else
112:           @waiting_jobs.push(command)
113:         end
114:       end
115:     end

[Source]

    # File lib/shell/process-controller.rb, line 70
70:     def jobs
71:       jobs = []
72:       @jobs_sync.synchronize(:SH) do
73:         jobs.concat @waiting_jobs
74:         jobs.concat @active_jobs
75:       end
76:       jobs
77:     end

[Source]

    # File lib/shell/process-controller.rb, line 87
87:     def jobs_exist?
88:       @jobs_sync.synchronize(:SH) do
89:         @active_jobs.empty? or @waiting_jobs.empty?
90:       end
91:     end

kill a job

[Source]

     # File lib/shell/process-controller.rb, line 161
161:     def kill_job(sig, command)
162:       @jobs_sync.synchronize(:SH) do
163:         if @waiting_jobs.delete command
164:           ProcessController.inactivate(self)
165:           return
166:         elsif @active_jobs.include?(command)
167:           begin
168:             r = command.kill(sig)
169:             ProcessController.inactivate(self)
170:           rescue
171:             print "Shell: Warn: $!\n" if @shell.verbose?
172:             return nil
173:           end
174:           @active_jobs.delete command
175:           r
176:         end
177:       end
178:     end

simple fork

[Source]

     # File lib/shell/process-controller.rb, line 194
194:     def sfork(command, &block)
195:       pipe_me_in, pipe_peer_out = IO.pipe
196:       pipe_peer_in, pipe_me_out = IO.pipe
197:       Thread.critical = true
198: 
199:       STDOUT.flush
200:       ProcessController.each_active_object do |pc|
201:         for jobs in pc.active_jobs
202:           jobs.flush
203:         end
204:       end
205:       
206:       pid = fork {
207:         Thread.critical = true
208: 
209:         Thread.list.each do |th| 
210:           th.kill unless [Thread.main, Thread.current].include?(th)
211:         end
212: 
213:         STDIN.reopen(pipe_peer_in)
214:         STDOUT.reopen(pipe_peer_out)
215: 
216:         ObjectSpace.each_object(IO) do |io| 
217:           if ![STDIN, STDOUT, STDERR].include?(io)
218:             io.close unless io.closed?
219:           end
220:         end
221:         yield
222:       }
223: 
224:       pipe_peer_in.close
225:       pipe_peer_out.close
226:       command.notify "job(%name:##{pid}) start", @shell.debug?
227:       Thread.critical = false
228: 
229:       th = Thread.start {
230:         Thread.critical = true
231:         begin
232:           _pid = nil
233:           command.notify("job(%id) start to waiting finish.", @shell.debug?)
234:           Thread.critical = false
235:           _pid = Process.waitpid(pid, nil)
236:         rescue Errno::ECHILD
237:           command.notify "warn: job(%id) was done already waitipd."
238:           _pid = true
239:         ensure
240:           # when the process ends, wait until the command termintes
241:           if _pid
242:           else
243:             command.notify("notice: Process finishing...",
244:                            "wait for Job[%id] to finish.",
245:                            "You can use Shell#transact or Shell#check_point for more safe execution.")
246:             redo
247:           end
248:           Thread.exclusive do
249:             @job_monitor.synchronize do 
250:               terminate_job(command)
251:               @job_condition.signal
252:               command.notify "job(%id) finish.", @shell.debug?
253:             end
254:           end
255:         end
256:       }
257:       return pid, pipe_me_in, pipe_me_out
258:     end

start a job

[Source]

     # File lib/shell/process-controller.rb, line 118
118:     def start_job(command = nil)
119:       @jobs_sync.synchronize(:EX) do
120:         if command
121:           return if command.active?
122:           @waiting_jobs.delete command
123:         else
124:           command = @waiting_jobs.shift
125:           return unless command
126:         end
127:         @active_jobs.push command
128:         command.start
129: 
130:         # start all jobs that input from the job
131:         for job in @waiting_jobs
132:           start_job(job) if job.input == command
133:         end
134:       end
135:     end

terminate a job

[Source]

     # File lib/shell/process-controller.rb, line 150
150:     def terminate_job(command)
151:       @jobs_sync.synchronize(:EX) do
152:         @active_jobs.delete command
153:         ProcessController.inactivate(self)
154:         if @active_jobs.empty?
155:           start_job
156:         end
157:       end
158:     end

wait for all jobs to terminate

[Source]

     # File lib/shell/process-controller.rb, line 181
181:     def wait_all_jobs_execution
182:       @job_monitor.synchronize do
183:         begin
184:           while !jobs.empty?
185:             @job_condition.wait(@job_monitor)
186:           end
187:         ensure
188:           redo unless jobs.empty?
189:         end
190:       end
191:     end

[Source]

     # File lib/shell/process-controller.rb, line 137
137:     def waiting_job?(job)
138:       @jobs_sync.synchronize(:SH) do
139:         @waiting_jobs.include?(job)
140:       end
141:     end

[Source]

    # File lib/shell/process-controller.rb, line 83
83:     def waiting_jobs
84:       @waiting_jobs
85:     end

[Source]

     # File lib/shell/process-controller.rb, line 99
 99:     def waiting_jobs_exist?
100:       @jobs_sync.synchronize(:SH) do
101:         @waiting_jobs.empty?
102:       end
103:     end

[Validate]