splib 1.4.2 → 1.4.3
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/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
|
|