pwrake 0.9.9.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGES_V2.md +90 -0
  4. data/{LICENSE.txt → MIT-LICENSE} +2 -3
  5. data/README +12 -0
  6. data/README.md +75 -52
  7. data/bin/gfwhere-pipe +23 -12
  8. data/bin/pwrake +22 -29
  9. data/bin/pwrake_branch +24 -0
  10. data/lib/pwrake/branch.rb +22 -0
  11. data/lib/pwrake/branch/branch.rb +213 -0
  12. data/lib/pwrake/branch/branch_application.rb +53 -0
  13. data/lib/pwrake/branch/fiber_queue.rb +36 -0
  14. data/lib/pwrake/branch/file_utils.rb +101 -0
  15. data/lib/pwrake/branch/shell.rb +231 -0
  16. data/lib/pwrake/{profiler.rb → branch/shell_profiler.rb} +28 -27
  17. data/lib/pwrake/branch/worker_communicator.rb +104 -0
  18. data/lib/pwrake/{gfarm_feature.rb → gfarm/gfarm_path.rb} +2 -100
  19. data/lib/pwrake/gfarm/gfarm_postprocess.rb +53 -0
  20. data/lib/pwrake/iomux/channel.rb +70 -0
  21. data/lib/pwrake/iomux/handler.rb +124 -0
  22. data/lib/pwrake/iomux/handler_set.rb +35 -0
  23. data/lib/pwrake/iomux/runner.rb +62 -0
  24. data/lib/pwrake/logger.rb +3 -150
  25. data/lib/pwrake/master.rb +30 -137
  26. data/lib/pwrake/master/fiber_pool.rb +69 -0
  27. data/lib/pwrake/master/idle_cores.rb +30 -0
  28. data/lib/pwrake/master/master.rb +345 -0
  29. data/lib/pwrake/master/master_application.rb +150 -0
  30. data/lib/pwrake/master/postprocess.rb +16 -0
  31. data/lib/pwrake/{graphviz.rb → misc/graphviz.rb} +0 -0
  32. data/lib/pwrake/{mcgp.rb → misc/mcgp.rb} +63 -42
  33. data/lib/pwrake/option/host_map.rb +158 -0
  34. data/lib/pwrake/option/option.rb +357 -0
  35. data/lib/pwrake/option/option_filesystem.rb +112 -0
  36. data/lib/pwrake/queue/locality_aware_queue.rb +158 -0
  37. data/lib/pwrake/queue/no_action_queue.rb +67 -0
  38. data/lib/pwrake/queue/queue_array.rb +366 -0
  39. data/lib/pwrake/queue/task_queue.rb +164 -0
  40. data/lib/pwrake/report.rb +1 -0
  41. data/lib/pwrake/report/parallelism.rb +9 -3
  42. data/lib/pwrake/report/report.rb +50 -103
  43. data/lib/pwrake/report/task_stat.rb +83 -0
  44. data/lib/pwrake/task/task_algorithm.rb +107 -0
  45. data/lib/pwrake/task/task_manager.rb +32 -0
  46. data/lib/pwrake/task/task_property.rb +98 -0
  47. data/lib/pwrake/task/task_rank.rb +48 -0
  48. data/lib/pwrake/task/task_wrapper.rb +296 -0
  49. data/lib/pwrake/version.rb +1 -1
  50. data/lib/pwrake/worker/executor.rb +169 -0
  51. data/lib/pwrake/worker/gfarm_directory.rb +90 -0
  52. data/lib/pwrake/worker/invoker.rb +199 -0
  53. data/lib/pwrake/worker/load.rb +14 -0
  54. data/lib/pwrake/worker/log_executor.rb +73 -0
  55. data/lib/pwrake/worker/shared_directory.rb +74 -0
  56. data/lib/pwrake/worker/worker_main.rb +14 -0
  57. data/lib/pwrake/worker/writer.rb +59 -0
  58. data/setup.rb +1212 -1502
  59. data/spec/003/Rakefile +2 -2
  60. data/spec/008/Rakefile +2 -1
  61. data/spec/009/Rakefile +1 -1
  62. data/spec/009/pwrake_conf.yaml +1 -3
  63. data/spec/hosts +0 -2
  64. data/spec/pwrake_spec.rb +9 -8
  65. metadata +50 -21
  66. data/lib/pwrake.rb +0 -19
  67. data/lib/pwrake/application.rb +0 -232
  68. data/lib/pwrake/counter.rb +0 -54
  69. data/lib/pwrake/file_utils.rb +0 -98
  70. data/lib/pwrake/gfwhere_pool.rb +0 -109
  71. data/lib/pwrake/host_list.rb +0 -88
  72. data/lib/pwrake/locality_aware_queue.rb +0 -413
  73. data/lib/pwrake/option.rb +0 -400
  74. data/lib/pwrake/rake_modify.rb +0 -14
  75. data/lib/pwrake/shell.rb +0 -186
  76. data/lib/pwrake/task_algorithm.rb +0 -475
  77. data/lib/pwrake/task_queue.rb +0 -633
  78. data/lib/pwrake/timer.rb +0 -22
