From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS22989 209.51.188.0/24 X-Spam-Status: No, score=-3.6 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id B35161F463 for ; Sun, 1 Dec 2019 01:27:14 +0000 (UTC) Received: from localhost ([::1]:39824 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ibE13-0004Qj-Vc for e@80x24.org; Sat, 30 Nov 2019 20:27:13 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:59334) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ibE10-0004Ou-Lg for dtas-all@nongnu.org; Sat, 30 Nov 2019 20:27:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ibE0z-0006Ua-BC for dtas-all@nongnu.org; Sat, 30 Nov 2019 20:27:10 -0500 Received: from dcvr.yhbt.net ([64.71.152.64]:48418) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ibE0z-0006UT-3j for dtas-all@nongnu.org; Sat, 30 Nov 2019 20:27:09 -0500 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 2C1921F46D for ; Sun, 1 Dec 2019 01:26:54 +0000 (UTC) From: Eric Wong To: dtas-all@nongnu.org Subject: [PATCH 4/5] watchable: use fiddle for inotify support Date: Sun, 1 Dec 2019 01:26:52 +0000 Message-Id: <20191201012653.21967-5-e@80x24.org> In-Reply-To: <20191201012653.21967-1-e@80x24.org> References: <20191201012653.21967-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 64.71.152.64 X-BeenThere: dtas-all@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: duct tape audio suite List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dtas-all-bounces+e=80x24.org@nongnu.org Sender: "dtas-all" 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 # License: GPL-3.0+ # frozen_string_literal: true +require_relative '../dtas' +require_relative 'nonblock' + begin -require 'sleepy_penguin' +require 'fiddle' =20 # 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 =3D Fiddle::Function.new(DTAS.libc['inotify_init1'], + [ Fiddle::TYPE_INT ], + Fiddle::TYPE_INT) + + Inotify_add_watch =3D Fiddle::Function.new(DTAS.libc['inotify_add_wa= tch'], + [ Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT ], + Fiddle::TYPE_INT) + + # IO.select compatibility + attr_reader :to_io #:nodoc: + + def initialize # :nodoc: + fd =3D Inotify_init.call(02000000 | 04000) # CLOEXEC | NONBLOCK + raise "inotify_init failed: #{Fiddle.last_error}" if fd < 0 + @to_io =3D DTAS::Nonblock.for_fd(fd) + @buf =3D ''.b + @q =3D [] end =20 - FLAGS =3D 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 =3D Struct.new(:wd, :mask, :cookie, :len, :name) # :nod= oc: + + def take # :nodoc: + event =3D @q.pop and return event + case rv =3D @to_io.read_nonblock(16384, @buf, exception: false) + when :wait_readable, nil + return + else + until rv.empty? + hdr =3D rv.slice!(0,16) + name =3D nil + wd, mask, cookie, len =3D res =3D hdr.unpack('iIII') + wd && mask && cookie && len or + raise "bogus inotify_event #{res.inspect} hdr=3D#{hdr.inspec= t}" + if len > 0 + name =3D rv.slice!(0, len) + name.size =3D=3D len or raise "short name #{name.inspect} !=3D= #{len}" + name.sub!(/\0+\z/, '') or + raise "missing: `\\0', inotify_event.name=3D#{name.inspect= }" + name =3D DTAS.dedupe_str(name) + end + ie =3D InotifyEvent.new(wd, mask, cookie, len, name) + if event + @q << ie + else + event =3D ie + end + end # /until rv.empty? + return event + end while true + end + + FLAGS =3D 8 | 128 # CLOSE_WRITE | MOVED_TO =20 def readable_iter or_call =3D false - while event =3D take(true) # drain the buffer + while event =3D take # drain the buffer w =3D @watches[event.wd] or next if (event.mask & FLAGS) !=3D 0 && w[event.name] or_call =3D true @@ -30,6 +88,16 @@ def readable_iter end end =20 + def add_watch(watchdir) + wd =3D 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 =3D @to_io.close if @to_io + end + # we must watch the directory, since def watch_files(paths, blk) @watches =3D {} # wd -> { basename -> true } @@ -38,7 +106,7 @@ def watch_files(paths, blk) Array(paths).each do |path| watchdir, watchbase =3D File.split(File.expand_path(path)) begin - wd =3D @dir2wd[watchdir] ||=3D add_watch(watchdir, FLAGS) + wd =3D @dir2wd[watchdir] ||=3D add_watch(watchdir) m =3D @watches[wd] ||=3D {} m[watchbase] =3D true rescue SystemCallError =3D> e @@ -67,5 +135,6 @@ def watch_end(srv) end end =20 -rescue LoadError +rescue LoadError, Fiddle::DLError =3D> e + warn "#{e.message} (#{e.class})" end