fsevent 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 190a71cc39238eaa13406a607bd3156a708b9327
4
- data.tar.gz: 312958f08630a7f81721fa2738b3a5375537bdac
3
+ metadata.gz: a29fe94eaba408b87373eb438cb5586bc0d97906
4
+ data.tar.gz: 837f02c21999e8b41e86e22066d0f198111cbb0c
5
5
  SHA512:
6
- metadata.gz: ee4a193a6b9bae8d14f19be365ff123578495774bb2dcff9a27afac8b83e8a87ad55dd63aaab6f7ac76f7749a28fe704d2d34574f59c6baf5f8491a58c9917b9
7
- data.tar.gz: ee1aa94816594f090d13ea360e8ca2095be7829d1655f6030b9a54b68e4d1c4874007f5908f7200dfac2ef3877b71c705d203d645b00d7e5c0d305b6a9b4c1a0
6
+ metadata.gz: 2e163903a427283fa54b05c675a5aa806f872c750e8da21f3e084061efdc3457e552cc5eeda138cef43f2671c04a703cec9b6143e13106c4ccfdc6d9cbfd7981
7
+ data.tar.gz: 902f766db3e5148e76c60bfd25f245bbd738b423a6d15a89545ff98c19a650ee05fdb1479ca6f59ed966a9276682e1189e13c25dfbd3b0f4377852d6525e5300
data/README.md CHANGED
@@ -2,10 +2,21 @@
2
2
 
3
3
  fail safe event driven framework
4
4
 
5
+ # install
6
+
7
+ ```
8
+ gem install fsevent
9
+ ```
10
+
5
11
  # author
6
12
 
7
13
  Tanaka Akira
8
14
 
15
+ # links
16
+
17
+ - https://github.com/fsevent/fsevent
18
+ - http://rubygems.org/gems/fsevent
19
+
9
20
  # license
10
21
  GPLv3 or later
11
22
 
@@ -1,11 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'fsevent'
3
- s.version = '0.1'
4
- s.date = '2013-06-23'
3
+ s.version = '0.2'
4
+ s.date = '2013-06-30'
5
5
  s.author = 'Tanaka Akira'
6
6
  s.email = 'tanaka-akira@aist.go.jp'
7
7
  s.license = 'GPL-3.0+'
8
8
  s.required_ruby_version = '>= 1.9.2'
9
+ s.add_runtime_dependency 'depq', '~> 0.6'
10
+ s.add_development_dependency 'test-unit', '~> 2.5'
9
11
  s.files = %w[
10
12
  .gitignore
11
13
  LICENSE
@@ -13,6 +15,7 @@ Gem::Specification.new do |s|
13
15
  fsevent.gemspec
14
16
  lib/fsevent.rb
15
17
  lib/fsevent/abstractdevice.rb
18
+ lib/fsevent/debugdumper.rb
16
19
  lib/fsevent/failsafedevice.rb
17
20
  lib/fsevent/framework.rb
18
21
  lib/fsevent/periodicschedule.rb
@@ -21,6 +24,7 @@ Gem::Specification.new do |s|
21
24
  lib/fsevent/schedulemerger.rb
22
25
  lib/fsevent/simpledevice.rb
23
26
  lib/fsevent/util.rb
27
+ lib/fsevent/watchset.rb
24
28
  sample/repeat.rb
25
29
  sample/repeat2.rb
26
30
  ]
@@ -17,13 +17,18 @@
17
17
 
18
18
  require 'rbconfig'
19
19
  require 'depq'
20
+ require 'pp'
20
21
 
21
22
  class FSEvent
23
+ class FSEventError < StandardError
24
+ end
22
25
  end
23
26
 
24
27
  require 'fsevent/util'
28
+ require 'fsevent/watchset'
25
29
  require 'fsevent/framework'
26
30
  require 'fsevent/abstractdevice'
31
+ require 'fsevent/debugdumper'
27
32
  require 'fsevent/simpledevice'