@@ -0,0 +1,22 @@
1
+ require "logger"
2
+ require 'csv'
3
+
4
+ require "pwrake/logger"
5
+
6
+ require "pwrake/iomux/channel"
7
+ require "pwrake/iomux/handler"
8
+ require "pwrake/iomux/handler_set"
9
+ require "pwrake/iomux/runner"
10
+
11
+ require "pwrake/branch/branch_application"
12
+ require "pwrake/branch/branch"
13
+ require "pwrake/branch/fiber_queue"
14
+ require "pwrake/branch/file_utils"
15
+
16
+ require 'pwrake/branch/shell_profiler'
17
+ require "pwrake/branch/shell"
18
+ require "pwrake/branch/worker_communicator"
19
+
20
+ require "pwrake/option/option"
21
+ require "pwrake/option/option_filesystem"
22
+ require "pwrake/option/host_map"
@@ -0,0 +1,213 @@
1
+ module Pwrake
2
+
3
+ class Branch
4
+
5
+ def initialize(opts,r,w)
6
+ #Thread.abort_on_exception = true
7
+ @option = opts
8
+ @task_q = {} # worker_id => FiberQueue.new
9
+ @shells = []
10
+ @ior = r
11
+ @iow = w
12
+ @runner = Runner.new(@option['HEARTBEAT'])
13
+ @master_hdl = Handler.new(@runner,@ior,@iow)
14
+ @master_chan = Channel.new(@master_hdl)
15
+ @wk_comm = {}
16
+ @wk_hdl_set = HandlerSet.new
17
+ @shell_start_interval = @option['SHELL_START_INTERVAL']
18
+ end
19
+
20
+ # Rakefile is loaded after 'init' before 'run'
21
+
22
+ def run
23
+ setup_worker
24
+ setup_shell
25
+ setup_fiber
26
+ setup_master_channel
27
+ @runner.run
28
+ Log.debug "Brandh#run end"
29
+ end
30
+
31
+ attr_reader :logger
32
+
33
+ def init_logger
34
+ if dir = @option['LOG_DIR']
35
+ logfile = File.join(dir,@option['LOG_FILE'])
36
+ @logger = Logger.new(logfile)
37
+ else
38
+ if @option['DEBUG']
39
+ @logger = Logger.new($stderr)
40
+ else
41
+ @logger = Logger.new(File::NULL)
42
+ end
43
+ end
44
+
45
+ if @option['DEBUG']
46
+ @logger.level = Logger::DEBUG
47
+ elsif @option['TRACE']
48
+ @logger.level = Logger::INFO
49
+ else
50
+ @logger.level = Logger::WARN
51
+ end
52
+ end
53
+
54
+ def setup_worker
55
+ s = @ior.gets
56
+ if s.chomp != "host_list_begin"
57
+ raise "Branch#setup_worker: recv=#{s.chomp} expected=host_list_begin"
58
+ end
59
+
60
+ if dir = @option['LOG_DIR']
61
+ fn = File.join(dir,@option["COMMAND_CSV_FILE"])
62
+ Shell.profiler.open(fn,@option['GNU_TIME'],@option['PLOT_PARALLELISM'])
63
+ end
64
+
65
+ worker_code = WorkerCommunicator.read_worker_progs(@option)
66
+
67
+ while s = @ior.gets
68
+ s.chomp!
69
+ break if s == "host_list_end"
70
+ if /^host:(\d+) (\S+) ([+-]?\d+)?$/ =~ s
71
+ id, host, ncore = $1,$2,$3
72
+ ncore &&= ncore.to_i
73
+ comm = WorkerCommunicator.new(id,host,ncore,@runner,@option)
74
+ comm.setup_connection(worker_code)
75
+ @wk_comm[id] = comm
76
+ @wk_hdl_set << comm.handler
77
+ @task_q[id] = FiberQueue.new
78
+ else
79
+ raise "Branch#setup_worker: recv=#{s.chomp} expected=host:id hostname ncore"
80
+ end
81
+ end
82
+
83
+ errors = []
84
+
85
+ @wk_comm.values.each do |comm|
86
+ Fiber.new do
87
+ while true
88
+ if s = comm.channel.get_line
89
+ break unless comm.ncore_proc(s)
90
+ else
91
+ errors << comm
92
+ break
93
+ end
94
+ end
95
+ Log.debug "Branch#setup_worker: fiber end of ncore_proc"
96
+ end.resume
97
+ end
98
+
99
+ @runner.run
100
+
101
+ if !errors.empty?
102
+ errors.each{|comm| @wk_hdl_set.delete(comm.handler)}
103
+ hosts = errors.map{|comm| comm.host}.join(",")
104
+ raise RuntimeError,"Failed to connect to workers: #{hosts}"
105
+ end
106
+
107
+ # ncore
108
+ @wk_comm.each_value do |comm|
109
+ # set WorkerChannel#ncore at Master
110
+ @master_hdl.put_line "ncore:#{comm.id}:#{comm.ncore}"
111
+ end
112
+ @master_hdl.put_line "ncore:done"
113
+ end
114
+
115
+ def setup_shell
116
+ @shells = []
117
+ errors = []
118
+ shell_id = 0
119
+ @wk_comm.each_value do |comm|
120
+ comm.ncore.times do
121
+ chan = Channel.new(comm.handler,shell_id)
122
+ shell_id += 1
123
+ shell = Shell.new(chan,@task_q[comm.id],@option.worker_option)
124
+ @shells << shell
125
+ # wait for remote shell open
126
+ Fiber.new do
127
+ if !shell.open
128
+ errors << [comm.host,s]
129
+ end
130
+ Log.debug "Branch#setup_shells: end of fiber to open shell"
131
+ end.resume
132
+ sleep @shell_start_interval
133
+ end
134
+ end
135
+
136
+ @runner.run
137
+
138
+ if !errors.empty?
139
+ raise RuntimeError,"Failed to start workers: #{errors.inspect}"
140
+ end
141
+ end
142
+
143
+ def setup_fiber
144
+ # start fibers
145
+ @shells.each do |shell|
146
+ shell.create_fiber(@master_hdl).resume
147
+ end
148
+ Log.debug "all fiber started"
149
+
150
+ @wk_comm.each_value do |comm|
151
+ #comm.start_default_fiber
152
+ Fiber.new do
153
+ while s = comm.channel.get_line
154
+ break unless comm.common_line(s)
155
+ end
156
+ Log.debug "Branch#setup_fiber: end of fiber for default channel"
157
+ end.resume
158
+ end
159
+
160
+ # setup end
161
+ @wk_comm.values.each do |comm|
162
+ comm.handler.put_line "setup_end"
163
+ end
164
+
165
+ @master_hdl.put_line "branch_setup:done"
166
+ Log.debug "Branch#setup_fiber: setup end"
167
+ end
168
+
169
+ def setup_master_channel
170
+ Fiber.new do
171
+ while s = @master_chan.get_line
172
+ # receive command from main pwrake
173
+ Log.debug "Branch:recv #{s.inspect} from master"
174
+ case s
175
+ #
176
+ when /^(\d+):(.+)$/o
177
+ id, tname = $1,$2
178
+ @task_q[id].enq(tname)
179
+ #
180
+ when /^exit$/
181
+ @task_q.each_value{|q| q.finish}
182
+ @shells.each{|shell| shell.close}
183
+ @runner.finish
184
+ break
185
+ #
186
+ when /^kill:(.*)$/o
187
+ sig = $1
188
+ kill(sig)
189
+ else
190
+ Log.debug "Branch: invalid line from master: #{s}"
191
+ end
192
+ end
193
+ Log.debug "Branch#setup_master_channel: end of fiber for master channel"
194
+ end.resume
195
+ end
196
+
197
+ def kill(sig="INT")
198
+ Log.warn "Branch#kill #{sig}"
199
+ @wk_hdl_set.kill(sig)
200
+ end
201
+
202
+ def finish
203
+ return if @finished
204
+ @finished = true
205
+ Log.debug "Branch#finish: begin"
206
+ @wk_hdl_set.exit
207
+ Log.debug "Branch#finish: worker exited"
208
+ @master_hdl.put_line "exited"
209
+ Log.debug "Branch#finish: sent 'exited' to master"
210
+ end
211
+
212
+ end # Pwrake::Branch
213
+ end
@@ -0,0 +1,53 @@
1
+ module Pwrake
2
+
3
+ # The TaskManager module is a mixin for managing tasks.
4
+ module BranchApplication
5
+
6
+ def logger
7
+ @branch.logger
8
+ end
9
+
10
+ def run_branch(r,w)
11
+ #standard_exception_handling do
12
+ init("pwrake_branch")
13
+ opts = Marshal.load(r)
14
+ if !opts.kind_of?(Hash)
15
+ raise "opts is not a Hash: opts=#{opts.inspect}"
16
+ end
17
+ @branch = Branch.new(opts,r,w)
18
+ @branch.init_logger
19
+ opts.feedback_options
20
+ load_rakefile
21
+ w.puts "pwrake_branch start"
22
+ w.flush
23
+ begin
24
+ @branch.run
25
+ rescue => e
26
+ Log.fatal e
27
+ $stderr.puts e
28
+ $stderr.puts e.backtrace
29
+ @branch.kill
30
+ ensure
31
+ @branch.finish
32
+ end
33
+ #end
34
+ end
35
+
36
+ def run_branch_in_thread(r,w,opts)
37
+ #standard_exception_handling do
38
+ @branch = Branch.new(opts,r,w)
39
+ begin
40
+ @branch.run
41
+ rescue => e
42
+ Log.fatal e
43
+ $stderr.puts e
44
+ $stderr.puts e.backtrace
45
+ @branch.kill
46
+ ensure
47
+ @branch.finish
48
+ end
49
+ #end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,36 @@
1
+ require 'fiber'
2
+
3
+ module Pwrake
4
+
5
+ class FiberQueue
6
+
7
+ def initialize
8
+ @q = []
9
+ @waiter = []
10
+ @finished = false
11
+ end
12
+
13
+ def enq(x)
14
+ @q.push(x)
15
+ f = @waiter.shift
16
+ f.resume if f
17
+ end
18
+
19
+ def deq
20
+ while @q.empty?
21
+ return nil if @finished
22
+ @waiter.push(Fiber.current)
23
+ Fiber.yield
24
+ end
25
+ return @q.shift
26
+ end
27
+
28
+ def finish
29
+ @finished = true
30
+ while f = @waiter.shift
31
+ f.resume
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,101 @@
1
+ module Pwrake
2
+
3
+ module FileUtils
4
+ module_function
5
+
6
+ def sh(*cmd, &block)
7
+ options = (Hash === cmd.last) ? cmd.pop : {}
8
+ unless block_given?
9
+ show_command = cmd.join(" ")
10
+ show_command = show_command[0,42] + "..."
11
+ block = lambda { |ok, status|
12
+ ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
13
+ }
14
+ end
15
+ if RakeFileUtils.verbose_flag == :default
16
+ options[:verbose] = true
17
+ else
18
+ options[:verbose] ||= RakeFileUtils.verbose_flag
19
+ end
20
+ options[:noop] ||= RakeFileUtils.nowrite_flag
21
+ Rake.rake_check_options options, :noop, :verbose
22
+ Rake.rake_output_message cmd.join(" ") if options[:verbose]
23
+ #Pwrake::Log.stderr_puts cmd.join(" ") if options[:verbose]
24
+ unless options[:noop]
25
+ res,status = Pwrake::FileUtils.pwrake_system(*cmd)
26
+ block.call(res, status)
27
+ end
28
+ end
29
+
30
+ def bq(*cmd, &block)
31
+ options = (Hash === cmd.last) ? cmd.pop : {}
32
+ unless block_given?
33
+ show_command = cmd.join(" ")
34
+ show_command = show_command[0,42] + "..."
35
+ block = lambda { |ok, status|
36
+ ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
37
+ }
38
+ end
39
+ if RakeFileUtils.verbose_flag == :default
40
+ options[:verbose] = true
41
+ else
42
+ options[:verbose] ||= RakeFileUtils.verbose_flag
43
+ end
44
+ options[:noop] ||= RakeFileUtils.nowrite_flag
45
+ Rake.rake_check_options options, :noop, :verbose
46
+ Rake.rake_output_message cmd.join(" ") if options[:verbose]
47
+ #Pwrake::Log.stderr_puts cmd.join(" ") if options[:verbose]
48
+ unless options[:noop]
49
+ res,status = Pwrake::FileUtils.pwrake_backquote(*cmd)
50
+ block.call(res, status)
51
+ end
52
+ res
53
+ end
54
+
55
+ def pwrake_system(*cmd)
56
+ cmd_log = cmd.join(" ").inspect
57
+ #tm = Pwrake::Timer.new("sh",cmd_log)
58
+
59
+ conn = Pwrake::Shell.current
60
+ if conn.kind_of?(Pwrake::Shell)
61
+ res = conn.system(*cmd)
62
+ status = Rake::PseudoStatus.new(conn.status)
63
+ else
64
+ res = system(*cmd)
65
+ status = $?
66
+ status = Rake::PseudoStatus.new(1) if !res && status.nil?
67
+ end
68
+
69
+ #tm.finish("status=%s cmd=%s"%[status.exitstatus,cmd_log])
70
+ [res,status]
71
+ end
72
+
73
+ # Pwrake version of backquote command
74
+ def pwrake_backquote(cmd)
75
+ cmd_log = cmd.inspect
76
+ #tm = Pwrake::Timer.new("bq",cmd_log)
77
+
78
+ conn = Pwrake::Shell.current
79
+ if conn.kind_of?(Pwrake::Shell)
80
+ res = conn.backquote(*cmd)
81
+ status = Rake::PseudoStatus.new(conn.status)
82
+ else
83
+ res = `#{cmd}`
84
+ status = $?
85
+ status = Rake::PseudoStatus.new(1) if status.nil?
86
+ end
87
+
88
+ #tm.finish("status=%s cmd=%s"%[status.exitstatus,cmd_log])
89
+ [res,status]
90
+ end
91
+
92
+ end # module Pwrake::FileUtils
93
+ end
94
+
95
+ module Rake
96
+ module DSL
97
+ include Pwrake::FileUtils
98
+ private(*Pwrake::FileUtils.instance_methods(false))
99
+ end
100
+ end
101
+ self.extend Rake::DSL
@@ -0,0 +1,231 @@
1
+ module Pwrake
2
+
3
+ class DummyMutex
4
+ def synchronize
5
+ yield
6
+ end
7
+ end
8
+
9
+ class Shell
10
+
11
+ OPEN_LIST={}
12
+ BY_FIBER={}
13
+ @@profiler = ShellProfiler.new
14
+
15
+ def self.profiler
16
+ @@profiler
17
+ end
18
+
19
+ def self.current
20
+ BY_FIBER[Fiber.current]
21
+ end
22
+
23
+ def initialize(chan,task_q,opt={})
24
+ @chan = chan
25
+ @host = chan.handler.host
26
+ @task_q = task_q
27
+ @lock = DummyMutex.new
28
+ @id = chan.id
29
+ #
30
+ @option = opt
31
+ @work_dir = @option[:work_dir] || Dir.pwd
32
+ end
33
+
34
+ attr_reader :id, :host, :status, :profile
35
+
36
+ def open
37
+ if @opened
38
+ Log.warn "already opened: host=#{@host} id=#{@id}"
39
+ end
40
+ _puts("open")
41
+ if (s = _gets) == "open"
42
+ OPEN_LIST[__id__] = self
43
+ @opened = true
44
+ true
45
+ else
46
+ Log.error("Shell#open failed: recieve #{s.inspect}")
47
+ false
48
+ end
49
+ end
50
+
51
+ def close
52
+ if !@opened
53
+ Log.warn "already closed: host=#{@host} id=#{@id}"
54
+ end
55
+ _puts("exit")
56
+ if (s = _gets) == "exit"
57
+ OPEN_LIST.delete(__id__)
58
+ @opened = false
59
+ true
60
+ else
61
+ Log.warn("Shell#close failed: recieve #{s.inspect}")
62
+ false
63
+ end
64
+ end
65
+
66
+ def set_current_task(task_id,task_name)
67
+ @task_id = task_id
68
+ @task_name = task_name
69
+ end
70
+
71
+ def backquote(*command)
72
+ command = command.join(' ')
73
+ @lock.synchronize do
74
+ a = []
75
+ _execute(command){|x| a << x}
76
+ a.join("\n")
77
+ end
78
+ end
79
+
80
+ def system(*command)
81
+ command = command.join(' ')
82
+ @lock.synchronize do
83
+ _execute(command){|x| print x+"\n"}
84
+ end
85
+ @status == 0
86
+ end
87
+
88
+ def cd(dir="")
89
+ _system("cd #{dir}") or die
90
+ end
91
+
92
+ def die
93
+ raise "Failed at #{@host}, id=#{@id}, cmd='#{@cmd}'"
94
+ end
95
+
96
+ at_exit {
97
+ Shell.profiler.close
98
+ }
99
+
100
+ private
101
+
102
+ def _puts(s)
103
+ #Log.debug "Shell#_puts(host=#{@host},id=#{@id}): #{s.inspect}"
104
+ @chan.put_line(s)
105
+ end
106
+
107
+ def _gets
108
+ s = @chan.get_line
109
+ #Log.debug "Shell#_gets(host=#{@host},id=#{@id}): #{s.inspect}"
110
+ if s.nil?
111
+ begin
112
+ raise
113
+ rescue => e
114
+ Log.debug e
115
+ end
116
+ end
117
+ s
118
+ end
119
+
120
+ def _system(cmd)
121
+ @cmd = cmd
122
+ #raise "@chan is closed" if @chan.closed?
123
+ @lock.synchronize do
124
+ _puts(cmd)
125
+ status = io_read_loop{}
126
+ Integer(status||1) == 0
127
+ end
128
+ end
129
+
130
+ def _backquote(cmd)
131
+ @cmd = cmd
132
+ #raise "@chan is closed" if @chan.closed?
133
+ a = []
134
+ @lock.synchronize do
135
+ _puts(cmd)
136
+ status = io_read_loop{|x| a << x}
137
+ end
138
+ a.join("\n")
139
+ end
140
+
141
+ def _execute(cmd,quote=nil,&block)
142
+ @cmd = cmd
143
+ if !@opened
144
+ raise "closed"
145
+ end
146
+ status = nil
147
+ start_time = Time.now
148
+ begin
149
+ _puts(cmd)
150
+ @status = io_read_loop(&block)
151
+ ensure
152
+ end_time = Time.now
153
+ @status = @@profiler.profile(@task_id, @task_name, cmd,
154
+ start_time, end_time, host, @status)
155
+ end
156
+ end
157
+
158
+ def io_read_loop
159
+ while s = _gets
160
+ case s
161
+ when /^(\w+):(.*)$/
162
+ x = [$1,$2]
163
+ case x[0]
164
+ when "o"
165
+ yield x[1]
166
+ next
167
+ when "e"
168
+ $stderr.print x[1]+"\n"
169
+ next
170
+ when "z"
171
+ # see Executor#status_to_str
172
+ status = x[1]
173
+ case status
174
+ when /^\d+$/
175
+ status = status.to_i
176
+ end
177
+ return status
178
+ when "err"
179
+ # see Executor#status_to_str
180
+ status = x[1]
181
+ case status
182
+ when /^\d+$/
183
+ status = status.to_i
184
+ end
185
+ return status
186
+ end
187
+ end
188
+ msg = "Shell#io_read_loop: Invalid result: #{s.inspect}"
189
+ $stderr.puts(msg)
190
+ Log.error(msg)
191
+ end
192
+ end
193
+
194
+ public
195
+
196
+ def create_fiber(hdl)
197
+ if !@opened
198
+ Log.warn "not opened: host=#{@host} id=#{@id}"
199
+ end
200
+ Fiber.new do
201
+ BY_FIBER[Fiber.current] = self
202
+ Log.debug "shell start id=#{@id} host=#{@host}"
203
+ begin
204
+ while task_str = @task_q.deq
205
+ #Log.debug "task_str=#{task_str}"
206
+ if /^(\d+):(.*)$/ =~ task_str
207
+ task_id, task_name = $1.to_i, $2
208
+ else
209
+ raise RuntimeError, "invalid task_str: #{task_str}"
210
+ end
211
+ @task_id = task_id
212
+ @task_name = task_name
213
+ task = Rake.application[task_name]
214
+ begin
215
+ task.execute(task.arguments) if task.needed?
216
+ result = "taskend:#{@id}:#{task.name}"
217
+ rescue Exception=>e
218
+ Rake.application.display_error_message(e)
219
+ Log.error e
220
+ result = "taskfail:#{@id}:#{task.name}"
221
+ end
222
+ hdl.put_line result
223
+ end
224
+ ensure
225
+ Log.debug "shell id=#{@id} fiber end"
226
+ end
227
+ end
228
+ end
229
+
230
+ end
231
+ end