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 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
@@ -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-p376
25
- * Ruby 1.8.7-p248
26
- * Ruby 1.9.1-p383
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
- ==== TODO: Write examples for CodeReloader and RandomIterator
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.2'
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}/**/*")
@@ -8,6 +8,7 @@ module Splib
8
8
  :HumanIdealRandomIterator,
9
9
  :Monitor,
10
10
  :PriorityQueue,
11
+ :Sleep,
11
12
  :UrlShorteners
12
13
  ]
13
14
  # args:: name of library to load
@@ -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.constants.each do |const|
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
@@ -3,7 +3,12 @@ require 'timeout'
3
3
  module Splib
4
4
 
5
5
  @@processes = []
6
- Kernel.at_exit{@@processes.each{|p| Process.kill('KILL', pro.pid) }}
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
@@ -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
- timout = timeout.to_f
17
- @timers[Thread.current] = Thread.new(Thread.current) do |t|
18
- time = 0.0
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
- if(@timers[Thread.current].alive?)
32
- @timers[Thread.current].kill
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
- t.wakeup if t && t.alive?
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
- if(Thread.exclusive{do_lock})
73
- until(owner?(Thread.current)) do
74
- Thread.stop
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
- Thread.exclusive{ do_unlock }
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
- @locks.size > 0
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
- Thread.exclusive do
90
- do_lock
91
- result = yield
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
- stop = false
146
+ clean
105
147
  if(@lock_owner)
106
- @locks << Thread.current
107
- stop = true
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
- stop
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
- unless(@locks.empty?)
164
+ Thread.exclusive do
119
165
  @locks.delete_if{|t|!t.alive?}
120
- @lock_owner = @locks.shift
121
- @lock_owner.wakeup
122
- else
123
- @lock_owner = nil
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
@@ -1,7 +1,8 @@
1
- require 'thread'
1
+ Splib.load :Monitor
2
+
2
3
  module Splib
3
4
  # Exception raised when queue is empty
4
- class EmptyQueue < Exception
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 = Mutex.new
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
- raise EmptyQueue.new('Queue is currently empty') if m.nil? && @raise
81
- return m
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
 
@@ -0,0 +1,10 @@
1
+ module Splib
2
+ class << self
3
+ # secs:: Number of seconds to sleep (Use float to provide better actual sleep time)
4
+ def sleep(secs=nil)
5
+ start = Time.now.to_f
6
+ secs.nil? ? Kernel.sleep : Kernel.sleep(secs)
7
+ Time.now.to_f - start
8
+ end
9
+ end
10
+ end
@@ -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))
@@ -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('ruby -e \'sleep(0.4); puts "done"\'')
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
@@ -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.01) # give threads a chance to wait
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{|i| t << Thread.new{ @monitor.wait((i+1)/100.0); o << 1 } }
24
- sleep(0.011)
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.01)
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
- t = Thread.new{ @monitor.wait_until{ stop } }
93
- sleep(0.01)
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.01)
107
- assert(!t.alive?)
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.01)
139
+ Splib.sleep(0.1)
115
140
  assert_equal(t.size, @monitor.waiters)
116
141
  @monitor.broadcast
117
- sleep(0.01)
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((i+1)/100.0); output << i; @monitor.unlock;}}
125
- sleep(0.011)
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.021)
152
+ Splib.sleep(0.12)
128
153
  assert_equal(2, output.size)
129
- sleep(0.031)
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.11)
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
@@ -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
@@ -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.2
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-01-29 00:00:00 -08:00
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.rb
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: true
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.5
85
+ rubygems_version: 1.3.1
84
86
  signing_key:
85
- specification_version: 3
87
+ specification_version: 2
86
88
  summary: Spox Library
87
89
  test_files: []
88
90