fsevent 0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/LICENSE +674 -0
- data/README.md +13 -0
- data/fsevent.gemspec +43 -0
- data/lib/fsevent.rb +32 -0
- data/lib/fsevent/abstractdevice.rb +71 -0
- data/lib/fsevent/failsafedevice.rb +85 -0
- data/lib/fsevent/framework.rb +298 -0
- data/lib/fsevent/periodicschedule.rb +34 -0
- data/lib/fsevent/processdevice.rb +93 -0
- data/lib/fsevent/processdevicec.rb +79 -0
- data/lib/fsevent/schedulemerger.rb +48 -0
- data/lib/fsevent/simpledevice.rb +46 -0
- data/lib/fsevent/util.rb +77 -0
- data/sample/repeat.rb +24 -0
- data/sample/repeat2.rb +23 -0
- data/test/test_failsafedevice.rb +159 -0
- data/test/test_framework.rb +167 -0
- data/test/test_processdevice.rb +76 -0
- data/test/test_util.rb +53 -0
- data/test/test_watch.rb +169 -0
- metadata +70 -0
data/README.md
ADDED
data/fsevent.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'fsevent'
|
3
|
+
s.version = '0.1'
|
4
|
+
s.date = '2013-06-23'
|
5
|
+
s.author = 'Tanaka Akira'
|
6
|
+
s.email = 'tanaka-akira@aist.go.jp'
|
7
|
+
s.license = 'GPL-3.0+'
|
8
|
+
s.required_ruby_version = '>= 1.9.2'
|
9
|
+
s.files = %w[
|
10
|
+
.gitignore
|
11
|
+
LICENSE
|
12
|
+
README.md
|
13
|
+
fsevent.gemspec
|
14
|
+
lib/fsevent.rb
|
15
|
+
lib/fsevent/abstractdevice.rb
|
16
|
+
lib/fsevent/failsafedevice.rb
|
17
|
+
lib/fsevent/framework.rb
|
18
|
+
lib/fsevent/periodicschedule.rb
|
19
|
+
lib/fsevent/processdevice.rb
|
20
|
+
lib/fsevent/processdevicec.rb
|
21
|
+
lib/fsevent/schedulemerger.rb
|
22
|
+
lib/fsevent/simpledevice.rb
|
23
|
+
lib/fsevent/util.rb
|
24
|
+
sample/repeat.rb
|
25
|
+
sample/repeat2.rb
|
26
|
+
]
|
27
|
+
s.test_files = %w[
|
28
|
+
test/test_failsafedevice.rb
|
29
|
+
test/test_framework.rb
|
30
|
+
test/test_processdevice.rb
|
31
|
+
test/test_util.rb
|
32
|
+
test/test_watch.rb
|
33
|
+
]
|
34
|
+
s.has_rdoc = true
|
35
|
+
s.homepage = 'https://github.com/fsevent/fsevent'
|
36
|
+
s.require_path = 'lib'
|
37
|
+
s.summary = 'fail safe event driven framework'
|
38
|
+
s.description = <<'End'
|
39
|
+
fail safe event driven framework
|
40
|
+
End
|
41
|
+
end
|
42
|
+
|
43
|
+
|
data/lib/fsevent.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# fsevent.rb --- library file to be required by users
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 National Institute of Advanced Industrial Science and Technology (AIST)
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require 'rbconfig'
|
19
|
+
require 'depq'
|
20
|
+
|
21
|
+
class FSEvent
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'fsevent/util'
|
25
|
+
require 'fsevent/framework'
|
26
|
+
require 'fsevent/abstractdevice'
|
27
|
+
require 'fsevent/simpledevice'
|
28
|
+
require 'fsevent/processdevice'
|
29
|
+
require 'fsevent/processdevicec'
|
30
|
+
require 'fsevent/failsafedevice.rb'
|
31
|
+
require 'fsevent/schedulemerger'
|
32
|
+
require 'fsevent/periodicschedule'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# abstractdevice.rb --- abstract device definition
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 National Institute of Advanced Industrial Science and Technology (AIST)
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Abstract class for devices
|
19
|
+
#
|
20
|
+
class FSEvent::AbstractDevice
|
21
|
+
def initialize(device_name)
|
22
|
+
@name = device_name
|
23
|
+
@current_status = {}
|
24
|
+
@schedule = FSEvent::ScheduleMerger.new
|
25
|
+
end
|
26
|
+
attr_reader :name, :schedule
|
27
|
+
attr_writer :framework
|
28
|
+
|
29
|
+
# Called from the framework when this device is registered.
|
30
|
+
def registered
|
31
|
+
# child process calls:
|
32
|
+
# * @framework.add_watch
|
33
|
+
# * @framework.define_status
|
34
|
+
# * @framework.status_changed # possible but needless
|
35
|
+
# * @framework.set_elapsed_time
|
36
|
+
end
|
37
|
+
|
38
|
+
# Called from the framework when this device is unregistered.
|
39
|
+
def unregistered
|
40
|
+
end
|
41
|
+
|
42
|
+
# Called from the framework
|
43
|
+
def run(watched_status_change)
|
44
|
+
raise NotImplementedError
|
45
|
+
# child process calls:
|
46
|
+
# * @framework.add_watch # possible but should be rare
|
47
|
+
# * @framework.define_status # possible but should be rare
|
48
|
+
# * @framework.status_changed
|
49
|
+
# * @framework.set_elapsed_time
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_watch(watchee_device_name, status_name, reaction = :immediate)
|
53
|
+
@framework.add_watch(watchee_device_name, status_name, reaction)
|
54
|
+
end
|
55
|
+
|
56
|
+
def define_status(status_name, value)
|
57
|
+
@framework.define_status(status_name, value)
|
58
|
+
end
|
59
|
+
|
60
|
+
def status_changed(status_name, value)
|
61
|
+
@framework.status_changed(status_name, value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unregister_device(device_name)
|
65
|
+
@framework.unregister_device(device_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_elapsed_time(t)
|
69
|
+
@framework.set_elapsed_time(t)
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# failsafedevice.rb --- fail safe device class
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 National Institute of Advanced Industrial Science and Technology (AIST)
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
class FSEvent::FailSafeDevice < FSEvent::AbstractDevice
|
19
|
+
def initialize(device_name, initial_status, *watchee_device_names)
|
20
|
+
super device_name
|
21
|
+
raise "One devices required at least" if watchee_device_names.empty?
|
22
|
+
@current_status = {} # status_name -> value
|
23
|
+
@current_status_list = {} # status_name -> watchee_device_name status_name -> value
|
24
|
+
@status_merger = {}
|
25
|
+
initial_status.each {|k, v, merger|
|
26
|
+
@current_status[k] = v
|
27
|
+
@status_merger[k] = merger_callable(merger)
|
28
|
+
@current_status_list[k] = {}
|
29
|
+
watchee_device_names.each {|watchee_device_name|
|
30
|
+
@current_status_list[k][watchee_device_name] = v
|
31
|
+
}
|
32
|
+
}
|
33
|
+
@watchee_device_names = watchee_device_names
|
34
|
+
end
|
35
|
+
|
36
|
+
def merger_callable(merger)
|
37
|
+
case merger
|
38
|
+
when :max
|
39
|
+
method(:merger_max)
|
40
|
+
when :min
|
41
|
+
method(:merger_min)
|
42
|
+
when :lazy
|
43
|
+
method(:merger_lazy)
|
44
|
+
else
|
45
|
+
merger
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def merger_max(cur, *values) values.max end
|
50
|
+
def merger_min(cur, *values) values.min end
|
51
|
+
def merger_lazy(cur, *values) values.uniq.length == 1 ? values[0] : cur end
|
52
|
+
|
53
|
+
def registered
|
54
|
+
@watchee_device_names.each {|n|
|
55
|
+
@current_status.each {|k, v|
|
56
|
+
add_watch n, k
|
57
|
+
}
|
58
|
+
}
|
59
|
+
@current_status.each {|k, v|
|
60
|
+
define_status k, v
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def run(watched_status_change)
|
65
|
+
updated = {}
|
66
|
+
watched_status_change.each {|watchee_device_name, h|
|
67
|
+
h.each {|status_name, value|
|
68
|
+
unless updated.has_key? status_name
|
69
|
+
updated[status_name] = @current_status_list[status_name]
|
70
|
+
end
|
71
|
+
updated[status_name][watchee_device_name] = value
|
72
|
+
}
|
73
|
+
}
|
74
|
+
updated.each {|status_name, h|
|
75
|
+
merger = @status_merger[status_name]
|
76
|
+
cur_val = @current_status[status_name]
|
77
|
+
values = @watchee_device_names.map {|d| h[d] }
|
78
|
+
new_val = merger.call(cur_val, *values)
|
79
|
+
if cur_val != new_val
|
80
|
+
@current_status[status_name] = new_val
|
81
|
+
status_changed status_name, new_val
|
82
|
+
end
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
# framework.rb --- fail safe event driven framework
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014 National Institute of Advanced Industrial Science and Technology (AIST)
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
class FSEvent
|
19
|
+
include FSEvent::Util
|
20
|
+
|
21
|
+
def initialize(initial_time=Time.now)
|
22
|
+
@current_time = initial_time
|
23
|
+
|
24
|
+
@devices = {} # device_name -> device
|
25
|
+
|
26
|
+
@status = {} # device_name -> status_name -> value
|
27
|
+
|
28
|
+
# valid values of reaction: :immediate, :immediate_only_at_beginning, :schedule
|
29
|
+
@watches = nested_hash(3) # watchee_device_name -> status_name -> watcher_device_name -> reaction
|
30
|
+
@watch_patterns = [] # [watchee_device_name_pat, status_name_pat, watcher_device_name, reaction]
|
31
|
+
@watched_status_change = nested_hash(3) # watcher_device_name -> watchee_device_name -> status_name -> value
|
32
|
+
|
33
|
+
@q = Depq.new
|
34
|
+
@schedule_locator = {} # device_name -> locator
|
35
|
+
end
|
36
|
+
attr_reader :current_time
|
37
|
+
|
38
|
+
def register_device(device, register_time=@current_time)
|
39
|
+
device_name = device.name
|
40
|
+
value = [:register, device_name, device]
|
41
|
+
@schedule_locator[device_name] = @q.insert value, register_time
|
42
|
+
end
|
43
|
+
|
44
|
+
def start
|
45
|
+
until @q.empty?
|
46
|
+
loc = @q.delete_min_locator
|
47
|
+
event_type, *args = loc.value
|
48
|
+
@current_time = loc.priority
|
49
|
+
case event_type
|
50
|
+
when :register; at_register(loc, *args)
|
51
|
+
when :wakeup; at_wakeup(loc, *args)
|
52
|
+
when :sleep; at_sleep(loc, *args)
|
53
|
+
else
|
54
|
+
raise "unexpected event type: #{event_type}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def wrap_device_action(&block)
|
60
|
+
Thread.current[:fsevent_device_watch_buffer] = device_watch_buffer = []
|
61
|
+
Thread.current[:fsevent_device_define_buffer] = device_define_buffer = []
|
62
|
+
Thread.current[:fsevent_device_changed_buffer] = device_changed_buffer = []
|
63
|
+
Thread.current[:fsevent_unregister_device_buffer] = unregister_device_buffer = []
|
64
|
+
Thread.current[:fsevent_device_elapsed_time] = nil
|
65
|
+
t1 = Time.now
|
66
|
+
yield
|
67
|
+
t2 = Time.now
|
68
|
+
elapsed = Thread.current[:fsevent_device_elapsed_time] || t2 - t1
|
69
|
+
return device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed
|
70
|
+
ensure
|
71
|
+
Thread.current[:fsevent_device_watch_buffer] = nil
|
72
|
+
Thread.current[:fsevent_device_define_buffer] = nil
|
73
|
+
Thread.current[:fsevent_device_changed_buffer] = nil
|
74
|
+
Thread.current[:fsevent_unregister_device_buffer] = nil
|
75
|
+
Thread.current[:fsevent_device_elapsed_time] = nil
|
76
|
+
end
|
77
|
+
private :wrap_device_action
|
78
|
+
|
79
|
+
# Called from a device. (mainly from registered().)
|
80
|
+
def add_watch(watchee_device_name, status_name, reaction = :immediate)
|
81
|
+
Thread.current[:fsevent_device_watch_buffer] << [:add, watchee_device_name, status_name, reaction]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Called from a device. (mainly from registered().)
|
85
|
+
def del_watch(watchee_device_name, status_name)
|
86
|
+
Thread.current[:fsevent_device_watch_buffer] << [:del, watchee_device_name, status_name, nil]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Called from a device to define the status.
|
90
|
+
def define_status(status_name, value)
|
91
|
+
Thread.current[:fsevent_device_define_buffer] << [status_name, value]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Called from a device to notify the status.
|
95
|
+
def status_changed(status_name, value)
|
96
|
+
Thread.current[:fsevent_device_changed_buffer] << [status_name, value]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Called from a device.
|
100
|
+
def unregister_device(device_name)
|
101
|
+
Thread.current[:fsevent_unregister_device_buffer] << device_name
|
102
|
+
end
|
103
|
+
|
104
|
+
# Called from a device to set the elapsed time.
|
105
|
+
def set_elapsed_time(t)
|
106
|
+
raise "elapsed time must be positive: #{t}" if t <= 0
|
107
|
+
Thread.current[:fsevent_device_elapsed_time] = t
|
108
|
+
end
|
109
|
+
|
110
|
+
def at_register(loc, device_name, device)
|
111
|
+
if @devices.has_key? device_name
|
112
|
+
raise "Device already registered: #{device_name}"
|
113
|
+
end
|
114
|
+
|
115
|
+
device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed =
|
116
|
+
wrap_device_action {
|
117
|
+
device.framework = self
|
118
|
+
device.registered
|
119
|
+
}
|
120
|
+
|
121
|
+
@devices[device_name] = device
|
122
|
+
@status[device_name] = {}
|
123
|
+
|
124
|
+
value = [:sleep, device_name, device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer]
|
125
|
+
loc.update value, current_time + elapsed
|
126
|
+
@q.insert_locator loc
|
127
|
+
end
|
128
|
+
private :at_register
|
129
|
+
|
130
|
+
def at_wakeup(loc, device_name)
|
131
|
+
time = loc.priority
|
132
|
+
device = @devices[device_name]
|
133
|
+
|
134
|
+
watched_status_change = @watched_status_change.delete(device_name)
|
135
|
+
watched_status_change = nonempty_hash(watched_status_change, 2)
|
136
|
+
|
137
|
+
device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed =
|
138
|
+
wrap_device_action { device.run(watched_status_change) }
|
139
|
+
|
140
|
+
value = [:sleep, device_name, device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer]
|
141
|
+
loc.update value, time + elapsed
|
142
|
+
@q.insert_locator loc
|
143
|
+
end
|
144
|
+
private :at_wakeup
|
145
|
+
|
146
|
+
def at_sleep(loc, device_name, device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer)
|
147
|
+
sleep_time = loc.priority
|
148
|
+
update_status(device_name, device_define_buffer, device_changed_buffer)
|
149
|
+
wakeup_immediate = update_watch(device_name, device_watch_buffer)
|
150
|
+
notify_status_change(device_name, sleep_time, device_define_buffer, device_changed_buffer)
|
151
|
+
wakeup_immediate ||= immediate_wakeup?(device_name)
|
152
|
+
setup_next_schedule(device_name, loc, sleep_time, wakeup_immediate)
|
153
|
+
unregister_device_internal(unregister_device_buffer)
|
154
|
+
end
|
155
|
+
private :at_sleep
|
156
|
+
|
157
|
+
def update_status(device_name, device_define_buffer, device_changed_buffer)
|
158
|
+
device_define_buffer.each {|status_name, value|
|
159
|
+
if @status[device_name].has_key? status_name
|
160
|
+
raise "device status already defined: #{device_name} #{status_name}"
|
161
|
+
end
|
162
|
+
@status[device_name][status_name] = value
|
163
|
+
}
|
164
|
+
device_changed_buffer.each {|status_name, value|
|
165
|
+
unless @status[device_name].has_key? status_name
|
166
|
+
raise "device status not defined: #{device_name} #{status_name}"
|
167
|
+
end
|
168
|
+
@status[device_name][status_name] = value
|
169
|
+
}
|
170
|
+
end
|
171
|
+
private :update_status
|
172
|
+
|
173
|
+
def update_watch(device_name, device_watch_buffer)
|
174
|
+
wakeup_immediate = false
|
175
|
+
device_watch_buffer.each {|add_or_del, watchee_device_name, status_name, reaction|
|
176
|
+
case add_or_del
|
177
|
+
when :add
|
178
|
+
@watches[watchee_device_name][status_name][device_name] = reaction
|
179
|
+
if @status.has_key?(watchee_device_name) &&
|
180
|
+
@status[watchee_device_name].has_key?(status_name)
|
181
|
+
@watched_status_change[device_name][watchee_device_name][status_name] = @status[watchee_device_name][status_name]
|
182
|
+
wakeup_immediate ||= reaction_immediate_at_beginning? reaction
|
183
|
+
end
|
184
|
+
when :del
|
185
|
+
@watches[watchee_device_name][status_name].delete device_name
|
186
|
+
@watched_status_change[device_name][watchee_device_name].delete status_name
|
187
|
+
else
|
188
|
+
raise "unexpected add_or_del: #{add_or_del.inspect}"
|
189
|
+
end
|
190
|
+
}
|
191
|
+
wakeup_immediate
|
192
|
+
end
|
193
|
+
private :update_watch
|
194
|
+
|
195
|
+
def notify_status_change(device_name, sleep_time, device_define_buffer, device_changed_buffer)
|
196
|
+
device_define_buffer.each {|status_name, _|
|
197
|
+
value = @status[device_name][status_name]
|
198
|
+
lookup_watchers(device_name, status_name).each {|watcher_device_name, reaction|
|
199
|
+
@watched_status_change[watcher_device_name][device_name][status_name] = value
|
200
|
+
set_wakeup_if_possible(watcher_device_name, sleep_time) if reaction_immediate_at_beginning? reaction
|
201
|
+
}
|
202
|
+
}
|
203
|
+
device_changed_buffer.each {|status_name, _|
|
204
|
+
value = @status[device_name][status_name]
|
205
|
+
lookup_watchers(device_name, status_name).each {|watcher_device_name, reaction|
|
206
|
+
@watched_status_change[watcher_device_name][device_name][status_name] = value
|
207
|
+
set_wakeup_if_possible(watcher_device_name, sleep_time) if reaction_immediate_at_subsequent? reaction
|
208
|
+
}
|
209
|
+
}
|
210
|
+
end
|
211
|
+
private :notify_status_change
|
212
|
+
|
213
|
+
def lookup_watchers(watchee_device_name, status_name)
|
214
|
+
result = []
|
215
|
+
if @watches.has_key?(watchee_device_name) &&
|
216
|
+
@watches[watchee_device_name].has_key?(status_name)
|
217
|
+
@watches[watchee_device_name][status_name].each {|watcher_device_name, reaction|
|
218
|
+
result << [watcher_device_name, reaction]
|
219
|
+
}
|
220
|
+
end
|
221
|
+
result
|
222
|
+
end
|
223
|
+
private :lookup_watchers
|
224
|
+
|
225
|
+
def set_wakeup_if_possible(device_name, time)
|
226
|
+
loc = @schedule_locator[device_name]
|
227
|
+
if !loc.in_queue?
|
228
|
+
loc.update [:wakeup, device_name], time
|
229
|
+
@q.insert_locator loc
|
230
|
+
return
|
231
|
+
end
|
232
|
+
case event_type = loc.value.first
|
233
|
+
when :wakeup # The device is sleeping now.
|
234
|
+
if time < loc.priority
|
235
|
+
loc.update_priority time
|
236
|
+
end
|
237
|
+
when :sleep # The device is working now.
|
238
|
+
# Nothing to do. at_sleep itself checks arrived events at last.
|
239
|
+
else
|
240
|
+
raise "unexpected event type: #{event_type}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
private :set_wakeup_if_possible
|
244
|
+
|
245
|
+
def setup_next_schedule(device_name, loc, sleep_time, wakeup_immediate)
|
246
|
+
device = @devices[device_name]
|
247
|
+
wakeup_time = nil
|
248
|
+
if wakeup_immediate
|
249
|
+
wakeup_time = sleep_time
|
250
|
+
elsif wakeup_time = device.schedule.shift
|
251
|
+
if wakeup_time < sleep_time
|
252
|
+
wakeup_time = sleep_time
|
253
|
+
end
|
254
|
+
while device.schedule.first && device.schedule.first < sleep_time
|
255
|
+
device.schedule.shift
|
256
|
+
end
|
257
|
+
end
|
258
|
+
if wakeup_time
|
259
|
+
value = [:wakeup, device_name]
|
260
|
+
loc.update value, wakeup_time
|
261
|
+
@q.insert_locator loc
|
262
|
+
end
|
263
|
+
end
|
264
|
+
private :setup_next_schedule
|
265
|
+
|
266
|
+
def immediate_wakeup?(watcher_device_name)
|
267
|
+
return false unless @watched_status_change.has_key?(watcher_device_name)
|
268
|
+
@watched_status_change[watcher_device_name].each {|watchee_device_name, h|
|
269
|
+
h.each {|status_name, value|
|
270
|
+
lookup_watchers(watchee_device_name, status_name).each {|watcher_device_name2, reaction|
|
271
|
+
next if watcher_device_name != watcher_device_name2
|
272
|
+
return true if reaction_immediate_at_subsequent?(reaction)
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
false
|
277
|
+
end
|
278
|
+
private :immediate_wakeup?
|
279
|
+
|
280
|
+
def unregister_device_internal(unregister_device_buffer)
|
281
|
+
unregister_device_buffer.each {|device_name|
|
282
|
+
device = @devices.delete device_name
|
283
|
+
@status.delete device_name
|
284
|
+
@watches.each {|watchee_device_name, h1|
|
285
|
+
h1.each {|status_name, h2|
|
286
|
+
h2.delete device_name
|
287
|
+
}
|
288
|
+
}
|
289
|
+
@watched_status_change.delete device_name
|
290
|
+
@status.delete device_name
|
291
|
+
loc = @schedule_locator.fetch(device_name)
|
292
|
+
device.unregistered
|
293
|
+
@q.delete_locator loc
|
294
|
+
}
|
295
|
+
end
|
296
|
+
private :unregister_device_internal
|
297
|
+
|
298
|
+
end
|