slave 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|