wires 0.2.8 → 0.2.9

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/wires/hub.rb +49 -29
  3. data/lib/wires/time.rb +46 -38
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dadfbad6be58d85473f3742baef26fe8dc4ef70d
4
- data.tar.gz: 5e3f4739b620686a558f8c4265557d71cf819176
3
+ metadata.gz: 2db21e3f9e121e59a5bb749f91bfc99671408c69
4
+ data.tar.gz: e05678e737f152a47a9ccd3e7b14214d2ac61f4b
5
5
  SHA512:
6
- metadata.gz: a3c1d8fffaf16e1672cc8b6d16818300f8bf22104463647530d931f167373f8ca0de6abb2f7db8227b7549643e41ab9080a6f2ca2320d52eb64d053674a6832b
7
- data.tar.gz: 325e54850fe5774c5b1ba1d70e257790b1dd50a2229ee69eafedbbbd7407cf15972750770de991a7ea33b795dc8366fd1fb86275d270dad3333add5a2ae84bfa
6
+ metadata.gz: fb026f33a976e5c66d0da73e28bf5ac47deae08b8c1589df176bf70c471c4ea63b8d281777a4416b883258a91e820aeda776db7df0b167441b09b1a5f180c3cf
7
+ data.tar.gz: 03fbb2d4b977391eecfc75d4f3dfb259dd57b9345bd6c96e050020af2917dac2ad6ced83c89b6ddbb4b12b06b4e720ad611a9e61865c5f00d3b581e975169ce5
data/lib/wires/hub.rb CHANGED
@@ -10,6 +10,8 @@ module Wires
10
10
  # Allow user to get/set limit to number of child threads
11
11
  attr_accessor :max_child_threads
12
12
 
13
+ private
14
+
13
15
  # Make subclasses call class_init
14
16
  def inherited(subcls); subcls.class_init end
15
17
 
@@ -31,15 +33,20 @@ module Wires
31
33
 
32
34
  @please_finish_all = false
33
35
 
34
- @at_exit = Proc.new{nil}
35
- at_exit do self.at_exit_proc end
36
+ @on_neglect = Proc.new do |args|
37
+ $stderr.puts "#{self} neglected to spawn task: #{args.inspect}"
38
+ end
39
+ @on_neglect_done = Proc.new do |args|
40
+ $stderr.puts "#{self} finally spawned neglected task: #{args.inspect}"
41
+ end
42
+
43
+ at_exit { (sleep 0.05 until dead?) unless $! }
36
44
 
37
45
  state_machine_init
38
46
 
39
47
  nil end
40
48
 
41
- def at_exit_proc; @at_exit.call; end
42
-
49
+ public
43
50
 
44
51
  def dead?; state==:dead end
45
52
  def alive?; state==:alive end
@@ -68,10 +75,8 @@ module Wires
68
75
  # until all child threads are done
69
76
  def kill(*flags)
70
77
  sleep 0 until @spawning_count <= 0
71
- # @spawning_count_lock.synchronize do
72
- @please_finish_all = (not flags.include? :purge_tasks)
73
- sleep 0 until request_state :dead unless (flags.include? :nonblocking)
74
- # end
78
+ @please_finish_all = (not flags.include? :purge_tasks)
79
+ sleep 0 until request_state :dead unless (flags.include? :nonblocking)
75
80
  nil end
76
81
 
77
82
  # Register hook to execute before run - can call multiple times
@@ -94,6 +99,13 @@ module Wires
94
99
  @after_kills << [block, retain]
95
100
  nil end
96
101
 
102
+ def on_neglect(&block)
103
+ @on_neglect=block
104
+ end
105
+ def on_neglect_done(&block)
106
+ @on_neglect_done=block
107
+ end
108
+
97
109
  # Spawn a task
98
110
  def spawn(*args) # :args: event, ch_string, proc, blocking
99
111
  @spawning_count_lock.synchronize { @spawning_count += 1 }
@@ -136,38 +148,59 @@ module Wires
136
148
 
137
149
  def purge_neglected
138
150
  @neglected_lock.synchronize do
139
- @neglected = Array.new
151
+ @neglected.clear
152
+ end
153
+ nil end
154
+
155
+ def number_neglected
156
+ @neglected_lock.synchronize do
157
+ @neglected.size
140
158
  end
