slave 0.0.0 → 0.0.1
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.
- data/HISTORY +16 -0
- data/doc/classes/Slave/Heartbeat.html +241 -126
- data/doc/classes/Slave.html +289 -173
- data/doc/created.rid +1 -1
- data/doc/dot/f_1.dot +16 -1
- data/doc/dot/f_1.jpg +0 -0
- data/doc/files/README.html +1 -1
- data/doc/files/lib/slave_rb.html +3 -2
- data/doc/fr_file_index.html +0 -1
- data/doc/fr_method_index.html +16 -10
- data/lib/{slave-0.0.0.rb → slave-0.0.1.rb} +102 -8
- data/lib/slave.rb +130 -19
- data/rdoc.cmd +1 -1
- data/sample/a.rb +11 -94
- data/sample/b.rb +8 -0
- data/sample/c.rb +109 -0
- data/{slave-0.0.0.gem → slave-0.0.1.gem} +0 -0
- metadata +24 -22
- data/VERSION +0 -1
data/doc/created.rid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
Thu Jun 08 15:55:38 MDT 2006
|
data/doc/dot/f_1.dot
CHANGED
@@ -3,12 +3,27 @@ digraph TopLevel {
|
|
3
3
|
bgcolor = lightcyan1
|
4
4
|
fontname = Arial
|
5
5
|
fontsize = 8
|
6
|
-
label = "
|
6
|
+
label = "lib/slave.rb"
|
7
7
|
node [
|
8
8
|
fontname = Arial,
|
9
9
|
fontsize = 8,
|
10
10
|
color = black
|
11
11
|
]
|
12
12
|
|
13
|
+
subgraph cluster_1 {
|
14
|
+
fontname = Arial
|
15
|
+
color = red
|
16
|
+
label = "lib/slave.rb"
|
17
|
+
Slave [
|
18
|
+
fontcolor = black,
|
19
|
+
URL = "classes/Slave.html",
|
20
|
+
shape = ellipse,
|
21
|
+
color = palegoldenrod,
|
22
|
+
style = filled,
|
23
|
+
label = "Slave"
|
24
|
+
]
|
25
|
+
|
26
|
+
}
|
27
|
+
|
13
28
|
}
|
14
29
|
|
data/doc/dot/f_1.jpg
CHANGED
Binary file
|
data/doc/files/README.html
CHANGED
data/doc/files/lib/slave_rb.html
CHANGED
@@ -56,7 +56,7 @@
|
|
56
56
|
</tr>
|
57
57
|
<tr class="top-aligned-row">
|
58
58
|
<td><strong>Last Update:</strong></td>
|
59
|
-
<td>
|
59
|
+
<td>Thu Jun 08 15:54:54 MDT 2006</td>
|
60
60
|
</tr>
|
61
61
|
</table>
|
62
62
|
</div>
|
@@ -70,7 +70,7 @@
|
|
70
70
|
<map name="map">
|
71
71
|
<area shape="RECT" coords="28,88,99,40" href="../../classes/Slave.html" alt="Slave">
|
72
72
|
</map>
|
73
|
-
<img src="../../dot/
|
73
|
+
<img src="../../dot/f_1.jpg" usemap="#map" border=0 alt="TopLevel">
|
74
74
|
</div>
|
75
75
|
|
76
76
|
|
@@ -82,6 +82,7 @@
|
|
82
82
|
fileutils
|
83
83
|
tmpdir
|
84
84
|
tempfile
|
85
|
+
fcntl
|
85
86
|
</div>
|
86
87
|
</div>
|
87
88
|
|
data/doc/fr_file_index.html
CHANGED
data/doc/fr_method_index.html
CHANGED
@@ -20,19 +20,25 @@
|
|
20
20
|
<div id="index">
|
21
21
|
<h1 class="section-bar">Methods</h1>
|
22
22
|
<div id="index-entries">
|
23
|
-
<a href="classes/Slave/Heartbeat.html#
|
23
|
+
<a href="classes/Slave/Heartbeat.html#M000017">child_start (Slave::Heartbeat)</a><br />
|
24
|
+
<a href="classes/Slave/Heartbeat.html#M000014">child_start (Slave::Heartbeat)</a><br />
|
25
|
+
<a href="classes/Slave.html#M000004">detach (Slave)</a><br />
|
24
26
|
<a href="classes/Slave.html#M000002">fork (Slave)</a><br />
|
25
|
-
<a href="classes/Slave.html#
|
26
|
-
<a href="classes/Slave.html#M000006">getval (Slave)</a><br />
|
27
|
+
<a href="classes/Slave.html#M000008">gen_psname (Slave)</a><br />
|
27
28
|
<a href="classes/Slave.html#M000001">getval (Slave)</a><br />
|
28
|
-
<a href="classes/Slave
|
29
|
+
<a href="classes/Slave.html#M000009">getval (Slave)</a><br />
|
30
|
+
<a href="classes/Slave/Heartbeat.html#M000011">new (Slave::Heartbeat)</a><br />
|
29
31
|
<a href="classes/Slave.html#M000003">new (Slave)</a><br />
|
30
|
-
<a href="classes/Slave/Heartbeat.html#
|
31
|
-
<a href="classes/Slave.html#
|
32
|
-
<a href="classes/Slave
|
33
|
-
<a href="classes/Slave/Heartbeat.html#M000012">
|
34
|
-
<a href="classes/Slave.html#
|
35
|
-
<a href="classes/Slave/Heartbeat.html#
|
32
|
+
<a href="classes/Slave/Heartbeat.html#M000016">parent_start (Slave::Heartbeat)</a><br />
|
33
|
+
<a href="classes/Slave/Heartbeat.html#M000013">parent_start (Slave::Heartbeat)</a><br />
|
34
|
+
<a href="classes/Slave.html#M000007">shutdown (Slave)</a><br />
|
35
|
+
<a href="classes/Slave/Heartbeat.html#M000012">start (Slave::Heartbeat)</a><br />
|
36
|
+
<a href="classes/Slave/Heartbeat.html#M000015">start (Slave::Heartbeat)</a><br />
|
37
|
+
<a href="classes/Slave/Heartbeat.html#M000018">stop (Slave::Heartbeat)</a><br />
|
38
|
+
<a href="classes/Slave.html#M000010">trace (Slave)</a><br />
|
39
|
+
<a href="classes/Slave/Heartbeat.html#M000019">trace (Slave::Heartbeat)</a><br />
|
40
|
+
<a href="classes/Slave.html#M000005">wait (Slave)</a><br />
|
41
|
+
<a href="classes/Slave.html#M000006">wait2 (Slave)</a><br />
|
36
42
|
</div>
|
37
43
|
</div>
|
38
44
|
</body>
|
@@ -2,13 +2,43 @@ require 'drb/drb'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'tmpdir'
|
4
4
|
require 'tempfile'
|
5
|
+
require 'fcntl'
|
6
|
+
|
7
|
+
class Pipe
|
8
|
+
attr 'r'
|
9
|
+
attr 'w'
|
10
|
+
def initialize
|
11
|
+
@r, @w = IO.pipe
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Lifeline
|
16
|
+
class Error < ::StandardError
|
17
|
+
def initialize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def initialize
|
21
|
+
@pid = Process.pid
|
22
|
+
@pipe = Pipe.new
|
23
|
+
end
|
24
|
+
def throw
|
25
|
+
end
|
26
|
+
def cling
|
27
|
+
@w.close
|
28
|
+
Thread.new(@r, Thread.current) do |r, t|
|
29
|
+
r.read rescue t.raise($!)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
5
33
|
|
6
34
|
#
|
7
35
|
# the Slave class encapsulates the work of setting up a drb server in another
|
8
|
-
# process.
|
36
|
+
# process.
|
9
37
|
#
|
10
38
|
class Slave
|
11
39
|
#--{{{
|
40
|
+
VERSION = '0.0.1'
|
41
|
+
|
12
42
|
DEFAULT_SOCKET_CREATION_ATTEMPTS =
|
13
43
|
Integer(ENV['SLAVE_SOCKET_CREATION_ATTEMPTS'] || 42)
|
14
44
|
|
@@ -68,9 +98,11 @@ require 'tempfile'
|
|
68
98
|
attr :socket
|
69
99
|
attr :debug
|
70
100
|
|
101
|
+
#
|
71
102
|
# 'obj' can be any object and 'opts' may contain the keys
|
72
103
|
# 'socket_creation_attempts', 'pulse_rate', 'psname', or 'debug'
|
73
|
-
|
104
|
+
#
|
105
|
+
def initialize obj = nil, opts = {}, &block
|
74
106
|
#--{{{
|
75
107
|
@obj = obj
|
76
108
|
|
@@ -85,7 +117,7 @@ require 'tempfile'
|
|
85
117
|
|
86
118
|
@shutdown = false
|
87
119
|
|
88
|
-
@heartbeat = Heartbeat::new @pulse_rate, @debug
|
120
|
+
# @heartbeat = Heartbeat::new @pulse_rate, @debug
|
89
121
|
@r, @w = IO::pipe
|
90
122
|
#
|
91
123
|
# child
|
@@ -119,15 +151,16 @@ require 'tempfile'
|
|
119
151
|
end
|
120
152
|
|
121
153
|
if @socket and @uri
|
122
|
-
@heartbeat.start
|
154
|
+
# @heartbeat.start
|
123
155
|
@w.write @socket
|
124
156
|
@w.close
|
125
157
|
trap('SIGUSR2') do
|
126
|
-
@heartbeat.stop rescue nil
|
158
|
+
# @heartbeat.stop rescue nil
|
127
159
|
DBb::thread.kill rescue nil
|
128
160
|
FileUtils::rm_f @socket rescue nil
|
129
161
|
exit!
|
130
162
|
end
|
163
|
+
block[obj] if block
|
131
164
|
DRb::thread.join
|
132
165
|
else
|
133
166
|
@w.close
|
@@ -152,7 +185,7 @@ require 'tempfile'
|
|
152
185
|
at_exit{ FileUtils::rm_f @socket }
|
153
186
|
@uri = "drbunix://#{ socket }"
|
154
187
|
trace{ "parent - uri <#{ @uri }>" }
|
155
|
-
@heartbeat.start
|
188
|
+
# @heartbeat.start
|
156
189
|
#
|
157
190
|
# starting drb on localhost avoids dns lookups!
|
158
191
|
#
|
@@ -164,30 +197,38 @@ require 'tempfile'
|
|
164
197
|
end
|
165
198
|
#--}}}
|
166
199
|
end
|
200
|
+
#
|
167
201
|
# stops the heartbeat thread and kills the child process
|
202
|
+
#
|
168
203
|
def shutdown
|
169
204
|
#--{{{
|
170
205
|
raise "already shutdown" if @shutdown
|
171
|
-
@heartbeat.stop rescue nil
|
206
|
+
# @heartbeat.stop rescue nil
|
172
207
|
Process::kill('SIGUSR2', @pid) rescue nil
|
173
208
|
Process::kill('SIGTERM', @pid) rescue nil
|
174
209
|
FileUtils::rm_f @socket
|
175
210
|
@shutdown = true
|
176
211
|
#--}}}
|
177
212
|
end
|
213
|
+
#
|
178
214
|
# generate a default name to appear in ps/top
|
215
|
+
#
|
179
216
|
def gen_psname obj
|
180
217
|
#--{{{
|
181
218
|
"#{ obj.class }_slave_of_#{ Process::pid }".downcase
|
182
219
|
#--}}}
|
183
220
|
end
|
184
|
-
#
|
221
|
+
#
|
222
|
+
# see docs for Slave.getval
|
223
|
+
#
|
185
224
|
def getval key, opts = {}
|
186
225
|
#--{{{
|
187
226
|
self.class.getval key
|
188
227
|
#--}}}
|
189
228
|
end
|
229
|
+
#
|
190
230
|
# debugging output
|
231
|
+
#
|
191
232
|
def trace
|
192
233
|
#--{{{
|
193
234
|
STDERR.puts(yield) if @debug and STDERR.tty?
|
@@ -223,6 +264,7 @@ require 'tempfile'
|
|
223
264
|
if Process::pid == @pid
|
224
265
|
@w.close
|
225
266
|
@pipe = @r
|
267
|
+
@pipe.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
|
226
268
|
parent_start
|
227
269
|
else
|
228
270
|
@r.close
|
@@ -273,6 +315,58 @@ require 'tempfile'
|
|
273
315
|
end
|
274
316
|
#--}}}
|
275
317
|
end
|
318
|
+
|
319
|
+
def start
|
320
|
+
#--{{{
|
321
|
+
if Process::pid == @pid
|
322
|
+
@r.close
|
323
|
+
@pipe = @w
|
324
|
+
@pipe.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
|
325
|
+
parent_start
|
326
|
+
else
|
327
|
+
@w.close
|
328
|
+
@pipe = @r
|
329
|
+
child_start
|
330
|
+
end
|
331
|
+
@beating = true
|
332
|
+
#--}}}
|
333
|
+
end
|
334
|
+
def parent_start
|
335
|
+
#--{{{
|
336
|
+
@whoami = 'parent'
|
337
|
+
@thread =
|
338
|
+
Thread::new(Thread::current) do |cur|
|
339
|
+
begin
|
340
|
+
sleep
|
341
|
+
rescue => e
|
342
|
+
cur.raise e
|
343
|
+
ensure
|
344
|
+
@pipe.close rescue nil
|
345
|
+
end
|
346
|
+
end
|
347
|
+
#--}}}
|
348
|
+
end
|
349
|
+
def child_start
|
350
|
+
#--{{{
|
351
|
+
@whoami = 'child'
|
352
|
+
@pid = Process::pid
|
353
|
+
@ppid = Process::ppid
|
354
|
+
@thread =
|
355
|
+
Thread::new(Thread::current) do |cur|
|
356
|
+
begin
|
357
|
+
trace{ "child reading..." }
|
358
|
+
@pipe.read
|
359
|
+
trace{ "child read." }
|
360
|
+
trace{ "child exiting." }
|
361
|
+
exit!
|
362
|
+
rescue => e
|
363
|
+
cur.raise e
|
364
|
+
ensure
|
365
|
+
@pipe.close rescue nil
|
366
|
+
end
|
367
|
+
end
|
368
|
+
#--}}}
|
369
|
+
end
|
276
370
|
def stop
|
277
371
|
#--{{{
|
278
372
|
raise "not beating" unless @beating
|
data/lib/slave.rb
CHANGED
@@ -2,13 +2,35 @@ require 'drb/drb'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'tmpdir'
|
4
4
|
require 'tempfile'
|
5
|
+
require 'fcntl'
|
5
6
|
|
6
7
|
#
|
7
8
|
# the Slave class encapsulates the work of setting up a drb server in another
|
8
|
-
# process.
|
9
|
+
# process running on localhost. the slave process is attached to it's parent
|
10
|
+
# via a Heartbeat which is designed such that the slave cannot out-live it's
|
11
|
+
# parent and become a zombie, even if the parent dies and early death, such as
|
12
|
+
# by 'kill -9'. the concept and purpose of the Slave class is to be able to
|
13
|
+
# setup any server object in another process so easily that using a
|
14
|
+
# multi-process, drb/ipc, based design is as easy, or easier, than a
|
15
|
+
# multi-threaded one. eg
|
16
|
+
#
|
17
|
+
# class Server
|
18
|
+
# def add_two n
|
19
|
+
# n + 2
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# slave = Slave.new Server.new
|
24
|
+
# server = slave.object
|
25
|
+
#
|
26
|
+
# p server.add_two(40) #=> 42
|
9
27
|
#
|
10
28
|
class Slave
|
11
29
|
#--{{{
|
30
|
+
VERSION = '0.0.1'
|
31
|
+
#
|
32
|
+
# config
|
33
|
+
#
|
12
34
|
DEFAULT_SOCKET_CREATION_ATTEMPTS =
|
13
35
|
Integer(ENV['SLAVE_SOCKET_CREATION_ATTEMPTS'] || 42)
|
14
36
|
|
@@ -21,7 +43,9 @@ require 'tempfile'
|
|
21
43
|
@socket_creation_attempts = DEFAULT_SOCKET_CREATION_ATTEMPTS
|
22
44
|
@pulse_rate = DEFAULT_PULSE_RATE
|
23
45
|
@debug = DEFAULT_DEBUG
|
24
|
-
|
46
|
+
#
|
47
|
+
# class methods
|
48
|
+
#
|
25
49
|
class << self
|
26
50
|
#--{{{
|
27
51
|
# defineds how many attempts will be made to create a temporary unix domain
|
@@ -67,10 +91,13 @@ require 'tempfile'
|
|
67
91
|
attr :pulse_rate
|
68
92
|
attr :socket
|
69
93
|
attr :debug
|
94
|
+
attr :status
|
70
95
|
|
71
|
-
|
72
|
-
|
73
|
-
|
96
|
+
#
|
97
|
+
# 'obj' can be any object and 'opts' may contain the keys
|
98
|
+
# 'socket_creation_attempts', 'pulse_rate', 'psname', or 'debug'
|
99
|
+
#
|
100
|
+
def initialize obj = nil, opts = {}, &block
|
74
101
|
#--{{{
|
75
102
|
@obj = obj
|
76
103
|
|
@@ -84,6 +111,7 @@ require 'tempfile'
|
|
84
111
|
trace{ "psname <#{ @psname }>" }
|
85
112
|
|
86
113
|
@shutdown = false
|
114
|
+
@waiter = @status = nil
|
87
115
|
|
88
116
|
@heartbeat = Heartbeat::new @pulse_rate, @debug
|
89
117
|
@r, @w = IO::pipe
|
@@ -91,6 +119,7 @@ require 'tempfile'
|
|
91
119
|
# child
|
92
120
|
#
|
93
121
|
unless((@pid = Slave::fork))
|
122
|
+
e = nil
|
94
123
|
begin
|
95
124
|
$0 = @psname
|
96
125
|
@pid = Process::pid
|
@@ -123,25 +152,28 @@ require 'tempfile'
|
|
123
152
|
@w.write @socket
|
124
153
|
@w.close
|
125
154
|
trap('SIGUSR2') do
|
126
|
-
@heartbeat.stop rescue nil
|
155
|
+
# @heartbeat.stop rescue nil
|
127
156
|
DBb::thread.kill rescue nil
|
128
157
|
FileUtils::rm_f @socket rescue nil
|
129
158
|
exit!
|
130
159
|
end
|
160
|
+
block[obj] if block
|
131
161
|
DRb::thread.join
|
132
162
|
else
|
133
163
|
@w.close
|
134
164
|
end
|
135
|
-
rescue => e
|
165
|
+
rescue Exception => e
|
136
166
|
trace{ %Q[#{ e.message } (#{ e.class })\n#{ e.backtrace.join "\n" }] }
|
137
167
|
ensure
|
138
|
-
|
168
|
+
status = e.respond_to?('status') ? e.status : 1
|
169
|
+
exit!(status)
|
139
170
|
end
|
140
171
|
#
|
141
172
|
# parent
|
142
173
|
#
|
143
174
|
else
|
144
|
-
Process::detach @pid
|
175
|
+
#Process::detach @pid
|
176
|
+
detach
|
145
177
|
@w.close
|
146
178
|
@socket = @r.read
|
147
179
|
@r.close
|
@@ -164,7 +196,27 @@ require 'tempfile'
|
|
164
196
|
end
|
165
197
|
#--}}}
|
166
198
|
end
|
167
|
-
|
199
|
+
#
|
200
|
+
# starts a thread to attempt collecting the child status
|
201
|
+
#
|
202
|
+
def detach
|
203
|
+
#--{{{
|
204
|
+
@waiter =
|
205
|
+
Thread.new{ @status = Process::waitpid2(@pid).last }
|
206
|
+
#--}}}
|
207
|
+
end
|
208
|
+
#
|
209
|
+
# wait for slave to finish
|
210
|
+
#
|
211
|
+
def wait
|
212
|
+
#--{{{
|
213
|
+
@waiter.value
|
214
|
+
#--}}}
|
215
|
+
end
|
216
|
+
alias :wait2 :wait
|
217
|
+
#
|
218
|
+
# stops the heartbeat thread and kills the child process
|
219
|
+
#
|
168
220
|
def shutdown
|
169
221
|
#--{{{
|
170
222
|
raise "already shutdown" if @shutdown
|
@@ -175,19 +227,25 @@ require 'tempfile'
|
|
175
227
|
@shutdown = true
|
176
228
|
#--}}}
|
177
229
|
end
|
178
|
-
|
230
|
+
#
|
231
|
+
# generate a default name to appear in ps/top
|
232
|
+
#
|
179
233
|
def gen_psname obj
|
180
234
|
#--{{{
|
181
|
-
"#{ obj.class }_slave_of_#{ Process::pid }".downcase
|
235
|
+
"#{ obj.class }_slave_of_#{ Process::pid }".downcase.gsub(%r/\s*/,'_')
|
182
236
|
#--}}}
|
183
237
|
end
|
184
|
-
|
238
|
+
#
|
239
|
+
# see docs for Slave.getval
|
240
|
+
#
|
185
241
|
def getval key, opts = {}
|
186
242
|
#--{{{
|
187
243
|
self.class.getval key
|
188
244
|
#--}}}
|
189
245
|
end
|
190
|
-
|
246
|
+
#
|
247
|
+
# debugging output - ENV['SLAVE_DEBUG']=1 to enable
|
248
|
+
#
|
191
249
|
def trace
|
192
250
|
#--{{{
|
193
251
|
STDERR.puts(yield) if @debug and STDERR.tty?
|
@@ -195,11 +253,11 @@ require 'tempfile'
|
|
195
253
|
end
|
196
254
|
|
197
255
|
#
|
198
|
-
# the Heartbeat class is essentially wrapper over an IPC channel that sends
|
199
|
-
# ping on the channel indicating process health. if either end of the
|
200
|
-
# is detached the ping will fail and an error will be raised. in
|
201
|
-
# is ensured that Slave
|
202
|
-
# being alive.
|
256
|
+
# the Heartbeat class is essentially wrapper over an IPC channel that sends
|
257
|
+
# a ping on the channel indicating process health. if either end of the
|
258
|
+
# channel is detached the ping will fail and an error will be raised. in
|
259
|
+
# this way it is ensured that Slave objects cannot continue to live without
|
260
|
+
# their parent being alive.
|
203
261
|
#
|
204
262
|
class Heartbeat
|
205
263
|
#--{{{
|
@@ -223,6 +281,7 @@ require 'tempfile'
|
|
223
281
|
if Process::pid == @pid
|
224
282
|
@w.close
|
225
283
|
@pipe = @r
|
284
|
+
@pipe.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
|
226
285
|
parent_start
|
227
286
|
else
|
228
287
|
@r.close
|
@@ -273,6 +332,58 @@ require 'tempfile'
|
|
273
332
|
end
|
274
333
|
#--}}}
|
275
334
|
end
|
335
|
+
|
336
|
+
def start
|
337
|
+
#--{{{
|
338
|
+
if Process::pid == @pid
|
339
|
+
@r.close
|
340
|
+
@pipe = @w
|
341
|
+
@pipe.fcntl Fcntl::F_SETFD, Fcntl::FD_CLOEXEC
|
342
|
+
parent_start
|
343
|
+
else
|
344
|
+
@w.close
|
345
|
+
@pipe = @r
|
346
|
+
child_start
|
347
|
+
end
|
348
|
+
@beating = true
|
349
|
+
#--}}}
|
350
|
+
end
|
351
|
+
def parent_start
|
352
|
+
#--{{{
|
353
|
+
@whoami = 'parent'
|
354
|
+
@thread =
|
355
|
+
Thread::new(Thread::current) do |cur|
|
356
|
+
begin
|
357
|
+
sleep
|
358
|
+
rescue => e
|
359
|
+
cur.raise e
|
360
|
+
ensure
|
361
|
+
@pipe.close rescue nil
|
362
|
+
end
|
363
|
+
end
|
364
|
+
#--}}}
|
365
|
+
end
|
366
|
+
def child_start
|
367
|
+
#--{{{
|
368
|
+
@whoami = 'child'
|
369
|
+
@pid = Process::pid
|
370
|
+
@ppid = Process::ppid
|
371
|
+
@thread =
|
372
|
+
Thread::new(Thread::current) do |cur|
|
373
|
+
begin
|
374
|
+
trace{ "child reading..." }
|
375
|
+
@pipe.read
|
376
|
+
trace{ "child read." }
|
377
|
+
trace{ "child exiting." }
|
378
|
+
exit!
|
379
|
+
rescue => e
|
380
|
+
cur.raise e
|
381
|
+
ensure
|
382
|
+
@pipe.close rescue nil
|
383
|
+
end
|
384
|
+
end
|
385
|
+
#--}}}
|
386
|
+
end
|
276
387
|
def stop
|
277
388
|
#--{{{
|
278
389
|
raise "not beating" unless @beating
|
data/rdoc.cmd
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rdoc -a -d -F -S -m README -I jpg -N README
|
1
|
+
rdoc -a -d -F -S -m README -I jpg -N README lib/slave.rb
|
data/sample/a.rb
CHANGED
@@ -1,102 +1,19 @@
|
|
1
|
-
$:.unshift 'lib'
|
2
|
-
$:.unshift '../lib'
|
3
|
-
|
4
1
|
require 'slave'
|
5
2
|
|
6
|
-
class Incrementer
|
7
|
-
attr :decrementer, true
|
8
|
-
def increment n
|
9
|
-
n + 1
|
10
|
-
end
|
11
|
-
def decrement n
|
12
|
-
@decrementer.decrement n
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Decrementer
|
17
|
-
attr :incrementer, true
|
18
|
-
def increment n
|
19
|
-
@incrementer.increment n
|
20
|
-
end
|
21
|
-
def decrement n
|
22
|
-
n - 1
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# here we set up a triangle of communicating processes
|
30
3
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
# \ /
|
35
|
-
# \ /
|
36
|
-
# \ /
|
37
|
-
# parent
|
4
|
+
# simple usage is simply to stand up a server object as a slave. you do not
|
5
|
+
# need to wait for the server, join it, etc. it will die when the parent
|
6
|
+
# process dies - even under 'kill -9' conditions
|
38
7
|
#
|
39
|
-
#
|
40
|
-
|
41
|
-
incrementer_slave = Slave::new Incrementer::new
|
42
|
-
incrementer = incrementer_slave.object
|
43
8
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
puts
|
50
|
-
|
51
|
-
decrementer_slave = Slave::new Decrementer::new
|
52
|
-
decrementer = decrementer_slave.object
|
53
|
-
|
54
|
-
puts '---'
|
55
|
-
puts 'decrementer :'
|
56
|
-
puts " sockect : #{ decrementer_slave.socket.inspect }"
|
57
|
-
puts " uri : #{ decrementer_slave.uri.inspect }"
|
58
|
-
puts " pid : #{ decrementer_slave.pid.inspect }"
|
59
|
-
puts
|
60
|
-
|
61
|
-
#
|
62
|
-
# connect incrementer and decrementer
|
63
|
-
#
|
64
|
-
|
65
|
-
incrementer.decrementer = decrementer
|
66
|
-
decrementer.incrementer = incrementer
|
67
|
-
|
68
|
-
#
|
69
|
-
# now we can call methods on each drb object, and they can also call methods on
|
70
|
-
# each other
|
71
|
-
#
|
72
|
-
|
73
|
-
n = 0
|
74
|
-
|
75
|
-
n = incrementer.increment n
|
76
|
-
p n #=> 1
|
77
|
-
|
78
|
-
n = decrementer.decrement n
|
79
|
-
p n #=> 0
|
80
|
-
|
81
|
-
n = decrementer.increment n
|
82
|
-
p n #=> 1
|
83
|
-
|
84
|
-
n = incrementer.decrement n
|
85
|
-
p n #=> 0
|
86
|
-
|
87
|
-
#
|
88
|
-
# we can explicitly shutdown certain slaves
|
89
|
-
#
|
9
|
+
class Server
|
10
|
+
def add_two n
|
11
|
+
n + 2
|
12
|
+
end
|
13
|
+
end
|
90
14
|
|
91
|
-
|
92
|
-
|
93
|
-
p n #=> 42
|
15
|
+
slave = Slave.new Server.new
|
16
|
+
server = slave.object
|
94
17
|
|
95
|
-
|
96
|
-
# Slaves cannot live beyond their parent so we simply exit and all living slaves
|
97
|
-
# will eventually die. how long it takes to die is determined by the
|
98
|
-
# pulse_rate - the next time the Heartbeat trys to ping the parent the Slave
|
99
|
-
# will die.
|
100
|
-
#
|
18
|
+
p server.add_two(40) #=> 42
|
101
19
|
|
102
|
-
exit
|