/usr/lib/ruby/vendor_ruby/ramaze/reloader/watch_inotify.rb is in ruby-ramaze 2012.12.08-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | module Ramaze
class Reloader
##
# TODO:
# * There seems to be a problem somewhere that I couldn't identify yet, a
# file has to be modified twice initially to make it show up as
# modified here, subsequent changes work just fine.
# The only workaround I could find right now would be to read/write
# every single file, but that would be unexpected, irresponsible, and
# error-prone.
#
# NOTE:
# * I have changed from using a Mutex to using a Queue, which uses a
# Mutex internally.
class WatchInotify
POLL_INTERVAL = 2 # seconds
NOTIFY_MASK = RInotify::MODIFY | RInotify::IN_ONESHOT
def initialize
@watcher = RInotify.new
@changed = Queue.new
@watcher_thread = start_watcher
end
def call(cooldown)
yield
end
# TODO: define a finalizer to cleanup? -- reloader never calls #close
def start_watcher
Thread.new{ loop{ watcher_cycle }}
end
# Not much work here, we just have to empty the event queue and push the
# descriptors for reloading on next request.
def watcher_cycle
return unless @watcher.wait_for_events(POLL_INTERVAL)
@watcher.each_event do |event|
@changed.push(event.watch_descriptor)
end
end
def watch(file)
return if @watcher.watch_descriptors.has_value?(file)
return unless File.exist?(file)
@watcher.add_watch(file, NOTIFY_MASK)
rescue Errno::ENOENT
retry
end
# FIXME:
# Seems like this won't work due to some bug in the rinotify library.
# Would be cool if someone could make a FFI version.
def remove_watch(file)
@watcher.rm_watch(file)
end
def close
@watcher_thread.terminate
@watcher.close
true
end
# NOTE:
# We have to add the changed file again after we got a notification, I
# have no idea why, but using IN_ONESHOT should make sure that there is
# no memory leak in the C level even if we add a file again.
# There is a memory leak however in the watch_descriptors hash, since
# rinotify won't synchronize the contents properly and will only add to
# the hash, so we have to clean up ourselves.
def changed_files
until @changed.empty?
descriptor = @changed.shift
file = @watcher.watch_descriptors.delete(descriptor)
watch(file)
yield(file)
end
end
end # WatchInotify
end # Reloader
end # Ramaze
|