141
159
  end
142
160
 
161
+ # Join child threads, one by one, allowing more children to appear
162
+ def join_children
163
+ a_thread = Thread.new{nil}
164
+ while a_thread
165
+ @child_threads_lock.synchronize do
166
+ a_thread = @child_threads.shift
167
+ end
168
+ a_thread.join if ((a_thread) and (a_thread!=Thread.current))
169
+ sleep 0 # Yield to other threads
170
+ end
171
+ nil end
172
+
143
173
  private
144
174
 
145
175
  # Temporarily neglect a task until resources are available to run it
146
176
  def neglect(*args)
147
- $stderr.puts "#{self} neglected to spawn #{args.inspect}"
148
177
  @neglected_lock.synchronize do
178
+ @on_neglect.call(args)
149
179
  @neglected << args
150
180
  end
151
181
  false end
152
182
 
153
183
  # Run a chain of @neglected tasks in place until no more are waiting
154
184
  def spawn_neglected_task_chain
155
- neglected_one = nil
156
- @neglected_lock.synchronize do
185
+ args = @neglected_lock.synchronize do
157
186
  return nil if @neglected.empty?
158
- neglected_one = @neglected.shift
187
+ ((@neglected.shift)[0...-1]<<true) # Call with blocking
159
188
  end
160
- spawn(*((neglected_one)[0...-1]<<true)) # Call with blocking
189
+ spawn(*args)
190
+ @on_neglect_done.call(args)
161
191
  spawn_neglected_task_chain
162
192
  nil end
163
193
 
164
194
  # Flush @neglected task queue, each in a new thread
165
195
  def spawn_neglected_task_threads
166
196
  until (cease||=false)
167
- @neglected_lock.synchronize do
197
+ args = @neglected_lock.synchronize do
168
198
  break if (cease = @neglected.empty?)
169
- spawn(*((@neglected.shift)[0...-1]<<false)) # Call without blocking
199
+ ((@neglected.shift)[0...-1]<<false) # Call without blocking
170
200
  end
201
+ break if cease
202
+ spawn(*args)
203
+ @on_neglect_done.call(args)
171
204
  end
172
205
  nil end
173
206
 
@@ -185,19 +218,6 @@ module Wires
185
218
  end
186
219
  nil end
187
220
 
188
- # Join child threads, one by one, allowing more children to appear
189
- def join_children
190
- a_thread = Thread.new{nil}
191
- while a_thread
192
- @child_threads_lock.synchronize do
193
- # flush_queue
194
- a_thread = @child_threads.shift
195
- end
196
- a_thread.join if a_thread
197
- sleep 0 # Yield to other threads
198
- end
199
- nil end
200
-
201
221
  end
202
222
 
203
223
 
data/lib/wires/time.rb CHANGED
@@ -37,7 +37,9 @@ module Wires
37
37
 
38
38
  def active?; @active end
39
39
  def inactive?; not @active end
40
- def ready?; @active and (Time.now >= @time) end
40
+
41
+ def ready?(at_time=Time.now); @active and (at_time >= @time) end
42
+
41
43
  def time_until; (@active ? [(Time.now - @time), 0].max : nil) end
42
44
 
43
45
  def cancel; @active = false ;nil end
@@ -83,6 +85,8 @@ module Wires
83
85
  @schedule_lock = Monitor.new
84
86
  @dont_sleep = false
85
87
 
88
+ @grain = 1.seconds
89
+
86
90
  # Operate on the metaclass as a type of singleton pattern
87
91
  class << self
88
92
 
@@ -90,7 +94,6 @@ module Wires
90
94
  def add(new_item)
91
95
  expect_type new_item, TimeSchedulerItem
92
96
  schedule_add(new_item)
93
- wakeup
94
97
  nil end
95
98
  # Add an event to the schedule using << operator
96
99
  alias_method :<<, :add
@@ -98,18 +101,26 @@ module Wires
98
101
  # Get a copy of the event schedule from outside the class
99
102
  def list; @schedule.clone end
100
103
  # Clear the event schedule from outside the class
101
- def clear; @schedule.clear end
104
+ def clear; schedule_clear end
102
105
 
103
106
  private
104
107
 
108
+ def schedule_clear
109
+ @schedule.clear
110
+ end
111
+
105
112
  def schedule_reshuffle
