splib 1.4.2 → 1.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/README.rdoc +74 -6
- data/Rakefile +1 -1
- data/lib/splib.rb +1 -0
- data/lib/splib/CodeReloader.rb +1 -4
- data/lib/splib/Exec.rb +6 -1
- data/lib/splib/Monitor.rb +131 -44
- data/lib/splib/PriorityQueue.rb +16 -5
- data/lib/splib/Sleep.rb +10 -0
- data/test/cases/CodeReloader.rb +1 -1
- data/test/cases/Exec.rb +7 -6
- data/test/cases/Monitor.rb +76 -40
- data/test/cases/PriorityQueue.rb +28 -0
- data/test/cases/Sleep.rb +24 -0
- metadata +10 -8
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
1.4.3
|
2
|
+
* Added new Splib.sleep to return actual sleep times that are useful
|
3
|
+
* Added Monitor#try_lock
|
4
|
+
* Modify locking behavior on Monitor#signal and Monitor#broadcast
|
5
|
+
* Updates to Monitor#wait when used with a timeout
|
6
|
+
* Added some simple checking to remove dead threads that fail to release their lock
|
7
|
+
* CodeReloader.reload_code returns new holder instead of gutted holder
|
1
8
|
1.4.2
|
2
9
|
* Modify Float#within_delta? to use #between? like any
|
3
10
|
reasonable person would
|
data/README.rdoc
CHANGED
@@ -21,14 +21,14 @@ The Spox Library is collection of helper methods and classes.
|
|
21
21
|
|
22
22
|
This library has been tested on:
|
23
23
|
|
24
|
-
* Ruby 1.8.6-
|
25
|
-
* Ruby 1.8.7-
|
26
|
-
* Ruby 1.9.1-
|
27
|
-
* JRuby 1.4
|
24
|
+
* Ruby 1.8.6-p399
|
25
|
+
* Ruby 1.8.7-p249
|
26
|
+
* Ruby 1.9.1-p378
|
27
|
+
* JRuby 1.4.0
|
28
28
|
|
29
29
|
=== Usage
|
30
30
|
|
31
|
-
The Spox Library has various things located within it. The Splib#load method will allow you to load individual parts of the library, or the entire thing into your program. Lets take a quick look at some of the things available from this library.
|
31
|
+
The Spox Library has various things located within it. The Splib#load method will allow you to load individual parts of the library, or the entire thing, into your program. Lets take a quick look at some of the things available from this library.
|
32
32
|
|
33
33
|
==== URL Shorteners
|
34
34
|
|
@@ -185,7 +185,75 @@ monitor does its best to ensure your threads stay where they are supposed.
|
|
185
185
|
[:foobar, :foo]
|
186
186
|
[:foobar, :foo, :bar]
|
187
187
|
|
188
|
-
|
188
|
+
The monitor also provides simple wait timers. See the following code:
|
189
|
+
|
190
|
+
require 'splib'
|
191
|
+
Splib.load :Monitor
|
192
|
+
|
193
|
+
monitor = Splib::Monitor.new
|
194
|
+
a = Queue.new
|
195
|
+
5.times{ Thread.new{ monitor.wait(0.1); a << 1; } }
|
196
|
+
sleep(0.2)
|
197
|
+
puts "Size: #{a.size}"
|
198
|
+
|
199
|
+
Here we have five threads waiting with a timeout. Nicely, the monitor only uses
|
200
|
+
a single thread for timing, instead of generating a new thread for each timeout.
|
201
|
+
|
202
|
+
==== Sleep
|
203
|
+
|
204
|
+
Make getting an actual amount of sleeping a bit easier:
|
205
|
+
|
206
|
+
require 'splib'
|
207
|
+
Splib.load :Sleep
|
208
|
+
|
209
|
+
puts Kernel.sleep(0.01)
|
210
|
+
puts Splib.sleep(0.01)
|
211
|
+
|
212
|
+
=>
|
213
|
+
0
|
214
|
+
0.00228595733642578
|
215
|
+
|
216
|
+
==== CodeReloader
|
217
|
+
|
218
|
+
Easily reload code into a module:
|
219
|
+
|
220
|
+
First, assume that file.rb starts out with the following contents:
|
221
|
+
|
222
|
+
class Foo
|
223
|
+
def test
|
224
|
+
puts 'Test'
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
Then, after the Splib.load_code call, we modify the file to contain:
|
229
|
+
|
230
|
+
class Foo
|
231
|
+
def untest
|
232
|
+
puts 'UnTest'
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
Okay, now we proceed:
|
237
|
+
|
238
|
+
require 'splib'
|
239
|
+
Splib.load :CodeReloader, :Constants
|
240
|
+
|
241
|
+
mod = Splib.load_code('file.rb')
|
242
|
+
foo = Splib.find_const('Foo', [mod]).new
|
243
|
+
p foo.respond_to?(:test)
|
244
|
+
puts foo.test
|
245
|
+
mod = Splib.reload_code(mod)
|
246
|
+
foo = Splib.find_const('Foo', [mod]).new
|
247
|
+
p foo.respond_to?(:test)
|
248
|
+
p foo.respond_to?(:untest)
|
249
|
+
puts foo.untest
|
250
|
+
|
251
|
+
=>
|
252
|
+
true
|
253
|
+
Test
|
254
|
+
false
|
255
|
+
true
|
256
|
+
UnTest
|
189
257
|
|
190
258
|
== Last remarks
|
191
259
|
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ spec = Gem::Specification.new do |s|
|
|
15
15
|
s.name = 'splib'
|
16
16
|
s.author = 'spox'
|
17
17
|
s.email = 'spox@modspox.com'
|
18
|
-
s.version = '1.4.
|
18
|
+
s.version = '1.4.3'
|
19
19
|
s.summary = 'Spox Library'
|
20
20
|
s.platform = Gem::Platform::RUBY
|
21
21
|
s.files = %w(LICENSE README.rdoc CHANGELOG Rakefile) + Dir.glob("{bin,lib,spec,test}/**/*")
|
data/lib/splib.rb
CHANGED
data/lib/splib/CodeReloader.rb
CHANGED
@@ -43,10 +43,7 @@ module Splib
|
|
43
43
|
# Reload the code within the module
|
44
44
|
def self.reload_code(holder)
|
45
45
|
raise ArgumentError.new('Expecting a module containing loaded code') unless holder.respond_to?(:path)
|
46
|
-
holder.
|
47
|
-
holder.send(:remove_const, const)
|
48
|
-
end
|
49
|
-
self.load_code(holder.path, holder)
|
46
|
+
self.load_code(holder.path)
|
50
47
|
end
|
51
48
|
|
52
49
|
# path:: path to ruby code
|
data/lib/splib/Exec.rb
CHANGED
@@ -3,7 +3,12 @@ require 'timeout'
|
|
3
3
|
module Splib
|
4
4
|
|
5
5
|
@@processes = []
|
6
|
-
|
6
|
+
@@owner ||= Thread.current
|
7
|
+
Kernel.at_exit do
|
8
|
+
if(Thread.current == @@owner)
|
9
|
+
@@processes.each{|pro| Process.kill('KILL', pro.pid) }
|
10
|
+
end
|
11
|
+
end
|
7
12
|
|
8
13
|
# Returns current array of running Processes
|
9
14
|
def self.running_procs
|
data/lib/splib/Monitor.rb
CHANGED
@@ -1,37 +1,42 @@
|
|
1
1
|
require 'thread'
|
2
2
|
|
3
3
|
module Splib
|
4
|
-
|
4
|
+
Splib.load :Sleep
|
5
|
+
# Basic exception to wakeup a monitor timer
|
6
|
+
class Wakeup < Exception
|
7
|
+
end
|
5
8
|
class Monitor
|
9
|
+
# Create a new Monitor
|
6
10
|
def initialize
|
7
11
|
@threads = []
|
8
12
|
@locks = []
|
9
13
|
@lock_owner = nil
|
10
14
|
@timers = {}
|
15
|
+
@timer = start_timer
|
16
|
+
@stop = false
|
17
|
+
Kernel.at_exit do
|
18
|
+
if(@timer)
|
19
|
+
@stop = true
|
20
|
+
@timer.raise Wakeup.new
|
21
|
+
end
|
22
|
+
end
|
11
23
|
end
|
24
|
+
|
12
25
|
# timeout:: Wait for given amount of time
|
13
26
|
# Park a thread here
|
14
27
|
def wait(timeout=nil)
|
28
|
+
raise 'This thread is already a registered sleeper' if @threads.include?(Thread.current)
|
29
|
+
Thread.exclusive{ @threads << Thread.current }
|
15
30
|
if(timeout)
|
16
|
-
|
17
|
-
@timers[Thread.current] =
|
18
|
-
|
19
|
-
until(time >= timeout) do
|
20
|
-
s = Time.now.to_f
|
21
|
-
sleep(timeout - time)
|
22
|
-
time += Time.now.to_f - s
|
23
|
-
end
|
24
|
-
t.wakeup
|
25
|
-
end
|
31
|
+
timeout = timeout.to_f
|
32
|
+
Thread.exclusive{ @timers[Thread.current] = timeout }
|
33
|
+
@timer.raise Wakeup.new
|
26
34
|
end
|
27
|
-
@threads << Thread.current
|
28
35
|
Thread.stop
|
29
|
-
@threads.delete(Thread.current)
|
30
|
-
if(timeout)
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
@timers.delete(Thread.current)
|
36
|
+
Thread.exclusive{ @threads.delete(Thread.current) }
|
37
|
+
if(timeout && @timers.has_key?(Thread.current))
|
38
|
+
Thread.exclusive{ @timers.delete(Thread.current) }
|
39
|
+
@timer.raise Wakeup.new
|
35
40
|
end
|
36
41
|
true
|
37
42
|
end
|
@@ -50,17 +55,22 @@ module Splib
|
|
50
55
|
# Wake up earliest thread
|
51
56
|
def signal
|
52
57
|
synchronize do
|
53
|
-
t = @threads.shift
|
54
|
-
|
58
|
+
while(t = @threads.shift)
|
59
|
+
if(t && t.alive? && t.stop?)
|
60
|
+
t.wakeup
|
61
|
+
break
|
62
|
+
else
|
63
|
+
next
|
64
|
+
end
|
65
|
+
end
|
55
66
|
end
|
56
67
|
end
|
57
68
|
# Wake up all threads
|
58
69
|
def broadcast
|
59
70
|
synchronize do
|
60
|
-
@threads.each do |t|
|
61
|
-
t.wakeup if t.alive?
|
71
|
+
@threads.dup.each do |t|
|
72
|
+
t.wakeup if t.alive? && t.stop?
|
62
73
|
end
|
63
|
-
@threads.clear
|
64
74
|
end
|
65
75
|
end
|
66
76
|
# Number of threads waiting
|
@@ -69,58 +79,135 @@ module Splib
|
|
69
79
|
end
|
70
80
|
# Lock the monitor
|
71
81
|
def lock
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
82
|
+
Thread.exclusive{ do_lock }
|
83
|
+
until(owner?(Thread.current)) do
|
84
|
+
Thread.stop
|
76
85
|
end
|
77
86
|
end
|
78
87
|
# Unlock the monitor
|
79
88
|
def unlock
|
80
|
-
|
89
|
+
do_unlock
|
90
|
+
end
|
91
|
+
# Attempt to lock. Returns true if lock is aquired and false if not.
|
92
|
+
def try_lock
|
93
|
+
locked = false
|
94
|
+
Thread.exclusive do
|
95
|
+
clean
|
96
|
+
unless(locked?(false))
|
97
|
+
do_lock
|
98
|
+
locked = true
|
99
|
+
else
|
100
|
+
locked = owner?(Thread.current)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
locked
|
81
104
|
end
|
105
|
+
# cln:: Clean dead threads
|
82
106
|
# Is monitor locked
|
83
|
-
def locked?
|
84
|
-
|
107
|
+
def locked?(cln=true)
|
108
|
+
Thread.exclusive{clean} if cln
|
109
|
+
@locks.size > 0 || @lock_owner
|
85
110
|
end
|
86
111
|
# Lock the monitor, execute block and unlock the monitor
|
87
112
|
def synchronize
|
88
113
|
result = nil
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
do_unlock
|
93
|
-
end
|
114
|
+
lock
|
115
|
+
result = yield
|
116
|
+
do_unlock
|
94
117
|
result
|
95
118
|
end
|
96
119
|
|
97
120
|
private
|
98
121
|
|
122
|
+
|
123
|
+
# This is a simple helper method to help keep threads from ending
|
124
|
+
# up stuck waiting for a lock when a thread locks the monitor and
|
125
|
+
# then decides to die without unlocking. It is only called when
|
126
|
+
# new locks are attempted or a check is made if the monitor is
|
127
|
+
# currently locked.
|
128
|
+
def clean
|
129
|
+
@locks.delete_if{|t|!t.alive?}
|
130
|
+
if(@lock_owner && !@lock_owner.alive?)
|
131
|
+
@lock_owner = @locks.empty? ? nil : @locks.shift
|
132
|
+
@lock_owner.wakeup if @lock_owner && !owner?(Thread.current)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Check if the givin thread is the current owner
|
99
137
|
def owner?(t)
|
100
138
|
@lock_owner == t
|
101
139
|
end
|
102
140
|
|
141
|
+
# Aquire monitor lock or be queued for lock
|
142
|
+
# NOTE: To make this method more generic and useful, it does
|
143
|
+
# not perform a Thread.exclusive, and as such this method should
|
144
|
+
# only be called from within a Thread.exclusive{}
|
103
145
|
def do_lock
|
104
|
-
|
146
|
+
clean
|
105
147
|
if(@lock_owner)
|
106
|
-
|
107
|
-
|
148
|
+
if(owner?(Thread.current))
|
149
|
+
@locks.unshift(Thread.current)
|
150
|
+
else
|
151
|
+
@locks << Thread.current
|
152
|
+
end
|
108
153
|
else
|
109
154
|
@lock_owner = Thread.current
|
110
155
|
end
|
111
|
-
|
156
|
+
true
|
112
157
|
end
|
113
158
|
|
159
|
+
# Unlock the monitor
|
114
160
|
def do_unlock
|
115
161
|
unless(owner?(Thread.current))
|
116
162
|
raise ThreadError.new("Thread #{Thread.current} is not the current owner: #{@lock_owner}")
|
117
163
|
end
|
118
|
-
|
164
|
+
Thread.exclusive do
|
119
165
|
@locks.delete_if{|t|!t.alive?}
|
120
|
-
@
|
121
|
-
|
122
|
-
|
123
|
-
|
166
|
+
unless(@locks.empty?)
|
167
|
+
old_owner = @lock_owner
|
168
|
+
@lock_owner = @locks.shift
|
169
|
+
@lock_owner.wakeup unless old_owner == @lock_owner
|
170
|
+
else
|
171
|
+
@lock_owner = nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Starts the timer for waiting threads with a timeout
|
177
|
+
def start_timer
|
178
|
+
@timer = Thread.new do
|
179
|
+
begin
|
180
|
+
until(@stop) do
|
181
|
+
cur = []
|
182
|
+
t = 0
|
183
|
+
Thread.exclusive do
|
184
|
+
t = @timers.values.min
|
185
|
+
cur = @timers.dup
|
186
|
+
end
|
187
|
+
t = 0 if !t.nil? && t < 0
|
188
|
+
a = 0
|
189
|
+
begin
|
190
|
+
a = Splib.sleep(t)
|
191
|
+
rescue Wakeup
|
192
|
+
# do nothing of importance
|
193
|
+
ensure
|
194
|
+
next if t.nil?
|
195
|
+
Thread.exclusive do
|
196
|
+
cur.each_pair do |thread, value|
|
197
|
+
value -= a
|
198
|
+
if(value <= 0)
|
199
|
+
thread.wakeup
|
200
|
+
@timers.delete(thread)
|
201
|
+
else
|
202
|
+
@timers[thread] = value
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
rescue
|
209
|
+
retry
|
210
|
+
end
|
124
211
|
end
|
125
212
|
end
|
126
213
|
end
|
data/lib/splib/PriorityQueue.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
Splib.load :Monitor
|
2
|
+
|
2
3
|
module Splib
|
3
4
|
# Exception raised when queue is empty
|
4
|
-
class EmptyQueue <
|
5
|
+
class EmptyQueue < RuntimeError
|
5
6
|
end
|
6
7
|
# This class provides some simple logic for item output. It is
|
7
8
|
# basically a priority based queue with some round robin thrown
|
@@ -19,7 +20,7 @@ module Splib
|
|
19
20
|
@whocares = whocares
|
20
21
|
@target_queues = {}
|
21
22
|
@queues = {:PRIORITY => [], :NEW => [], :NORMAL => [], :WHOCARES => []}
|
22
|
-
@lock =
|
23
|
+
@lock = Splib::Monitor.new
|
23
24
|
end
|
24
25
|
|
25
26
|
# target:: target queue
|
@@ -42,6 +43,7 @@ module Splib
|
|
42
43
|
add_queue(:NORMAL, @target_queues[target])
|
43
44
|
end
|
44
45
|
end
|
46
|
+
@lock.signal
|
45
47
|
end
|
46
48
|
item
|
47
49
|
end
|
@@ -54,6 +56,7 @@ module Splib
|
|
54
56
|
@target_queues[:internal_prio] = [] unless @target_queues[:internal_prio]
|
55
57
|
@target_queues[:internal_prio] << message
|
56
58
|
add_queue(:PRIORITY, @target_queues[:internal_prio])
|
59
|
+
@lock.signal
|
57
60
|
end
|
58
61
|
message
|
59
62
|
end
|
@@ -77,8 +80,15 @@ module Splib
|
|
77
80
|
end
|
78
81
|
end
|
79
82
|
end
|
80
|
-
|
81
|
-
|
83
|
+
unless(m)
|
84
|
+
if(@raise)
|
85
|
+
raise EmptyQueue.new('Queue is currently empty')
|
86
|
+
else
|
87
|
+
@lock.wait_while{ empty? }
|
88
|
+
m = pop
|
89
|
+
end
|
90
|
+
end
|
91
|
+
m
|
82
92
|
end
|
83
93
|
|
84
94
|
# Returns true if queue is empty
|
@@ -87,6 +97,7 @@ module Splib
|
|
87
97
|
end
|
88
98
|
|
89
99
|
alias :push :prioritized_queue
|
100
|
+
alias :<< :direct_queue
|
90
101
|
|
91
102
|
private
|
92
103
|
|
data/lib/splib/Sleep.rb
ADDED
data/test/cases/CodeReloader.rb
CHANGED
@@ -28,7 +28,7 @@ class CodeReloaderTest < Test::Unit::TestCase
|
|
28
28
|
assert(!obj.respond_to?(:feebar))
|
29
29
|
assert_equal('hello world', obj.foobar)
|
30
30
|
FileUtils.cp @s2, @s
|
31
|
-
Splib.reload_code(holder)
|
31
|
+
holder = Splib.reload_code(holder)
|
32
32
|
klass = Splib.find_const('Fu::Bar', [holder])
|
33
33
|
obj = klass.new
|
34
34
|
assert(obj.respond_to?(:feebar))
|
data/test/cases/Exec.rb
CHANGED
@@ -4,26 +4,27 @@ require 'test/unit'
|
|
4
4
|
class ExecTest < Test::Unit::TestCase
|
5
5
|
def setup
|
6
6
|
Splib.load :Exec
|
7
|
+
Splib.load :Sleep
|
7
8
|
end
|
8
9
|
|
9
10
|
def test_exec
|
10
11
|
assert_raise(IOError) do
|
11
|
-
Splib.exec('echo test', 10, 1)
|
12
|
+
Splib.exec('/bin/sh -c "echo test"', 10, 1)
|
12
13
|
end
|
13
14
|
assert_raise(Timeout::Error) do
|
14
|
-
Splib.exec('while [ true ]; do true; done;', 1)
|
15
|
+
Splib.exec('/bin/sh -c "while [ true ]; do true; done;"', 1)
|
15
16
|
end
|
16
|
-
assert_equal("test\n", Splib.exec('echo test'))
|
17
|
+
assert_equal("test\n", Splib.exec('/bin/sh -c "echo test"'))
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_running
|
20
21
|
output = nil
|
21
22
|
Thread.new do
|
22
|
-
output = Splib.exec('
|
23
|
+
output = Splib.exec('/bin/sh -c "sleep 0.4; echo done"')
|
23
24
|
end
|
24
|
-
sleep(0.1)
|
25
|
+
Kernel.sleep(0.1)
|
25
26
|
assert_equal(1, Splib.running_procs.size)
|
26
|
-
sleep(0.5)
|
27
|
+
Kernel.sleep(0.5)
|
27
28
|
assert_equal("done\n", output)
|
28
29
|
assert_equal(0, Splib.running_procs.size)
|
29
30
|
end
|
data/test/cases/Monitor.rb
CHANGED
@@ -2,15 +2,16 @@ require 'splib'
|
|
2
2
|
require 'test/unit'
|
3
3
|
|
4
4
|
class MonitorTest < Test::Unit::TestCase
|
5
|
+
Splib.load :Monitor
|
6
|
+
Splib.load :Sleep
|
5
7
|
def setup
|
6
|
-
Splib.load :Monitor
|
7
8
|
@monitor = Splib::Monitor.new
|
8
9
|
end
|
9
10
|
|
10
11
|
def test_wait
|
11
12
|
t = []
|
12
13
|
5.times{ t << Thread.new{ @monitor.wait } }
|
13
|
-
sleep(0.
|
14
|
+
Splib.sleep(0.1) # give threads a chance to wait
|
14
15
|
t.each do |thread|
|
15
16
|
assert(thread.alive?)
|
16
17
|
assert(thread.stop?)
|
@@ -19,139 +20,174 @@ class MonitorTest < Test::Unit::TestCase
|
|
19
20
|
|
20
21
|
def test_wait_timeout
|
21
22
|
t = []
|
22
|
-
o =
|
23
|
-
5.times{
|
24
|
-
sleep(0.
|
25
|
-
Thread.pass
|
26
|
-
assert(!t.shift.alive?)
|
27
|
-
assert_equal(1, o.size)
|
28
|
-
sleep(0.1)
|
23
|
+
o = Queue.new
|
24
|
+
5.times{ t << Thread.new{ @monitor.wait(0.1); o << 1 } }
|
25
|
+
Splib.sleep(0.3)
|
29
26
|
assert_equal(5, o.size)
|
30
|
-
t.each do |th|
|
31
|
-
assert(!th.alive?)
|
32
|
-
end
|
33
27
|
end
|
34
28
|
|
35
29
|
def test_signal
|
36
|
-
output =
|
30
|
+
output = Queue.new
|
37
31
|
t = []
|
38
32
|
5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
|
39
|
-
sleep(0.01)
|
33
|
+
Splib.sleep(0.01)
|
40
34
|
t.each do |thread|
|
41
35
|
assert(thread.alive?)
|
42
36
|
assert(thread.stop?)
|
43
37
|
end
|
44
38
|
assert(output.empty?)
|
45
39
|
@monitor.signal
|
46
|
-
sleep(0.01)
|
40
|
+
Splib.sleep(0.01)
|
47
41
|
assert_equal(4, t.select{|th|th.alive?}.size)
|
48
42
|
assert_equal(1, output.size)
|
49
43
|
assert_equal(1, output.pop)
|
50
44
|
end
|
51
45
|
|
52
46
|
def test_broadcast
|
53
|
-
output =
|
47
|
+
output = Queue.new
|
54
48
|
t = []
|
55
49
|
5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
|
56
|
-
sleep(0.01)
|
50
|
+
Splib.sleep(0.01)
|
57
51
|
t.each do |thread|
|
58
52
|
assert(thread.alive?)
|
59
53
|
assert(thread.stop?)
|
60
54
|
end
|
55
|
+
assert_equal(5, t.size)
|
61
56
|
assert(output.empty?)
|
62
57
|
@monitor.broadcast
|
63
|
-
sleep(0.
|
58
|
+
Splib.sleep(0.1)
|
64
59
|
assert_equal(5, output.size)
|
65
60
|
5.times{ assert_equal(1, output.pop) }
|
66
61
|
assert_equal(5, t.select{|th|!th.alive?}.size)
|
67
62
|
end
|
68
63
|
|
64
|
+
def test_synchronize_broadcast
|
65
|
+
output = Queue.new
|
66
|
+
t = []
|
67
|
+
5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
|
68
|
+
Splib.sleep(0.01)
|
69
|
+
t.each do |thread|
|
70
|
+
assert(thread.alive?)
|
71
|
+
assert(thread.stop?)
|
72
|
+
end
|
73
|
+
assert_equal(5, t.size)
|
74
|
+
assert(output.empty?)
|
75
|
+
@monitor.synchronize{ @monitor.broadcast }
|
76
|
+
Splib.sleep(0.1)
|
77
|
+
assert_equal(5, output.size)
|
78
|
+
5.times{ assert_equal(1, output.pop) }
|
79
|
+
assert_equal(5, t.select{|th|!th.alive?}.size)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_multi_lock
|
83
|
+
@monitor.synchronize do
|
84
|
+
@monitor.synchronize do
|
85
|
+
@monitor.lock
|
86
|
+
@monitor.synchronize do
|
87
|
+
true
|
88
|
+
end
|
89
|
+
@monitor.unlock
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
69
94
|
def test_wait_while
|
70
95
|
stop = true
|
71
96
|
t = Thread.new{ @monitor.wait_while{ stop } }
|
72
|
-
sleep(0.01)
|
97
|
+
Splib.sleep(0.01)
|
73
98
|
assert(t.alive?)
|
74
99
|
assert(t.stop?)
|
75
100
|
@monitor.signal
|
76
|
-
sleep(0.01)
|
101
|
+
Splib.sleep(0.01)
|
77
102
|
assert(t.alive?)
|
78
103
|
assert(t.stop?)
|
79
104
|
@monitor.broadcast
|
80
|
-
sleep(0.01)
|
105
|
+
Splib.sleep(0.01)
|
81
106
|
assert(t.alive?)
|
82
107
|
assert(t.stop?)
|
83
108
|
stop = false
|
84
109
|
@monitor.signal
|
85
|
-
sleep(0.01)
|
110
|
+
Splib.sleep(0.01)
|
86
111
|
assert(!t.alive?)
|
87
112
|
assert(t.stop?)
|
88
113
|
end
|
89
114
|
|
90
115
|
def test_wait_until
|
91
116
|
stop = false
|
92
|
-
|
93
|
-
|
117
|
+
done = false
|
118
|
+
t = Thread.new{ @monitor.wait_until{ stop }; done = true; }
|
119
|
+
Splib.sleep(0.01)
|
94
120
|
assert(t.alive?)
|
95
121
|
assert(t.stop?)
|
96
122
|
@monitor.signal
|
97
|
-
sleep(0.01)
|
123
|
+
Splib.sleep(0.01)
|
98
124
|
assert(t.alive?)
|
99
125
|
assert(t.stop?)
|
100
126
|
@monitor.broadcast
|
101
|
-
sleep(0.01)
|
127
|
+
Splib.sleep(0.01)
|
102
128
|
assert(t.alive?)
|
103
129
|
assert(t.stop?)
|
104
130
|
stop = true
|
105
131
|
@monitor.signal
|
106
|
-
sleep(0.
|
107
|
-
assert(
|
108
|
-
assert(t.stop?)
|
132
|
+
Splib.sleep(0.1)
|
133
|
+
assert(done)
|
109
134
|
end
|
110
135
|
|
111
136
|
def test_waiters
|
112
137
|
t = []
|
113
138
|
(rand(20)+1).times{ t << Thread.new{ @monitor.wait } }
|
114
|
-
sleep(0.
|
139
|
+
Splib.sleep(0.1)
|
115
140
|
assert_equal(t.size, @monitor.waiters)
|
116
141
|
@monitor.broadcast
|
117
|
-
sleep(0.
|
142
|
+
Splib.sleep(0.1)
|
118
143
|
assert_equal(0, @monitor.waiters)
|
119
144
|
end
|
120
145
|
|
121
146
|
def test_lock_unlock
|
122
147
|
t = []
|
123
148
|
output = []
|
124
|
-
3.times{|i| t << Thread.new{ @monitor.lock; sleep(
|
125
|
-
sleep(0.
|
149
|
+
3.times{|i| t << Thread.new{ @monitor.lock; Splib.sleep(0.1); output << i; @monitor.unlock;}}
|
150
|
+
Splib.sleep(0.12)
|
126
151
|
assert_equal(1, output.size)
|
127
|
-
sleep(0.
|
152
|
+
Splib.sleep(0.12)
|
128
153
|
assert_equal(2, output.size)
|
129
|
-
sleep(0.
|
154
|
+
Splib.sleep(0.12)
|
130
155
|
assert_equal(3, output.size)
|
131
156
|
assert(!t.any?{|th|th.alive?})
|
132
157
|
3.times{|i|assert_equal(i, output.shift)}
|
133
158
|
end
|
134
|
-
|
159
|
+
|
135
160
|
def test_lock_unlock_wakeup
|
136
161
|
complete = false
|
137
|
-
t1 = Thread.new{@monitor.lock; sleep(0.1); @monitor.unlock}
|
162
|
+
t1 = Thread.new{@monitor.lock; Splib.sleep(0.1); @monitor.unlock}
|
163
|
+
Splib.sleep(0.01)
|
138
164
|
t2 = Thread.new{@monitor.lock; complete = true; @monitor.unlock}
|
139
165
|
assert(!complete)
|
140
166
|
assert(t1.alive?)
|
141
167
|
t2.wakeup
|
142
168
|
Thread.pass
|
143
169
|
assert(!complete)
|
144
|
-
sleep(0.
|
170
|
+
Splib.sleep(0.15)
|
145
171
|
assert(complete)
|
146
172
|
end
|
147
173
|
|
148
174
|
def synchronize
|
149
175
|
t = []
|
150
176
|
output = []
|
151
|
-
5.times{|i| t << Thread.new{ @monitor.lock; sleep(i/100.0); output << i; @monitor.unlock;}}
|
177
|
+
5.times{|i| t << Thread.new{ @monitor.lock; Splib.sleep(i/100.0); output << i; @monitor.unlock;}}
|
152
178
|
@monitor.synchronize{ output << :done }
|
153
|
-
sleep(0.5)
|
179
|
+
Splib.sleep(0.5)
|
154
180
|
assert_equal(6, output.size)
|
155
181
|
end
|
156
182
|
|
183
|
+
def test_try_lock
|
184
|
+
assert(@monitor.try_lock)
|
185
|
+
assert(@monitor.locked?)
|
186
|
+
assert(@monitor.try_lock)
|
187
|
+
Thread.new{ assert(!@monitor.try_lock) }
|
188
|
+
@monitor.unlock
|
189
|
+
assert(!@monitor.locked?)
|
190
|
+
Thread.new{ assert(@monitor.try_lock); @monitor.unlock }
|
191
|
+
end
|
192
|
+
|
157
193
|
end
|
data/test/cases/PriorityQueue.rb
CHANGED
@@ -42,4 +42,32 @@ class PriorityQueueTest < Test::Unit::TestCase
|
|
42
42
|
assert_equal('last', queue.pop)
|
43
43
|
assert(queue.empty?)
|
44
44
|
end
|
45
|
+
|
46
|
+
def test_raise
|
47
|
+
queue = Splib::PriorityQueue.new(:raise_on_empty)
|
48
|
+
assert_raise(Splib::EmptyQueue){ queue.pop }
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_waiters
|
52
|
+
queue = Splib::PriorityQueue.new
|
53
|
+
q = Queue.new
|
54
|
+
t = Thread.new{ q << queue.pop; }
|
55
|
+
assert(t.alive?)
|
56
|
+
queue << :item1
|
57
|
+
sleep(0.1)
|
58
|
+
assert_equal(:item1, q.pop)
|
59
|
+
t = []
|
60
|
+
5.times{ t << Thread.new{ q << queue.pop } }
|
61
|
+
sleep(0.1)
|
62
|
+
assert_equal(5, t.find_all{|x|x.alive?}.size)
|
63
|
+
queue << :item2
|
64
|
+
sleep(0.1)
|
65
|
+
assert_equal(1, q.size)
|
66
|
+
queue.push(:foo, :item3)
|
67
|
+
sleep(0.1)
|
68
|
+
assert_equal(2, q.size)
|
69
|
+
3.times{ queue << :item4 }
|
70
|
+
sleep(0.1)
|
71
|
+
assert_equal(5, q.size)
|
72
|
+
end
|
45
73
|
end
|
data/test/cases/Sleep.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'splib'
|
5
|
+
|
6
|
+
class SleepTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
Splib.load :Sleep
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_sleep_valid
|
12
|
+
assert(Splib.sleep(0.5).between?(0.45, 0.55))
|
13
|
+
assert(Splib.sleep(0.05).between?(0.04, 0.06))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_sleep_invalid
|
17
|
+
assert_raise(TypeError) do
|
18
|
+
Splib.sleep(:foo)
|
19
|
+
end
|
20
|
+
assert_raise(ArgumentError) do
|
21
|
+
Splib.sleep(-1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: splib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- spox
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-04-06 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,7 +27,7 @@ files:
|
|
27
27
|
- README.rdoc
|
28
28
|
- CHANGELOG
|
29
29
|
- Rakefile
|
30
|
-
- lib/splib
|
30
|
+
- lib/splib
|
31
31
|
- lib/splib/Array.rb
|
32
32
|
- lib/splib/PriorityQueue.rb
|
33
33
|
- lib/splib/UrlShorteners.rb
|
@@ -38,7 +38,10 @@ files:
|
|
38
38
|
- lib/splib/HumanIdealRandomIterator.rb
|
39
39
|
- lib/splib/Monitor.rb
|
40
40
|
- lib/splib/Conversions.rb
|
41
|
+
- lib/splib/Sleep.rb
|
42
|
+
- lib/splib.rb
|
41
43
|
- spec/dummy.rb
|
44
|
+
- test/cases
|
42
45
|
- test/cases/Array.rb
|
43
46
|
- test/cases/PriorityQueue.rb
|
44
47
|
- test/cases/UrlShorteners.rb
|
@@ -49,13 +52,12 @@ files:
|
|
49
52
|
- test/cases/HumanIdealRandomIterator.rb
|
50
53
|
- test/cases/Monitor.rb
|
51
54
|
- test/cases/Conversions.rb
|
55
|
+
- test/cases/Sleep.rb
|
52
56
|
- test/run_tests.rb
|
53
57
|
- test/samplecode2.rb
|
54
58
|
- test/samplecode1.rb
|
55
|
-
has_rdoc:
|
59
|
+
has_rdoc: false
|
56
60
|
homepage: http://github.com/spox/splib
|
57
|
-
licenses: []
|
58
|
-
|
59
61
|
post_install_message:
|
60
62
|
rdoc_options:
|
61
63
|
- --title
|
@@ -80,9 +82,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
82
|
requirements: []
|
81
83
|
|
82
84
|
rubyforge_project:
|
83
|
-
rubygems_version: 1.3.
|
85
|
+
rubygems_version: 1.3.1
|
84
86
|
signing_key:
|
85
|
-
specification_version:
|
87
|
+
specification_version: 2
|
86
88
|
summary: Spox Library
|
87
89
|
test_files: []
|
88
90
|
|