From d8ac22a13f092731bf29a0399f31f3074764c95d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 20 Dec 2019 01:39:16 +0000 Subject: watchable: use fiddle for inotify support We have String#unpack at our disposal for working with "struct inotify_event", so use it instead of depending on an extension which requires a compiler and development headers to install. --- lib/dtas/watchable/fiddle_ino.rb | 78 ++++++++++++++++++++++++++++++++++++++++ lib/dtas/watchable/inotify.rb | 13 +++++++ 2 files changed, 91 insertions(+) create mode 100644 lib/dtas/watchable/fiddle_ino.rb create mode 100644 lib/dtas/watchable/inotify.rb (limited to 'lib/dtas/watchable') diff --git a/lib/dtas/watchable/fiddle_ino.rb b/lib/dtas/watchable/fiddle_ino.rb new file mode 100644 index 0000000..3b9d668 --- /dev/null +++ b/lib/dtas/watchable/fiddle_ino.rb @@ -0,0 +1,78 @@ +# Copyright (C) 2013-2019 all contributors +# License: GPL-3.0+ +# frozen_string_literal: true +require 'fiddle' + +# used to restart DTAS::Source::SplitFX processing in dtas-player +# if the YAML file is edited +class DTAS::Watchable::InotifyReadableIter # :nodoc: + include DTAS::Watchable::InotifyCommon + + Inotify_init = Fiddle::Function.new(DTAS.libc['inotify_init1'], + [ Fiddle::TYPE_INT ], + Fiddle::TYPE_INT) + + Inotify_add_watch = Fiddle::Function.new(DTAS.libc['inotify_add_watch'], + [ Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT ], + Fiddle::TYPE_INT) + + # IO.select compatibility + attr_reader :to_io #:nodoc: + + def initialize # :nodoc: + fd = Inotify_init.call(02000000 | 04000) # CLOEXEC | NONBLOCK + raise "inotify_init failed: #{Fiddle.last_error}" if fd < 0 + @to_io = DTAS::Nonblock.for_fd(fd) + @buf = ''.b + @q = [] + end + + # struct inotify_event { + # int wd; /* Watch descriptor */ + # uint32_t mask; /* Mask describing event */ + # uint32_t cookie; /* Unique cookie associating related + # events (for rename(2)) */ + # uint32_t len; /* Size of name field */ + # char name[]; /* Optional null-terminated name */ + InotifyEvent = Struct.new(:wd, :mask, :cookie, :len, :name) # :nodoc: + + def take(nonblock) # :nodoc: + event = @q.pop and return event + case rv = @to_io.read_nonblock(16384, @buf, exception: false) + when :wait_readable, nil + return + else + until rv.empty? + hdr = rv.slice!(0,16) + name = nil + wd, mask, cookie, len = res = hdr.unpack('iIII') + wd && mask && cookie && len or + raise "bogus inotify_event #{res.inspect} hdr=#{hdr.inspect}" + if len > 0 + name = rv.slice!(0, len) + name.size == len or raise "short name #{name.inspect} != #{len}" + name.sub!(/\0+\z/, '') or + raise "missing: `\\0', inotify_event.name=#{name.inspect}" + name = DTAS.dedupe_str(name) + end + ie = InotifyEvent.new(wd, mask, cookie, len, name) + if event + @q << ie + else + event = ie + end + end # /until rv.empty? + return event + end while true + end + + def add_watch(watchdir, flags) + wd = Inotify_add_watch.call(@to_io.fileno, watchdir, flags) + raise "inotify_add_watch failed: #{Fiddle.last_error}" if wd < 0 + wd + end + + def close + @to_io = @to_io.close if @to_io + end +end diff --git a/lib/dtas/watchable/inotify.rb b/lib/dtas/watchable/inotify.rb new file mode 100644 index 0000000..eface0e --- /dev/null +++ b/lib/dtas/watchable/inotify.rb @@ -0,0 +1,13 @@ +# Copyright (C) 2013-2019 all contributors +# License: GPL-3.0+ +# frozen_string_literal: true +require 'sleepy_penguin' + +# used to restart DTAS::Source::SplitFX processing in dtas-player +# if the YAML file is edited +class DTAS::Watchable::InotifyReadableIter < SleepyPenguin::Inotify # :nodoc: + include DTAS::Watchable::InotifyCommon + def self.new + super(:CLOEXEC) + end +end -- cgit v1.2.3-24-ge0c7