wires 0.2.6 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/wires/channel.rb +1 -1
- data/lib/wires/hub.rb +109 -128
- data/lib/wires/time.rb +6 -3
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 292c032ed0e9f02b7fb4700d477e4db91eb9af8c
|
4
|
+
data.tar.gz: d431d5471f1f1e4c4301dad21736c6be1f927455
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af4f5ad6bf247f95f9b6e7b8d5e8c236c4d858ef33d566beb610a7dcffde1ee0bbf98483ee6032a82c9618e553fbf7065cd2711965f5a85dac770d5ce4b17bfe
|
7
|
+
data.tar.gz: 1936dc17986f409580386ba6c6a2d2bcc6e25bcee0782eada1b3deaca158e11a8c65fd0df272d101e86d2e5009cdc8fb14bb56251719816665ea99466f87fc41
|
data/lib/wires/channel.rb
CHANGED
@@ -82,7 +82,7 @@ module Wires
|
|
82
82
|
for chan in relevant_channels()
|
83
83
|
for target in chan.target_list
|
84
84
|
for string in target[0] & event.class.codestrings
|
85
|
-
self.class.hub
|
85
|
+
self.class.hub.spawn(event, string, *target[1], blocking)
|
86
86
|
end end end
|
87
87
|
|
88
88
|
nil end
|
data/lib/wires/hub.rb
CHANGED
@@ -7,12 +7,22 @@ module Wires
|
|
7
7
|
# Operate on the metaclass as a type of singleton pattern
|
8
8
|
class << self
|
9
9
|
|
10
|
+
# Allow user to get/set limit to number of child threads
|
11
|
+
attr_accessor :max_child_threads
|
12
|
+
|
13
|
+
# Make subclasses call class_init
|
14
|
+
def inherited(subcls); subcls.class_init end
|
15
|
+
|
10
16
|
# Moved to a dedicated method for subclass' sake
|
11
17
|
def class_init
|
12
|
-
@queue = Queue.new
|
13
|
-
|
14
|
-
@child_threads
|
15
|
-
@child_threads_lock
|
18
|
+
# @queue = Queue.new
|
19
|
+
@max_child_threads = nil
|
20
|
+
@child_threads = Array.new
|
21
|
+
@child_threads_lock = Monitor.new
|
22
|
+
@neglected = Array.new
|
23
|
+
@neglected_lock = Monitor.new
|
24
|
+
@spawning_count = 0
|
25
|
+
@spawning_count_lock = Monitor.new
|
16
26
|
|
17
27
|
@before_runs = Queue.new
|
18
28
|
@after_runs = Queue.new
|
@@ -20,7 +30,6 @@ module Wires
|
|
20
30
|
@after_kills = Queue.new
|
21
31
|
|
22
32
|
@please_finish_all = false
|
23
|
-
@please_kill = false
|
24
33
|
|
25
34
|
@at_exit = Proc.new{nil}
|
26
35
|
at_exit do self.at_exit_proc end
|
@@ -31,31 +40,21 @@ module Wires
|
|
31
40
|
|
32
41
|
def at_exit_proc; @at_exit.call; end
|
33
42
|
|
34
|
-
# Make subclasses call class_init
|
35
|
-
def inherited(subcls); subcls.class_init end
|
36
|
-
|
37
43
|
|
38
44
|
def dead?; state==:dead end
|
39
45
|
def alive?; state==:alive end
|
40
46
|
|
41
47
|
##
|
42
|
-
# Start the Hub
|
48
|
+
# Start the Hub to allow task spawning.
|
43
49
|
#
|
44
|
-
# valid flags:
|
45
|
-
# [+:in_place+] Hub event loop will be run in calling thread,
|
46
|
-
# blocking until Hub is killed. If this flag is not
|
47
|
-
# specified, the Hub event loop is run in a new thread,
|
48
|
-
# which the main thread joins in at_exit.
|
49
50
|
def run(*flags)
|
50
|
-
sleep 0 until
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
51
|
+
sleep 0 until @spawning_count <= 0
|
52
|
+
@spawning_count_lock.synchronize do
|
53
|
+
sleep 0 until request_state :alive
|
54
|
+
end
|
55
|
+
spawn_neglected_task_threads
|
56
|
+
join_children
|
57
|
+
nil end
|
59
58
|
|
60
59
|
##
|
61
60
|
# Kill the Hub event loop (optional flags change thread behavior)
|
@@ -64,64 +63,114 @@ module Wires
|
|
64
63
|
# [+:nonblocking+]
|
65
64
|
# Without this flag, calling thread will be blocked
|
66
65
|
# until Hub thread is done
|
67
|
-
# [+:
|
66
|
+
# [+:purge_tasks+]
|
68
67
|
# Without this flag, Hub thread won't be done
|
69
68
|
# until all child threads are done
|
70
69
|
def kill(*flags)
|
71
|
-
|
72
|
-
@
|
73
|
-
|
70
|
+
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
|
74
75
|
nil end
|
75
76
|
|
76
77
|
# Register hook to execute before run - can call multiple times
|
77
|
-
def before_run(
|
78
|
-
|
79
|
-
expect_type func, Proc
|
80
|
-
@before_runs << [func, retain]
|
78
|
+
def before_run(retain=false, &block)
|
79
|
+
@before_runs << [block, retain]
|
81
80
|
nil end
|
82
81
|
|
83
82
|
# Register hook to execute after run - can call multiple times
|
84
|
-
def after_run(
|
85
|
-
|
86
|
-
expect_type func, Proc
|
87
|
-
@after_runs << [func, retain]
|
83
|
+
def after_run(retain=false, &block)
|
84
|
+
@after_runs << [block, retain]
|
88
85
|
nil end
|
89
86
|
|
90
87
|
# Register hook to execute before kill - can call multiple times
|
91
|
-
def before_kill(
|
92
|
-
|
93
|
-
expect_type func, Proc
|
94
|
-
@before_kills << [func, retain]
|
88
|
+
def before_kill(retain=false, &block)
|
89
|
+
@before_kills << [block, retain]
|
95
90
|
nil end
|
96
91
|
|
97
92
|
# Register hook to execute after kill - can call multiple times
|
98
|
-
def after_kill(
|
99
|
-
|
100
|
-
expect_type func, Proc
|
101
|
-
@after_kills << [func, retain]
|
93
|
+
def after_kill(retain=false, &block)
|
94
|
+
@after_kills << [block, retain]
|
102
95
|
nil end
|
103
96
|
|
104
|
-
#
|
105
|
-
def
|
106
|
-
|
107
|
-
if Thread.current==@_hegemon_auto_thread \
|
108
|
-
or Thread.current==@thread
|
97
|
+
# Spawn a task
|
98
|
+
def spawn(*args) # :args: event, ch_string, proc, blocking
|
99
|
+
@spawning_count_lock.synchronize { @spawning_count += 1 }
|
109
100
|
|
110
|
-
|
111
|
-
(x[2] and @thread) ?
|
112
|
-
sleep :
|
113
|
-
Thread.pass
|
101
|
+
return neglect(*args) if dead?
|
114
102
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
103
|
+
event, ch_string, proc, blocking = *args
|
104
|
+
|
105
|
+
# If blocking, run the proc in this thread
|
106
|
+
if blocking
|
107
|
+
proc.call(event, ch_string)
|
108
|
+
return :done
|
109
|
+
end
|
110
|
+
|
111
|
+
# If not blocking, clear old threads and spawn a new thread
|
112
|
+
new_thread = nil
|
113
|
+
|
114
|
+
@child_threads_lock.synchronize do
|
115
|
+
|
116
|
+
# Clear out dead threads
|
117
|
+
@child_threads.select!{|t| t.status}
|
118
|
+
|
119
|
+
begin
|
120
|
+
# Raise ThreadError for user-set thread limit to mimic OS limit
|
121
|
+
raise ThreadError if (@max_child_threads) and \
|
122
|
+
(@max_child_threads <= @child_threads.size)
|
123
|
+
# Start the new child thread; follow with chain of neglected tasks
|
124
|
+
new_thread = Thread.new { proc.call(event, ch_string); \
|
125
|
+
spawn_neglected_task_chain }
|
126
|
+
# Capture ThreadError from either OS or user-set limitation
|
127
|
+
rescue ThreadError; return neglect(*args); end
|
128
|
+
|
129
|
+
@child_threads << new_thread
|
130
|
+
return new_thread
|
131
|
+
end
|
132
|
+
|
133
|
+
ensure
|
134
|
+
@spawning_count_lock.synchronize { @spawning_count -= 1 }
|
120
135
|
end
|
121
136
|
|
137
|
+
def purge_neglected
|
138
|
+
@neglected_lock.synchronize do
|
139
|
+
@neglected = Array.new
|
140
|
+
end
|
141
|
+
end
|
122
142
|
|
123
143
|
private
|
124
144
|
|
145
|
+
# Temporarily neglect a task until resources are available to run it
|
146
|
+
def neglect(*args)
|
147
|
+
$stderr.puts "#{self} neglected to spawn #{args.inspect}"
|
148
|
+
@neglected_lock.synchronize do
|
149
|
+
@neglected << args
|
150
|
+
end
|
151
|
+
false end
|
152
|
+
|
153
|
+
# Run a chain of @neglected tasks in place until no more are waiting
|
154
|
+
def spawn_neglected_task_chain
|
155
|
+
neglected_one = nil
|
156
|
+
@neglected_lock.synchronize do
|
157
|
+
return nil if @neglected.empty?
|
158
|
+
neglected_one = @neglected.shift
|
159
|
+
end
|
160
|
+
spawn(*((neglected_one)[0...-1]<<true)) # Call with blocking
|
161
|
+
spawn_neglected_task_chain
|
162
|
+
nil end
|
163
|
+
|
164
|
+
# Flush @neglected task queue, each in a new thread
|
165
|
+
def spawn_neglected_task_threads
|
166
|
+
until (cease||=false)
|
167
|
+
@neglected_lock.synchronize do
|
168
|
+
break if (cease = @neglected.empty?)
|
169
|
+
spawn(*((@neglected.shift)[0...-1]<<false)) # Call without blocking
|
170
|
+
end
|
171
|
+
end
|
172
|
+
nil end
|
173
|
+
|
125
174
|
# Flush/run queue of [proc, retain]s, retaining those with retain==true
|
126
175
|
def run_hooks(hooks)
|
127
176
|
retained = Queue.new
|
@@ -129,7 +178,7 @@ module Wires
|
|
129
178
|
proc, retain = hooks.shift
|
130
179
|
retained << [proc, retain] if retain
|
131
180
|
proc.call
|
132
|
-
flush_queue if alive?
|
181
|
+
# flush_queue if alive?
|
133
182
|
end
|
134
183
|
while not retained.empty?
|
135
184
|
hooks << retained.shift
|
@@ -141,7 +190,7 @@ module Wires
|
|
141
190
|
a_thread = Thread.new{nil}
|
142
191
|
while a_thread
|
143
192
|
@child_threads_lock.synchronize do
|
144
|
-
flush_queue
|
193
|
+
# flush_queue
|
145
194
|
a_thread = @child_threads.shift
|
146
195
|
end
|
147
196
|
a_thread.join if a_thread
|
@@ -149,47 +198,6 @@ module Wires
|
|
149
198
|
end
|
150
199
|
nil end
|
151
200
|
|
152
|
-
# Kill all currently working child threads
|
153
|
-
# Newly fired events could still queue up,
|
154
|
-
# Waiting to be born until this thread is done killing
|
155
|
-
def kill_children
|
156
|
-
@child_threads_lock.synchronize do
|
157
|
-
until @child_threads.empty?
|
158
|
-
@child_threads.shift.exit
|
159
|
-
end
|
160
|
-
end
|
161
|
-
nil end
|
162
|
-
|
163
|
-
# Kill all currently working child threads
|
164
|
-
# Newly fired events could still queue up,
|
165
|
-
# But they will be cleared out and never be born
|
166
|
-
def kill_children_and_clear
|
167
|
-
@child_threads_lock.synchronize do
|
168
|
-
until @child_threads.empty?
|
169
|
-
@child_threads.shift.exit
|
170
|
-
end
|
171
|
-
clear
|
172
|
-
end
|
173
|
-
nil end
|
174
|
-
|
175
|
-
def process_item(x)
|
176
|
-
x, waiting_thread = x
|
177
|
-
string, event, blocking, proc = x
|
178
|
-
|
179
|
-
# Do all dealings with @child_threads under mutex
|
180
|
-
@child_threads_lock.synchronize do
|
181
|
-
|
182
|
-
# Clear dead child threads to free up memory
|
183
|
-
@child_threads.select! {|t| t.status}
|
184
|
-
|
185
|
-
# Start the new child thread
|
186
|
-
@child_threads << Thread.new do
|
187
|
-
proc.call(event)
|
188
|
-
waiting_thread.wakeup if blocking and waiting_thread
|
189
|
-
end
|
190
|
-
end
|
191
|
-
nil end
|
192
|
-
|
193
201
|
end
|
194
202
|
|
195
203
|
|
@@ -216,46 +224,19 @@ module Wires
|
|
216
224
|
impose_state :dead
|
217
225
|
|
218
226
|
declare_state :dead do
|
219
|
-
|
220
227
|
transition_to :alive do
|
221
228
|
before { run_hooks @before_runs }
|
222
229
|
after { run_hooks @after_runs }
|
223
|
-
after { start_hegemon_auto_thread(0.05) }
|
224
230
|
end
|
225
231
|
end
|
226
232
|
|
227
233
|
declare_state :alive do
|
228
|
-
|
229
|
-
task do |i|
|
230
|
-
if i==0
|
231
|
-
@thread_continue = true
|
232
|
-
@thread = Thread.new do
|
233
|
-
while @thread_continue
|
234
|
-
if @queue.empty? then sleep 0.01
|
235
|
-
else process_item(@queue.shift) end
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
end
|
241
|
-
|
242
234
|
transition_to :dead do
|
243
|
-
condition {@please_kill}
|
244
|
-
|
245
235
|
before { run_hooks @before_kills }
|
246
|
-
|
236
|
+
before { purge_neglected }
|
247
237
|
before { join_children if @please_finish_all }
|
248
|
-
|
249
|
-
after { @thread_continue=false
|
250
|
-
@thread.join
|
251
|
-
@thread = nil }
|
252
|
-
|
253
|
-
after { @please_kill = false }
|
254
238
|
after { @please_finish_all = false }
|
255
|
-
|
256
239
|
after { run_hooks @after_kills }
|
257
|
-
|
258
|
-
after { end_hegemon_auto_thread }
|
259
240
|
end
|
260
241
|
end
|
261
242
|
|
data/lib/wires/time.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
|
2
|
+
|
2
3
|
module Wires
|
3
4
|
|
4
|
-
class TimeSchedulerStartEvent < Event; end
|
5
5
|
class TimeSchedulerAnonEvent < Event; end
|
6
6
|
|
7
|
-
|
8
7
|
class TimeSchedulerItem
|
9
8
|
|
10
9
|
attr_reader :time, :event, :channel, :interval
|
@@ -68,7 +67,7 @@ module Wires
|
|
68
67
|
# Block until event is ready, then fire and block until it is done
|
69
68
|
def fire_when_ready(*args);
|
70
69
|
wait_until_ready
|
71
|
-
|
70
|
+
fire(*args)
|
72
71
|
end
|
73
72
|
|
74
73
|
# Lock (almost) all instance methods with common re-entrant lock
|
@@ -233,6 +232,10 @@ class ActiveSupport::Duration
|
|
233
232
|
|
234
233
|
end
|
235
234
|
|
235
|
+
def fire_every(interval, event, channel='*', **kwargs)
|
236
|
+
Wires::TimeScheduler << \
|
237
|
+
Wires::TimeSchedulerItem.new(self, event, channel, **kwargs)
|
238
|
+
end
|
236
239
|
|
237
240
|
# TODO: Repeatable event sugar?
|
238
241
|
# TODO: Tests for all new functionality
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wires
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
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
|
+
date: 2013-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
14
|
+
name: activesupport ~> 4.0
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - '>='
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.0.
|
33
|
+
version: 0.0.8
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.0.
|
40
|
+
version: 0.0.8
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|