28
33
  require 'fsevent/processdevice'
29
34
  require 'fsevent/processdevicec'
@@ -26,13 +26,19 @@ class FSEvent::AbstractDevice
26
26
  attr_reader :name, :schedule
27
27
  attr_writer :framework
28
28
 
29
+ def inspect
30
+ "\#<#{self.class}: #{@name}>"
31
+ end
32
+
29
33
  # Called from the framework when this device is registered.
30
34
  def registered
31
35
  # child process calls:
32
- # * @framework.add_watch
33
- # * @framework.define_status
34
- # * @framework.status_changed # possible but needless
35
- # * @framework.set_elapsed_time
36
+ # * add_watch
37
+ # * del_watch # possible but needless
38
+ # * define_status
39
+ # * modify_status # possible but needless
40
+ # * undefine_status # possible but needless
41
+ # * set_elapsed_time
36
42
  end
37
43
 
38
44
  # Called from the framework when this device is unregistered.
@@ -40,25 +46,39 @@ class FSEvent::AbstractDevice
40
46
  end
41
47
 
42
48
  # Called from the framework
43
- def run(watched_status_change)
49
+ def run(watched_status, changed_status)
44
50
  raise NotImplementedError
45
51
  # 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
52
+ # * add_watch # possible but should be rare
53
+ # * del_watch
54
+ # * define_status # possible but should be rare
55
+ # * modify_status
56
+ # * undefine_status
57
+ # * set_elapsed_time
58
+ end
59
+
60
+ def add_watch(watchee_device_name_pat, status_name_pat, reaction = :immediate)
61
+ @framework.add_watch(watchee_device_name_pat, status_name_pat, reaction)
50
62
  end
51
63
 
52
- def add_watch(watchee_device_name, status_name, reaction = :immediate)
53
- @framework.add_watch(watchee_device_name, status_name, reaction)
64
+ def del_watch(watchee_device_name_pat, status_name_pat)
65
+ @framework.del_watch(watchee_device_name_pat, status_name_pat)
54
66
  end
55
67
 
56
68
  def define_status(status_name, value)
57
69
  @framework.define_status(status_name, value)
58
70
  end
59
71
 
60
- def status_changed(status_name, value)
61
- @framework.status_changed(status_name, value)
72
+ def modify_status(status_name, value)
73
+ @framework.modify_status(status_name, value)
74
+ end
75
+
76
+ def undefine_status(status_name)
77
+ @framework.undefine_status(status_name)
78
+ end
79
+
80
+ def register_device(device)
81
+ @framework.register_device(device)
62
82
  end
63
83
 
64
84
  def unregister_device(device_name)
@@ -0,0 +1,33 @@
1
+ # debugdumper.rb --- device for debug dump
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::DebugDumper < FSEvent::AbstractDevice
21
+ def initialize(device_name="debugdumper")
22
+ super
23
+ end
24
+
25
+ def registered
26
+ add_watch("*", "*")
27
+ end
28
+
29
+ def run(watched_status, changed_status)
30
+ #pp watched_status
31
+ pp changed_status
32
+ end
33
+ end
@@ -18,9 +18,9 @@
18
18
  class FSEvent::FailSafeDevice < FSEvent::AbstractDevice
19
19
  def initialize(device_name, initial_status, *watchee_device_names)
20
20
  super device_name
21
- raise "One devices required at least" if watchee_device_names.empty?
21
+ raise ArgumentError, "One devices required at least" if watchee_device_names.empty?
22
22
  @current_status = {} # status_name -> value
23
- @current_status_list = {} # status_name -> watchee_device_name status_name -> value
23
+ @current_status_list = {} # status_name -> watchee_device_name -> value
24
24
  @status_merger = {}
25
25
  initial_status.each {|k, v, merger|
26
26
  @current_status[k] = v
@@ -61,10 +61,12 @@ class FSEvent::FailSafeDevice < FSEvent::AbstractDevice
61
61
  }
