From: Eric Wong <e@80x24.org>
To: dtas-all@nongnu.org
Subject: [PATCH 4/5] watchable: use fiddle for inotify support
Date: Sun, 1 Dec 2019 01:26:52 +0000 [thread overview]
Message-ID: <20191201012653.21967-5-e@80x24.org> (raw)
In-Reply-To: <20191201012653.21967-1-e@80x24.org>
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.rb | 85 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 77 insertions(+), 8 deletions(-)
diff --git a/lib/dtas/watchable.rb b/lib/dtas/watchable.rb
index d0f37af..4047a42 100644
--- a/lib/dtas/watchable.rb
+++ b/lib/dtas/watchable.rb
@@ -1,22 +1,80 @@
# Copyright (C) 2013-2019 all contributors <dtas-all@nongnu.org>
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
# frozen_string_literal: true
+require_relative '../dtas'
+require_relative 'nonblock'
+
begin
-require 'sleepy_penguin'
+require 'fiddle'
# used to restart DTAS::Source::SplitFX processing in dtas-player
# if the YAML file is edited
module DTAS::Watchable # :nodoc:
- class InotifyReadableIter < SleepyPenguin::Inotify # :nodoc:
- def self.new
- super(:CLOEXEC)
+ class InotifyReadableIter # :nodoc:
+
+ 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
- FLAGS = CLOSE_WRITE | MOVED_TO
+ # 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 # :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
+
+ FLAGS = 8 | 128 # CLOSE_WRITE | MOVED_TO
def readable_iter
or_call = false
- while event = take(true) # drain the buffer
+ while event = take # drain the buffer
w = @watches[event.wd] or next
if (event.mask & FLAGS) != 0 && w[event.name]
or_call = true
@@ -30,6 +88,16 @@ def readable_iter
end
end
+ def add_watch(watchdir)
+ 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
+
# we must watch the directory, since
def watch_files(paths, blk)
@watches = {} # wd -> { basename -> true }
@@ -38,7 +106,7 @@ def watch_files(paths, blk)
Array(paths).each do |path|
watchdir, watchbase = File.split(File.expand_path(path))
begin
- wd = @dir2wd[watchdir] ||= add_watch(watchdir, FLAGS)
+ wd = @dir2wd[watchdir] ||= add_watch(watchdir)
m = @watches[wd] ||= {}
m[watchbase] = true
rescue SystemCallError => e
@@ -67,5 +135,6 @@ def watch_end(srv)
end
end
-rescue LoadError
+rescue LoadError, Fiddle::DLError => e
+ warn "#{e.message} (#{e.class})"
end
next prev parent reply other threads:[~2019-12-01 1:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-01 1:26 [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
2019-12-01 1:26 ` [PATCH 1/5] pipe: avoid loading sleepy_penguin Eric Wong
2019-12-01 1:26 ` [PATCH 2/5] use fiddle-based eventfd implementation Eric Wong
2019-12-01 1:26 ` [PATCH 3/5] buffer: replace sleepy_penguin with fiddle Eric Wong
2019-12-01 1:26 ` Eric Wong [this message]
2019-12-01 1:26 ` [PATCH 5/5] doc: remove "sleepy_penguin" references Eric Wong
2019-12-13 18:16 ` [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
2019-12-15 20:39 ` fiddle vs sleepy_penguin vs Perl syscall() bench scripts Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://80x24.org/dtas/README
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191201012653.21967-5-e@80x24.org \
--to=e@80x24.org \
--cc=dtas-all@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/dtas.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).