Class: Forkr
- Inherits:
-
Object
- Object
- Forkr
- Defined in:
- lib/forkr.rb
Instance Attribute Summary collapse
-
#child_count ⇒ Object
readonly
Returns the value of attribute child_count.
-
#children ⇒ Object
readonly
Returns the value of attribute children.
-
#inbound ⇒ Object
readonly
Returns the value of attribute inbound.
-
#master_pid ⇒ Object
readonly
Returns the value of attribute master_pid.
-
#outbound ⇒ Object
readonly
Returns the value of attribute outbound.
Instance Method Summary collapse
- #add_worker ⇒ Object
- #child_dead?(pid) ⇒ Boolean
- #core_dump_quit ⇒ Object
- #dead_child ⇒ Object
- #decrement_workers ⇒ Object
- #ensure_right_worker_count ⇒ Object
- #increment_workers ⇒ Object
-
#initialize(forklet, num_kids = 1) ⇒ Forkr
constructor
A new instance of Forkr.
- #interrupt ⇒ Object
- #master_loop ⇒ Object
- #prune_workers ⇒ Object
- #reap_all_workers ⇒ Object
- #remove_worker ⇒ Object
- #run ⇒ Object
- #send_wake_notice(notice) ⇒ Object
- #shutdown ⇒ Object
- #shutdown_using(sig) ⇒ Object
- #signal_all_workers(sig) ⇒ Object
- #signal_worker(wpid, signal) ⇒ Object
- #spawn_worker ⇒ Object
- #worker_loop ⇒ Object
Constructor Details
#initialize(forklet, num_kids = 1) ⇒ Forkr
Returns a new instance of Forkr.
4 5 6 7 8 9 10 |
# File 'lib/forkr.rb', line 4 def initialize(forklet, num_kids = 1) @worker_client = forklet @master_pid = $$ @children = [] @child_count = num_kids @in_shutdown = false end |
Instance Attribute Details
#child_count ⇒ Object (readonly)
Returns the value of attribute child_count.
2 3 4 |
# File 'lib/forkr.rb', line 2 def child_count @child_count end |
#children ⇒ Object (readonly)
Returns the value of attribute children.
2 3 4 |
# File 'lib/forkr.rb', line 2 def children @children end |
#inbound ⇒ Object (readonly)
Returns the value of attribute inbound.
2 3 4 |
# File 'lib/forkr.rb', line 2 def inbound @inbound end |
#master_pid ⇒ Object (readonly)
Returns the value of attribute master_pid.
2 3 4 |
# File 'lib/forkr.rb', line 2 def master_pid @master_pid end |
#outbound ⇒ Object (readonly)
Returns the value of attribute outbound.
2 3 4 |
# File 'lib/forkr.rb', line 2 def outbound @outbound end |
Instance Method Details
#add_worker ⇒ Object
33 34 35 |
# File 'lib/forkr.rb', line 33 def add_worker send_wake_notice("+") end |
#child_dead?(pid) ⇒ Boolean
148 149 150 151 152 153 154 |
# File 'lib/forkr.rb', line 148 def child_dead?(pid) status = Process.waitpid(pid, Process::WNOHANG) unless status.nil? $stderr.puts "Process #{pid} dead: #{status}" end !status.nil? end |
#core_dump_quit ⇒ Object
29 30 31 |
# File 'lib/forkr.rb', line 29 def core_dump_quit send_wake_notice("Q") end |
#dead_child ⇒ Object
49 50 51 |
# File 'lib/forkr.rb', line 49 def dead_child send_wake_notice("D") end |
#decrement_workers ⇒ Object
65 66 67 68 69 |
# File 'lib/forkr.rb', line 65 def decrement_workers if @child_count > 1 @child_count = @child_count - 1 end end |
#ensure_right_worker_count ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/forkr.rb', line 111 def ensure_right_worker_count existing_workers = @children.length off_by = @child_count - @children.length if off_by > 0 off_by.times do spawn_worker end elsif off_by < 0 @children.take(off_by.abs).each do |kid| signal_worker(kid, :TERM) end end end |
#increment_workers ⇒ Object
61 62 63 |
# File 'lib/forkr.rb', line 61 def increment_workers @child_count = @child_count + 1 end |
#interrupt ⇒ Object
41 42 43 |
# File 'lib/forkr.rb', line 41 def interrupt send_wake_notice("I") end |
#master_loop ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/forkr.rb', line 77 def master_loop ensure_right_worker_count loop do fds = IO.select([@inbound],nil,nil,2) unless fds.nil? data_read = fds.first.first.read(1) if data_read == "I" shutdown_using(:INT) elsif data_read == "T" shutdown_using(:TERM) elsif data_read == "Q" shutdown_using(:QUIT) elsif data_read == "+" increment_workers elsif data_read == "-" decrement_workers end end prune_workers ensure_right_worker_count end reap_all_workers @outbound.close @inbound.close end |
#prune_workers ⇒ Object
136 137 138 |
# File 'lib/forkr.rb', line 136 def prune_workers @children = @children.reject { |pid| child_dead?(pid) } end |
#reap_all_workers ⇒ Object
103 104 105 106 107 108 109 |
# File 'lib/forkr.rb', line 103 def reap_all_workers begin wpid, status = Process.waitpid2(-1, Process::WNOHANG) rescue Errno::ECHILD break end while true end |
#remove_worker ⇒ Object
37 38 39 |
# File 'lib/forkr.rb', line 37 def remove_worker send_wake_notice("-") end |
#run ⇒ Object
12 13 14 15 16 17 18 19 20 21 |
# File 'lib/forkr.rb', line 12 def run @inbound, @outbound = IO.pipe Signal.trap('CHLD') { dead_child } Signal.trap('INT') { interrupt } Signal.trap('TERM') { shutdown } Signal.trap('QUIT') { core_dump_quit } Signal.trap('TTIN') { add_worker } Signal.trap('TTOU') { remove_worker } master_loop end |
#send_wake_notice(notice) ⇒ Object
23 24 25 26 27 |
# File 'lib/forkr.rb', line 23 def send_wake_notice(notice) return(nil) if $$ != master_pid return(nil) if @in_shutdown @outbound.write(notice) end |
#shutdown ⇒ Object
45 46 47 |
# File 'lib/forkr.rb', line 45 def shutdown send_wake_notice("T") end |
#shutdown_using(sig) ⇒ Object
71 72 73 74 75 |
# File 'lib/forkr.rb', line 71 def shutdown_using(sig) @in_shutdown = true signal_all_workers(sig) raise StopIteration.new end |
#signal_all_workers(sig) ⇒ Object
125 126 127 |
# File 'lib/forkr.rb', line 125 def signal_all_workers(sig) @children.each { |c| signal_worker(c, sig) } end |
#signal_worker(wpid, signal) ⇒ Object
129 130 131 132 133 134 |
# File 'lib/forkr.rb', line 129 def signal_worker(wpid, signal) begin Process.kill(signal, wpid) rescue Errno::ESRCH end end |
#spawn_worker ⇒ Object
53 54 55 56 57 58 59 |
# File 'lib/forkr.rb', line 53 def spawn_worker if new_pid = fork @children << new_pid else worker_loop end end |
#worker_loop ⇒ Object
140 141 142 143 144 145 146 |
# File 'lib/forkr.rb', line 140 def worker_loop @worker_client.after_fork if @worker_client.respond_to?(:after_fork) @inbound.close @outbound.close $stderr.puts "Worker spawned as #{$$}!" @worker_client.run end |