62
62
  end
63
63
 
64
- def run(watched_status_change)
64
+ def run(watched_status, changed_status)
65
65
  updated = {}
66
- watched_status_change.each {|watchee_device_name, h|
67
- h.each {|status_name, value|
66
+ changed_status.each {|watchee_device_name, h|
67
+ h.each {|status_name, time|
68
+ next if /\A_/ =~ status_name
69
+ value = watched_status[watchee_device_name][status_name]
68
70
  unless updated.has_key? status_name
69
71
  updated[status_name] = @current_status_list[status_name]
70
72
  end
@@ -78,7 +80,7 @@ class FSEvent::FailSafeDevice < FSEvent::AbstractDevice
78
80
  new_val = merger.call(cur_val, *values)
79
81
  if cur_val != new_val
80
82
  @current_status[status_name] = new_val
81
- status_changed status_name, new_val
83
+ modify_status status_name, new_val
82
84
  end
83
85
  }
84
86
  end
@@ -20,279 +20,459 @@ class FSEvent
20
20
 
21
21
  def initialize(initial_time=Time.now)
22
22
  @current_time = initial_time
23
+ @current_count = 0
23
24
 
24
25
  @devices = {} # device_name -> device
26
+ @device_last_run_count = {} # device_name -> count
25
27
 
26
- @status = {} # device_name -> status_name -> value
28
+ # special status:
29
+ # _fsevent : _device_registered_DEVICE_NAME => time
30
+ # _fsevent : _device_unregistered_DEVICE_NAME => time
31
+ # DEVICE_NAME : _status_defined_STATUS_NAME => time
32
+ # DEVICE_NAME : _status_undefined_STATUS_NAME => time
33
+ #
34
+ @status_value = { "_fsevent" => {} } # device_name -> status_name -> value
35
+ @status_time = { "_fsevent" => {} } # device_name -> status_name -> time
36
+ @status_count = { "_fsevent" => {} } # device_name -> status_name -> count
27
37
 
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
38
+ @watchset = FSEvent::WatchSet.new
39
+
40
+ @clock_proc = nil
32
41
 
33
42
  @q = Depq.new
34
43
  @schedule_locator = {} # device_name -> locator
35
44
  end
36
45
  attr_reader :current_time
46
+ attr_accessor :clock_proc
37
47
 
38
- def register_device(device, register_time=@current_time)
48
+ def register_device(device)
39
49
  device_name = device.name
40
- value = [:register, device_name, device]
41
- @schedule_locator[device_name] = @q.insert value, register_time
50
+ if !valid_device_name_for_write?(device_name)
51
+ raise ArgumentError, "invalid device name: #{device_name.inspect}"
52
+ end
53
+ if !Thread.current[:fsevent_buffer]
54
+ value = [:register_start, device_name, device]
55
+ @schedule_locator[device_name] = @q.insert value, @current_time
56
+ else
57
+ value = [:register_device, device_name, device]
58
+ Thread.current[:fsevent_buffer] << value
59
+ end
42
60
  end
43
61
 
44
62
  def start
45
63
  until @q.empty?
46
64
  loc = @q.delete_min_locator
47
65
  event_type, *args = loc.value
66
+ @clock_proc.call(@current_time, loc.priority) if @clock_proc && @current_time != loc.priority
48
67
  @current_time = loc.priority
68
+ @current_count += 1
49
69
  case event_type
50
- when :register; at_register(loc, *args)
51
- when :wakeup; at_wakeup(loc, *args)
52
- when :sleep; at_sleep(loc, *args)
70
+ when :register_start; at_register_start(loc, *args)
71
+ when :register_end; at_register_end(loc, *args)
72
+ when :run_start; at_run_start(loc, *args)
73
+ when :run_end; at_run_end(loc, *args)
53
74
  else
54
- raise "unexpected event type: #{event_type}"
75
+ raise FSEvent::FSEventError, "unexpected event type: #{event_type}"
55
76
  end
56
77
  end
57
78
  end
58
79
 
59
80
  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 = []
81
+ Thread.current[:fsevent_buffer] = buffer = []
64
82
  Thread.current[:fsevent_device_elapsed_time] = nil
65
83
  t1 = Time.now
66
84
  yield
67
85
  t2 = Time.now
68
86
  elapsed = Thread.current[:fsevent_device_elapsed_time] || t2 - t1
69
- return device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed
87
+ return buffer, elapsed
70
88
  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
89
+ Thread.current[:fsevent_buffer] = nil
75
90
  Thread.current[:fsevent_device_elapsed_time] = nil
76
91
  end
77
92
  private :wrap_device_action
78
93
 
79
94
  # 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]
95
+ def add_watch(watchee_device_name_pat, status_name_pat, reaction = :immediate)
96
+ if !valid_device_name_pat_for_read?(watchee_device_name_pat)
97
+ raise ArgumentError, "invalid device name pattern: #{watchee_device_name_pat.inspect}"
98
+ end
99
+ if !valid_status_name_pat_for_read?(status_name_pat)
100
+ raise ArgumentError, "invalid status name pattern: #{status_name_pat.inspect}"
101
+ end
102
+ Thread.current[:fsevent_buffer] << [:add_watch, watchee_device_name_pat, status_name_pat, reaction]
82
103
  end
83
104
 
84
105
  # 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]
106
+ def del_watch(watchee_device_name_pat, status_name_pat)
107
+ if !valid_device_name_pat_for_read?(watchee_device_name_pat)
108
+ raise ArgumentError, "invalid device name pattern: #{watchee_device_name_pat.inspect}"
109
+ end
110
+ if !valid_status_name_pat_for_read?(status_name_pat)
111
+ raise ArgumentError, "invalid status name pattern: #{status_name_pat.inspect}"
112
+ end
113
+ Thread.current[:fsevent_buffer] << [:del_watch, watchee_device_name_pat, status_name_pat]
87
114
  end
88
115
 
89
116
  # Called from a device to define the status.
90
117
  def define_status(status_name, value)
91
- Thread.current[:fsevent_device_define_buffer] << [status_name, value]
118
+ if !valid_status_name_for_write?(status_name)
119
+ raise ArgumentError, "invalid status name: #{status_name.inspect}"
120
+ end
121
+ Thread.current[:fsevent_buffer] << [:define_status, status_name, value]
92
122
  end
93
123
 
94
124
  # 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]
125
+ def modify_status(status_name, value)
126
+ if !valid_status_name_for_write?(status_name)
127
+ raise ArgumentError, "invalid status name: #{status_name.inspect}"
128
+ end
129
+ Thread.current[:fsevent_buffer] << [:modify_status, status_name, value]
130
+ end
131
+
132
+ # Called from a device to define the status.
133
+ def undefine_status(status_name)
134
+ if !valid_status_name_for_write?(status_name)
135
+ raise ArgumentError, "invalid status name: #{status_name.inspect}"
136
+ end
137
+ Thread.current[:fsevent_buffer] << [:undefine_status, status_name]
97
138
  end
98
139
 
99
140
  # Called from a device.
100
141
  def unregister_device(device_name)
101
- Thread.current[:fsevent_unregister_device_buffer] << device_name
142
+ if !valid_device_name_for_write?(device_name)
143
+ raise ArgumentError, "invalid device name: #{device_name.inspect}"
144
+ end
145
+ Thread.current[:fsevent_buffer] << [:unregister_device, device_name]
102
146
  end
103
147
 
104
148
  # Called from a device to set the elapsed time.
105
149
  def set_elapsed_time(t)
106
- raise "elapsed time must be positive: #{t}" if t <= 0
150
+ raise ArgumentError, "negative elapsed time given: #{t}" if t < 0
107
151
  Thread.current[:fsevent_device_elapsed_time] = t
108
152
  end
109
153
 
110
- def at_register(loc, device_name, device)
154
+ def at_register_start(loc, device_name, device)
111
155
  if @devices.has_key? device_name
112
- raise "Device already registered: #{device_name}"
156
+ raise ArgumentError, "Device already registered: #{device_name}"
113
157
  end
114
158
 
115
- device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed =
116
- wrap_device_action {
159
+ buffer, elapsed = wrap_device_action {
117
160
  device.framework = self
118
161
  device.registered
119
162
  }
120
163
 
164
+ value = [:register_end, device_name, device, @current_count, buffer]
165
+ loc.update value, @current_time + elapsed
166
+ @q.insert_locator loc
167
+ end
168
+ private :at_register_start
169
+
170
+ def at_register_end(loc, device_name, device, register_start_count, buffer)
171
+ if @devices.has_key? device_name
172
+ raise ArgumentError, "Device already registered: #{device_name}"
173
+ end
174
+
121
175
  @devices[device_name] = device
122
- @status[device_name] = {}
176
+ @device_last_run_count[device_name] = register_start_count
177
+ @status_value[device_name] = {}
178
+ @status_time[device_name] = {}
179
+ @status_count[device_name] = {}
123
180
 
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
181
+ internal_update_status("_fsevent", @current_time, "_device_registered_#{device_name}", @current_time)
182
+
183
+ at_run_end(loc, device_name, register_start_count, buffer)
127
184
  end
128
- private :at_register
185
+ private :at_register_end
129
186
 
130
- def at_wakeup(loc, device_name)
187
+ def at_run_start(loc, device_name)
131
188
  time = loc.priority
132
189
  device = @devices[device_name]
133
190
 
134
- watched_status_change = @watched_status_change.delete(device_name)
135
- watched_status_change = nonempty_hash(watched_status_change, 2)
191
+ watched_status, changed_status = notifications(device_name, @device_last_run_count[device_name])
136
192
 
137
- device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer, elapsed =
138
- wrap_device_action { device.run(watched_status_change) }
193
+ buffer, elapsed = wrap_device_action { device.run(watched_status, changed_status) }
139
194
 
140
- value = [:sleep, device_name, device_watch_buffer, device_define_buffer, device_changed_buffer, unregister_device_buffer]
195
+ value = [:run_end, device_name, @current_count, buffer]
141
196
  loc.update value, time + elapsed
142
197
  @q.insert_locator loc
143
198
  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)
199
+ private :at_run_start
200
+
201
+ def notifications(watcher_device_name, last_run_count)
202
+ watched_status = {}
203
+ changed_status = {}
204
+ @watchset.watcher_each(watcher_device_name) {|watchee_device_name_pat, status_name_pat, reaction|
205
+ matched_device_name_each(watchee_device_name_pat) {|watchee_device_name|
206
+ watched_status[watchee_device_name] ||= {}
207
+ changed_status[watchee_device_name] ||= {}
208
+ matched_status_name_each(watchee_device_name, status_name_pat) {|status_name|
209
+ if @status_value.has_key?(watchee_device_name) &&
210
+ @status_value[watchee_device_name].has_key?(status_name)
211
+ watched_status[watchee_device_name][status_name] = @status_value[watchee_device_name][status_name]
212
+ end
213
+ if @status_time.has_key?(watchee_device_name) &&
214
+ @status_time[watchee_device_name].has_key?(status_name) &&
215
+ last_run_count <= @status_count[watchee_device_name][status_name]
216
+ changed_status[watchee_device_name][status_name] = @status_time[watchee_device_name][status_name]
217
+ end
218
+ }
219
+ }
220
+ }
221
+ return watched_status, changed_status
154
222
  end
155
- private :at_sleep
223
+ private :notifications
224
+
225
+ def at_run_end(loc, device_name, run_start_count, buffer)
226
+ @device_last_run_count[device_name] = run_start_count
227
+ run_end_time = loc.priority
156
228
 
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}"
229
+ wakeup_immediate = false
230
+ unregister_self = false
231
+
232
+ buffer.each {|tag, *rest|
233
+ case tag
234
+ when :define_status
235
+ internal_define_status(device_name, run_end_time, *rest)
236
+ when :modify_status
237
+ internal_modify_status(device_name, run_end_time, *rest)
238
+ when :undefine_status
239
+ internal_undefine_status(device_name, run_end_time, *rest)
240
+ when :add_watch
241
+ wakeup_immediate |= internal_add_watch(device_name, *rest)
242
+ when :del_watch
243
+ internal_del_watch(device_name, *rest)
244
+ when :register_device
245
+ internal_register_device(device_name, *rest)
246
+ when :unregister_device
247
+ unregister_self |= internal_unregister_device(device_name, *rest)
248
+ else
249
+ raise "unexpected tag: #{tag}"
161
250
  end
162
- @status[device_name][status_name] = value
163
251
  }
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
252
+
253
+ unless unregister_self
254
+ wakeup_immediate ||= immediate_wakeup_self?(device_name, run_start_count)
255
+ setup_next_schedule(device_name, loc, run_end_time, wakeup_immediate)
256
+ end
257
+ end
258
+ private :at_run_end
259
+
260
+ def internal_register_device(device_name, target_device_name, device)
261
+ value = [:register_start, target_device_name, device]
262
+ @schedule_locator[target_device_name] = @q.insert value, @current_time
263
+ end
264
+
265
+ def internal_define_status(device_name, run_end_time, status_name, value)
266
+ internal_define_status2(device_name, run_end_time, status_name, value)
267
+ internal_update_status(device_name, run_end_time, "_status_defined_#{status_name}", run_end_time)
268
+ end
269
+ private :internal_define_status
270
+
271
+ def internal_update_status(device_name, run_end_time, status_name, value)
272
+ if has_status?(device_name, status_name)
273
+ internal_modify_status2(device_name, run_end_time, status_name, value)
274
+ else
275
+ internal_define_status2(device_name, run_end_time, status_name, value)
276
+ end
277
+ end
278
+ private :internal_update_status
279
+
280
+ def has_status?(device_name, status_name)
281
+ @status_value.has_key?(device_name) && @status_value[device_name].has_key?(status_name)
282
+ end
283
+ private :has_status?
284
+
285
+ def internal_define_status2(device_name, run_end_time, status_name, value)
286
+ unless @status_value.has_key? device_name
287
+ raise ArgumentError, "device not defined: #{device_name}"
288
+ end
289
+ if @status_value[device_name].has_key? status_name
290
+ raise ArgumentError, "device status already defined: #{device_name} #{status_name}"
291
+ end
292
+ @status_value[device_name][status_name] = value
293
+ @status_time[device_name][status_name] = @current_time
294
+ @status_count[device_name][status_name] = @current_count
295
+ lookup_watchers(device_name, status_name).each {|watcher_device_name, reaction|
296
+ set_wakeup_if_possible(watcher_device_name, run_end_time) if reaction_immediate_at_beginning? reaction
169
297
  }
170
298
  end
171
- private :update_status
299
+ private :internal_define_status2
172
300
 
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}"
301
+ def internal_modify_status(device_name, run_end_time, status_name, value)
302
+ internal_modify_status2(device_name, run_end_time, status_name, value)
303
+ end
304
+ private :internal_modify_status
305
+
306
+ def internal_modify_status2(device_name, run_end_time, status_name, value)
307
+ unless @status_value.has_key? device_name
308
+ raise ArgumentError, "device not defined: #{device_name}"
309
+ end
310
+ unless @status_value[device_name].has_key? status_name
311
+ raise ArgumentError, "device status not defined: #{device_name} #{status_name}"
312
+ end
313
+ @status_value[device_name][status_name] = value
314
+ @status_time[device_name][status_name] = @current_time
315
+ @status_count[device_name][status_name] = @current_count
316
+ lookup_watchers(device_name, status_name).each {|watcher_device_name, reaction|
317
+ set_wakeup_if_possible(watcher_device_name, run_end_time) if reaction_immediate_at_subsequent? reaction
318
+ }
319
+ end
320
+ private :internal_modify_status2
321
+
322
+ def internal_undefine_status(device_name, run_end_time, status_name)
323
+ unless @status_value.has_key? device_name
324
+ raise ArgumentError, "device not defined: #{device_name}"
325
+ end
326
+ unless @status_value[device_name].has_key? status_name
327
+ raise ArgumentError, "device status not defined: #{device_name} #{status_name}"
328
+ end
329
+ @status_value[device_name].delete status_name
330
+ @status_time[device_name][status_name] = @current_time
331
+ @status_count[device_name][status_name] = @current_count
332
+ lookup_watchers(device_name, status_name).each {|watcher_device_name, reaction|
333
+ set_wakeup_if_possible(watcher_device_name, run_end_time) if reaction_immediate_at_subsequent? reaction
334
+ }
335
+ internal_update_status(device_name, run_end_time, "_status_undefined_#{status_name}", run_end_time)
336
+ end
337
+ private :internal_update_status
338
+
339
+ def lookup_watchers(watchee_device_name, status_name)
340
+ @watchset.lookup_watchers(watchee_device_name, status_name)
341
+ end
342
+ private :lookup_watchers
343
+
344
+ def internal_add_watch(watcher_device_name, watchee_device_name_pat, status_name_pat, reaction)
345
+ @watchset.add(watchee_device_name_pat, status_name_pat, watcher_device_name, reaction)
346
+ matched_status_each(watchee_device_name_pat, status_name_pat) {|watchee_device_name, status_name|
347
+ if reaction_immediate_at_beginning? reaction
348
+ return true
189
349
  end
190
350
  }
191
- wakeup_immediate
351
+ false
192
352
  end
193
- private :update_watch
353
+ private :internal_add_watch
194
354
 
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
355
+ def matched_status_each(watchee_device_name_pat, status_name_pat)
356
+ matched_device_name_each(watchee_device_name_pat) {|watchee_device_name|
357
+ matched_status_name_each(watchee_device_name, status_name_pat) {|status_name|
358
+ yield watchee_device_name, status_name
201
359
  }
202
360
  }
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
361
+ end
362
+ private :matched_status_each
363
+
364
+ def matched_device_name_each(device_name_pat)
365
+ if /\*\z/ =~ device_name_pat
366
+ prefix = $`
367
+ @status_time.each {|device_name, _h|
368
+ if device_name.start_with? prefix
369
+ yield device_name
370
+ end
208
371
  }
209
- }
372
+ else
373
+ yield device_name_pat
374
+ end
210
375
  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]
376
+ private :matched_device_name_each
377
+
378
+ def matched_status_name_each(device_name, status_name_pat)
379
+ return unless @status_time.has_key? device_name
380
+ status_hash = @status_time[device_name]
381
+ if /\*\z/ =~ status_name_pat
382
+ prefix = $`
383
+ status_hash.each {|status_name, _value|
384
+ if status_name.start_with? prefix
385
+ yield status_name
386
+ end
219
387
  }
388
+ else
389
+ if status_hash.has_key? status_name_pat
390
+ yield status_name_pat
391
+ end
220
392
  end
221
- result
222
393
  end
223
- private :lookup_watchers
394
+ private :matched_status_name_each
395
+
396
+ def internal_del_watch(watcher_device_name, watchee_device_name_pat, status_name_pat)
397
+ @watchset.del(watchee_device_name_pat, status_name_pat, watcher_device_name)
398
+ end
399
+ private :internal_del_watch
224
400
 
225
401
  def set_wakeup_if_possible(device_name, time)
226
402
  loc = @schedule_locator[device_name]
227
403
  if !loc.in_queue?
228
- loc.update [:wakeup, device_name], time
404
+ loc.update [:run_start, device_name], time
229
405
  @q.insert_locator loc
230
406
  return
231
407
  end
232
408
  case event_type = loc.value.first
233
- when :wakeup # The device is sleeping now.
409
+ when :run_start # The device is sleeping now.
234
410
  if time < loc.priority
235
411
  loc.update_priority time
236
412
  end
237
- when :sleep # The device is working now.
238
- # Nothing to do. at_sleep itself checks arrived events at last.
413
+ when :run_end # The device is working now.
414
+ # Nothing to do. at_run_end itself checks arrived events at last.
239
415
  else
240
- raise "unexpected event type: #{event_type}"
416
+ raise FSEvent::FSEventError, "unexpected event type: #{event_type}"
241
417
  end
242
418
  end
243
419
  private :set_wakeup_if_possible
244
420
 
245
- def setup_next_schedule(device_name, loc, sleep_time, wakeup_immediate)
421
+ def setup_next_schedule(device_name, loc, run_end_time, wakeup_immediate)
246
422
  device = @devices[device_name]
247
- wakeup_time = nil
423
+ run_start_time = nil
248
424
  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
425
+ run_start_time = run_end_time
426
+ elsif run_start_time = device.schedule.shift
427
+ if run_start_time < run_end_time
428
+ run_start_time = run_end_time
253
429
  end
254
- while device.schedule.first && device.schedule.first < sleep_time
430
+ while device.schedule.first && device.schedule.first < run_end_time
255
431
  device.schedule.shift
256
432
  end
257
433
  end
258
- if wakeup_time
259
- value = [:wakeup, device_name]
260
- loc.update value, wakeup_time
434
+ if run_start_time
435
+ value = [:run_start, device_name]
436
+ loc.update value, run_start_time
261
437
  @q.insert_locator loc
262
438
  end
263
439
  end
264
440
  private :setup_next_schedule
265
441
 
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)
442
+ def immediate_wakeup_self?(watcher_device_name, run_start_count)
443
+ @watchset.watcher_each(watcher_device_name) {|watchee_device_name_pat, status_name_pat, reaction|
444
+ if reaction_immediate_at_subsequent?(reaction)
445
+ matched_status_each(watchee_device_name_pat, status_name_pat) {|watchee_device_name, status_name|
446
+ if @status_count.has_key?(watchee_device_name) &&
447
+ @status_count[watchee_device_name].has_key?(status_name) &&
448
+ run_start_count <= @status_count[watchee_device_name][status_name]
449
+ return true
450
+ end
273
451
  }
274
- }
452
+ end
275
453
  }
276
454
  false
277
455
  end
278
- private :immediate_wakeup?
456
+ private :immediate_wakeup_self?
279
457
 
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
- }
458
+ def internal_unregister_device(self_device_name, target_device_name)
459
+ if @status_value.has_key? target_device_name
460
+ @status_value[target_device_name].keys.each {|status_name|
461
+ next if /\A_/ =~ status_name
462
+ internal_undefine_status(target_device_name, @current_time, status_name)
288
463
  }
289
- @watched_status_change.delete device_name
290
- @status.delete device_name
291
- loc = @schedule_locator.fetch(device_name)
292
- device.unregistered
464
+ end
465
+ device = @devices.delete target_device_name
466
+ @status_value.delete target_device_name
467
+ @watchset.delete_watcher(target_device_name)
468
+ loc = @schedule_locator.delete target_device_name
469
+ if loc.in_queue?
293
470
  @q.delete_locator loc
294
- }
471
+ end
472
+ device.unregistered
473
+ internal_update_status("_fsevent", @current_time, "_device_unregistered_#{target_device_name}", @current_time)
474
+ self_device_name == target_device_name
295
475
  end
296
- private :unregister_device_internal
476
+ private :internal_unregister_device
297
477
 
298
478
  end