wires 0.2.8 → 0.2.9

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