106
113
  @schedule.select! {|x| x.active?}
107
114
  @schedule.sort! {|a,b| a.time <=> b.time}
108
115
  nil end
109
116
 
110
117
  def schedule_add(new_item)
111
- @schedule << new_item
112
- schedule_reshuffle
118
+ if new_item.ready?(@next_pass)
119
+ Thread.new{ new_item.fire_when_ready(blocking:true) }
120
+ else
121
+ @schedule << new_item
122
+ schedule_reshuffle
123
+ end
113
124
  nil end
114
125
 
115
126
  def schedule_concat(other_list)
@@ -118,72 +129,69 @@ module Wires
118
129
  nil end
119
130
 
120
131
  def schedule_pull
121
- pending = Array.new
132
+ pending_now = Array.new
133
+ pending_soon = Array.new
122
134
  while ((not @schedule.empty?) and @schedule[0].ready?)
123
- pending << @schedule.shift
135
+ pending_now << @schedule.shift
136
+ end
137
+ while ((not @schedule.empty?) and @schedule[0].ready?(@next_pass))
138
+ pending_soon << @schedule.shift
124
139
  end
125
- [pending, @schedule[0]]
140
+ return [pending_now, pending_soon]
141
+ end
142
+
143
+ def schedule_next_pass
144
+ @next_pass = Time.now+@grain
126
145
  end
127
146
 
128
147
  # Put all functions dealing with @schedule under @schedule_lock
129
148
  threadlock :list,
130
- :clear,
149
+ :schedule_clear,
131
150
  :schedule_reshuffle,
132
151
  :schedule_add,
133
152
  :schedule_concat,
134
153
  :schedule_pull,
154
+ :schedule_next_pass,
135
155
  lock: :@schedule_lock
136
156
 
137
157
  def main_loop
138
158
 
139
- @keepgoing = true
159
+ # @keepgoing = true
140
160
  pending = Array.new
141
161
  on_deck = nil
142
162
 
143
163
  while @keepgoing
144
164
 
165
+ schedule_next_pass
166
+
145
167
  # Pull, fire, and requeue relevant events
146
- pending, on_deck = schedule_pull
147
- pending.each { |x| x.fire }
148
- schedule_concat pending
168
+ pending_now, pending_soon = schedule_pull
169
+ pending_now.each { |x| x.fire }
170
+ pending_soon.each{ |x| Thread.new{ x.fire_when_ready(blocking:true) }}
171
+ # schedule_concat pending_now
149
172
 
150
- @sleepzone = true
151
- # Calculate the time to sleep based on next event's time
152
- if on_deck
153
- sleep on_deck.time_until
154
- else # sleep until wakeup if no event is on deck
155
- sleep
156
- end
157
- @sleepzone = false
173
+ sleep [@next_pass-Time.now, 0].max
158
174
  end
159
175
 
160
176
  nil end
161
177
 
162
- def wakeup
163
- sleep 0 until @sleepzone==true
164
- sleep 0 until @thread.status=='sleep'
165
- @thread.wakeup
166
- nil end
167
-
168
178
  end
169
179
 
170
- # Use fired event to only start scheduler when Hub is running
171
- # This also gets the scheduler loop its own thread within the Hub's threads
172
- # on :time_scheduler_start, self do; main_loop; end;
173
- # Channel.new(self).fire(:time_scheduler_start)
174
-
175
- # Refire the start event after Hub dies in case it restarts
180
+ # Start the main loop upon run of Hub
176
181
  Hub.after_run(retain:true) do
182
+ @keepgoing = true
177
183
  @thread = Thread.new { main_loop }
178
184
  end
179
185
 
180
186
  # Stop the main loop upon death of Hub
181
- Hub.before_kill(retain:true) do
182
- sleep 0 until @sleepzone==true
183
- sleep 0 until @thread.status=='sleep'
184
- @keepgoing=false
185
- wakeup
187
+ Hub.before_kill(retain:true) do
188
+ Thread.exclusive do
189
+ @keepgoing=false
190
+ @next_pass=Time.now
191
+ @thread.wakeup
192
+ end
186
193
  @thread.join
194
+ schedule_clear
187
195
  end
188
196
 
189
197
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wires
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe McIlvain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-11 00:00:00.000000000 Z
11
+ date: 2013-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport