* [PATCH 1/5] pipe: avoid loading sleepy_penguin
2019-12-01 1:26 [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
@ 2019-12-01 1:26 ` Eric Wong
2019-12-01 1:26 ` [PATCH 2/5] use fiddle-based eventfd implementation Eric Wong
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-01 1:26 UTC (permalink / raw)
To: dtas-all
The values of F_{GET,SET}PIPE_SZ are architecture-independent
and stable in Linux (unlike Ruby :P), so we won't need to bother
loading an extra .so here for two constants.
---
lib/dtas/pipe.rb | 20 ++++++++++++--------
test/test_sink_pipe_size.rb | 27 ++++++++++++---------------
2 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/lib/dtas/pipe.rb b/lib/dtas/pipe.rb
index 58d926c..4c3203d 100644
--- a/lib/dtas/pipe.rb
+++ b/lib/dtas/pipe.rb
@@ -1,10 +1,6 @@
# 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
-begin
- require 'sleepy_penguin'
-rescue LoadError
-end
require_relative '../dtas'
require_relative 'writable_iter'
require_relative 'nonblock'
@@ -14,6 +10,11 @@ class DTAS::Pipe < DTAS::Nonblock # :nodoc:
include DTAS::WritableIter
attr_accessor :sink
+ if RUBY_PLATFORM =~ /linux/i && File.readable?('/proc/sys/fs/pipe-max-size')
+ F_SETPIPE_SZ = 1031
+ F_GETPIPE_SZ = 1032
+ end
+
def self.new
_, w = rv = pipe
w.writable_iter_init
@@ -21,13 +22,16 @@ def self.new
end
def pipe_size=(nr)
- defined?(SleepyPenguin::F_SETPIPE_SZ) and
- fcntl(SleepyPenguin::F_SETPIPE_SZ, nr)
+ fcntl(F_SETPIPE_SZ, nr) if defined?(F_SETPIPE_SZ)
+ rescue Errno::EINVAL # old kernel
+ rescue Errno::EPERM
+ # resizes fail if Linux is close to the pipe limit for the user
+ # or if the user does not have permissions to resize
end
def pipe_size
- fcntl(SleepyPenguin::F_GETPIPE_SZ)
- end if defined?(SleepyPenguin::F_GETPIPE_SZ)
+ fcntl(F_GETPIPE_SZ)
+ end if defined?(F_GETPIPE_SZ)
# avoid syscall, we never change IO#nonblock= directly
def nonblock?
diff --git a/test/test_sink_pipe_size.rb b/test/test_sink_pipe_size.rb
index 1b6db72..bbe2884 100644
--- a/test/test_sink_pipe_size.rb
+++ b/test/test_sink_pipe_size.rb
@@ -1,20 +1,17 @@
# 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
-begin
- require 'sleepy_penguin'
- require './test/player_integration'
- class TestSinkPipeSizeIntegration < Testcase
- include PlayerIntegration
+require './test/player_integration'
+class TestSinkPipeSizeIntegration < Testcase
+ include PlayerIntegration
- def test_sink_pipe_size_integration
- s = client_socket
- default_sink_pid(s)
- s.req_ok("sink ed default pipe_size=0x1000")
- s.req_ok("sink ed default pipe_size=0x10000")
- s.req_ok("sink ed default pipe_size=")
- s.req_ok("sink ed default pipe_size=4096")
- end if SleepyPenguin.const_defined?(:F_SETPIPE_SZ)
+ def test_sink_pipe_size_integration
+ s = client_socket
+ default_sink_pid(s)
+ s.req_ok("sink ed default pipe_size=0x1000")
+ s.req_ok("sink ed default pipe_size=0x10000")
+ s.req_ok("sink ed default pipe_size=")
+ s.req_ok("sink ed default pipe_size=4096")
end
-rescue LoadError
-end
+end if RUBY_PLATFORM =~ /linux/i &&
+ File.readable?('/proc/sys/fs/pipe-max-size')
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/5] use fiddle-based eventfd implementation
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 ` Eric Wong
2019-12-01 1:26 ` [PATCH 3/5] buffer: replace sleepy_penguin with fiddle Eric Wong
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-01 1:26 UTC (permalink / raw)
To: dtas-all
sleepy_penguin requires a compiler and development headers to
install, so it could be a PITA to install for users on
distro-provided Ruby. Use fiddle since it's part of the Ruby
standard library since 1.9.2 and users won't have to install
anything else.
---
lib/dtas.rb | 8 +++++++
lib/dtas/sigevent.rb | 3 +--
lib/dtas/sigevent/efd.rb | 20 -----------------
lib/dtas/sigevent/fiddle_efd.rb | 38 +++++++++++++++++++++++++++++++++
lib/dtas/sigevent/pipe.rb | 2 +-
test/test_sigevent.rb | 20 +++++++++++++++++
6 files changed, 68 insertions(+), 23 deletions(-)
delete mode 100644 lib/dtas/sigevent/efd.rb
create mode 100644 lib/dtas/sigevent/fiddle_efd.rb
create mode 100644 test/test_sigevent.rb
diff --git a/lib/dtas.rb b/lib/dtas.rb
index 7e9c0d5..ae2f815 100644
--- a/lib/dtas.rb
+++ b/lib/dtas.rb
@@ -25,6 +25,14 @@ def self.null # :nodoc:
@null ||= File.open('/dev/null', 'r+')
end
+ @libc = nil
+ def self.libc
+ @libc ||= begin
+ require 'fiddle'
+ Fiddle.dlopen(nil)
+ end
+ end
+
# String#-@ will deduplicate strings when Ruby 2.5 is released (Dec 2017)
# https://bugs.ruby-lang.org/issues/13077
if RUBY_VERSION.to_f >= 2.5
diff --git a/lib/dtas/sigevent.rb b/lib/dtas/sigevent.rb
index d4a96d7..81b8160 100644
--- a/lib/dtas/sigevent.rb
+++ b/lib/dtas/sigevent.rb
@@ -3,8 +3,7 @@
# frozen_string_literal: true
begin
raise LoadError, "no eventfd with _DTAS_POSIX" if ENV["_DTAS_POSIX"]
- require 'sleepy_penguin'
- require_relative 'sigevent/efd'
+ require_relative 'sigevent/fiddle_efd'
rescue LoadError
require_relative 'sigevent/pipe'
end
diff --git a/lib/dtas/sigevent/efd.rb b/lib/dtas/sigevent/efd.rb
deleted file mode 100644
index 4be2c84..0000000
--- a/lib/dtas/sigevent/efd.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2013-2016 all contributors <dtas-all@nongnu.org>
-# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
-
-# used in various places for safe wakeups from IO.select via signals
-# This requires a modern Linux system and the "sleepy_penguin" RubyGem
-class DTAS::Sigevent < SleepyPenguin::EventFD # :nodoc:
- def self.new
- super(0, :CLOEXEC)
- end
-
- def signal
- incr(1)
- end
-
- def readable_iter
- value(true)
- yield self, nil # calls DTAS::Process.reaper
- :wait_readable
- end
-end
diff --git a/lib/dtas/sigevent/fiddle_efd.rb b/lib/dtas/sigevent/fiddle_efd.rb
new file mode 100644
index 0000000..e29f6ca
--- /dev/null
+++ b/lib/dtas/sigevent/fiddle_efd.rb
@@ -0,0 +1,38 @@
+# 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
+
+# used in various places for safe wakeups from IO.select via signals
+# This requires a modern GNU/Linux system with eventfd(2) support
+require_relative '../nonblock'
+require 'fiddle'
+class DTAS::Sigevent # :nodoc:
+
+ EventFD = Fiddle::Function.new(DTAS.libc['eventfd'],
+ [ Fiddle::TYPE_INT, Fiddle::TYPE_INT ], # initval, flags
+ Fiddle::TYPE_INT) # fd
+
+ attr_reader :to_io
+ ONE = [ 1 ].pack('Q').freeze
+
+ def initialize
+ fd = EventFD.call(0, 02000000|00004000) # EFD_CLOEXEC|EFD_NONBLOCK
+ raise "eventfd failed: #{Fiddle.last_error}" if fd < 0
+ @to_io = DTAS::Nonblock.for_fd(fd)
+ @buf = ''.b
+ end
+
+ def signal
+ @to_io.syswrite(ONE)
+ end
+
+ def readable_iter
+ @to_io.read_nonblock(8, @buf, exception: false)
+ yield self, nil # calls DTAS::Process.reaper
+ :wait_readable
+ end
+
+ def close
+ @to_io.close
+ end
+end
diff --git a/lib/dtas/sigevent/pipe.rb b/lib/dtas/sigevent/pipe.rb
index 921a5b3..0ea9d31 100644
--- a/lib/dtas/sigevent/pipe.rb
+++ b/lib/dtas/sigevent/pipe.rb
@@ -3,7 +3,7 @@
# frozen_string_literal: true
# used in various places for safe wakeups from IO.select via signals
-# A fallback for non-Linux systems lacking the "sleepy_penguin" RubyGem
+# A fallback for non-Linux systems lacking the "splice" syscall
require_relative '../nonblock'
class DTAS::Sigevent # :nodoc:
attr_reader :to_io
diff --git a/test/test_sigevent.rb b/test/test_sigevent.rb
new file mode 100644
index 0000000..6cfe528
--- /dev/null
+++ b/test/test_sigevent.rb
@@ -0,0 +1,20 @@
+# Copyright (C) 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 'helper'
+require 'dtas'
+require 'dtas/sigevent'
+
+class TestSigevent < Testcase
+ def test_sigevent
+ io = DTAS::Sigevent.new
+ io.signal
+ assert IO.select([io]), 'IO.select returns'
+ res = io.readable_iter do |f,arg|
+ assert_same io, f
+ assert_nil arg
+ end
+ assert_equal :wait_readable, res
+ assert_nil io.close
+ end
+end
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/5] buffer: replace sleepy_penguin with fiddle
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 ` Eric Wong
2019-12-01 1:26 ` [PATCH 4/5] watchable: use fiddle for inotify support Eric Wong
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-01 1:26 UTC (permalink / raw)
To: dtas-all
Fiddle exists on all Ruby 1.9.2+ installations and seems
alright. Since splice is a Linux-only API, we don't need to
worry about the values of constants changing (and they're
architecture-independent).
---
lib/dtas/buffer.rb | 7 +-
.../buffer/{splice.rb => fiddle_splice.rb} | 75 +++++++++++++++----
lib/dtas/buffer/read_write.rb | 4 +-
test/test_buffer.rb | 10 +--
4 files changed, 69 insertions(+), 27 deletions(-)
rename lib/dtas/buffer/{splice.rb => fiddle_splice.rb} (68%)
diff --git a/lib/dtas/buffer.rb b/lib/dtas/buffer.rb
index 39070d7..2bc44ba 100644
--- a/lib/dtas/buffer.rb
+++ b/lib/dtas/buffer.rb
@@ -8,11 +8,8 @@
class DTAS::Buffer # :nodoc:
begin
raise LoadError, "no splice with _DTAS_POSIX" if ENV["_DTAS_POSIX"]
- require 'sleepy_penguin' # splice is only in Linux for now...
- SleepyPenguin.respond_to?(:splice) or
- raise LoadError, 'sleepy_penguin 3.5+ required for splice', []
- require_relative 'buffer/splice'
- include DTAS::Buffer::Splice
+ require_relative 'buffer/fiddle_splice' # splice is only in Linux for now...
+ include DTAS::Buffer::FiddleSplice
rescue LoadError
require_relative 'buffer/read_write'
include DTAS::Buffer::ReadWrite
diff --git a/lib/dtas/buffer/splice.rb b/lib/dtas/buffer/fiddle_splice.rb
similarity index 68%
rename from lib/dtas/buffer/splice.rb
rename to lib/dtas/buffer/fiddle_splice.rb
index 2e86d0a..543b3e0 100644
--- a/lib/dtas/buffer/splice.rb
+++ b/lib/dtas/buffer/fiddle_splice.rb
@@ -2,16 +2,64 @@
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
# frozen_string_literal: true
require 'io/nonblock'
-require 'sleepy_penguin'
+require 'fiddle' # require_relative caller should expect LoadError
require_relative '../../dtas'
require_relative '../pipe'
-# Used by -player on Linux systems with the "sleepy_penguin" RubyGem installed
-module DTAS::Buffer::Splice # :nodoc:
+# Used by -player on Linux systems with the "splice" syscall
+module DTAS::Buffer::FiddleSplice # :nodoc:
MAX_AT_ONCE = 4096 # page size in Linux
MAX_AT_ONCE_1 = 65536
- F_MOVE = SleepyPenguin::F_MOVE
- F_NONBLOCK = SleepyPenguin::F_NONBLOCK
+ F_MOVE = 1
+ F_NONBLOCK = 2
+
+ Splice = Fiddle::Function.new(DTAS.libc['splice'], [
+ Fiddle::TYPE_INT, # int fd_in,
+ Fiddle::TYPE_VOIDP, # loff_t *off_in
+ Fiddle::TYPE_INT, # int fd_out
+ Fiddle::TYPE_VOIDP, # loff_t *off_out
+ Fiddle::TYPE_SIZE_T, # size_t len
+ Fiddle::TYPE_INT, # unsigned int flags
+ ],
+ Fiddle::TYPE_SSIZE_T) # ssize_t
+
+ Tee = Fiddle::Function.new(DTAS.libc['tee'], [
+ Fiddle::TYPE_INT, # int fd_in,
+ Fiddle::TYPE_INT, # int fd_out
+ Fiddle::TYPE_SIZE_T, # size_t len
+ Fiddle::TYPE_INT, # unsigned int flags
+ ],
+ Fiddle::TYPE_SSIZE_T) # ssize_t
+
+ def _syserr(s, func)
+ raise "BUG: we should not encounter EOF on #{func}" if s == 0
+ case errno = Fiddle.last_error
+ when Errno::EAGAIN::Errno
+ return :EAGAIN
+ when Errno::EPIPE::Errno
+ raise Errno::EPIPE.exception
+ when Errno::EINTR::Errno
+ return nil
+ else
+ raise SystemCallError, "#{func} error: #{errno}"
+ end
+ end
+
+ def splice(src, dst, len, flags)
+ begin
+ s = Splice.call(src.fileno, nil, dst.fileno, nil, len, flags)
+ return s if s > 0
+ sym = _syserr(s, 'splice') and return sym
+ end while true
+ end
+
+ def tee(src, dst, len, flags = 0)
+ begin
+ s = Tee.call(src.fileno, dst.fileno, len, flags)
+ return s if s > 0
+ sym = _syserr(s, 'tee') and return sym
+ end while true
+ end
def buffer_size
@to_io.pipe_size
@@ -25,14 +73,13 @@ def buffer_size=(bytes)
# be sure to only call this with nil when all writers to @wr are done
def discard(bytes)
- SleepyPenguin.splice(@to_io, DTAS.null, bytes)
+ splice(@to_io, DTAS.null, bytes, 0)
end
def broadcast_one(targets, limit = nil)
# single output is always non-blocking
limit ||= MAX_AT_ONCE_1
- s = SleepyPenguin.splice(@to_io, targets[0], limit, F_MOVE|F_NONBLOCK,
- exception: false)
+ s = splice(@to_io, targets[0], limit, F_MOVE|F_NONBLOCK)
if Symbol === s
targets # our one and only target blocked on write
else
@@ -48,7 +95,7 @@ def broadcast_one(targets, limit = nil)
def __tee_in_full(src, dst, bytes)
rv = 0
while bytes > 0
- s = SleepyPenguin.tee(src, dst, bytes)
+ s = tee(src, dst, bytes)
bytes -= s
rv += s
end
@@ -58,7 +105,7 @@ def __tee_in_full(src, dst, bytes)
def __splice_in_full(src, dst, bytes, flags)
rv = 0
while bytes > 0
- s = SleepyPenguin.splice(src, dst, bytes, flags)
+ s = splice(src, dst, bytes, flags)
rv += s
bytes -= s
end
@@ -71,9 +118,8 @@ def __broadcast_tee(blocked, targets, chunk_size)
targets.delete_if do |dst|
begin
t = (dst.nonblock? || most_teed == 0) ?
- SleepyPenguin.tee(@to_io, dst, chunk_size, F_NONBLOCK,
- exception: false) :
- __tee_in_full(@to_io, dst, chunk_size)
+ tee(@to_io, dst, chunk_size, F_NONBLOCK) :
+ __tee_in_full(@to_io, dst, chunk_size)
if Integer === t
if t > most_teed
chunk_size = t if most_teed == 0
@@ -120,8 +166,7 @@ def broadcast_inf(targets, limit = nil)
begin
targets << last
if last.nonblock? || most_teed == 0
- s = SleepyPenguin.splice(@to_io, last, bytes, F_MOVE|F_NONBLOCK,
- exception: false)
+ s = splice(@to_io, last, bytes, F_MOVE|F_NONBLOCK)
if Symbol === s
blocked << last
diff --git a/lib/dtas/buffer/read_write.rb b/lib/dtas/buffer/read_write.rb
index 04856c7..e2001b6 100644
--- a/lib/dtas/buffer/read_write.rb
+++ b/lib/dtas/buffer/read_write.rb
@@ -6,8 +6,8 @@
require_relative '../pipe'
require_relative '../nonblock'
-# compatibility code for systems lacking "splice" support via the
-# "sleepy_penguin" 3.5+ RubyGem. Used only by -player
+# compatibility code for non-Linux systems lacking "splice" support.
+# Used only by -player
module DTAS::Buffer::ReadWrite # :nodoc:
MAX_AT_ONCE = 512 # min PIPE_BUF value in POSIX
attr_accessor :buffer_size
diff --git a/test/test_buffer.rb b/test/test_buffer.rb
index 8f5d8b5..1773ca3 100644
--- a/test/test_buffer.rb
+++ b/test/test_buffer.rb
@@ -49,14 +49,14 @@ def test_set_buffer_size
buf = new_buffer
buf.buffer_size = @@max_size
assert_equal @@max_size, buf.buffer_size
- end if defined?(SleepyPenguin::F_GETPIPE_SZ)
+ end if defined?(DTAS::Pipe::F_GETPIPE_SZ)
def test_buffer_size
buf = new_buffer
assert_operator buf.buffer_size, :>, 128
buf.buffer_size = @@max_size
assert_equal @@max_size, buf.buffer_size
- end if defined?(SleepyPenguin::F_GETPIPE_SZ)
+ end if defined?(DTAS::Pipe::F_GETPIPE_SZ)
def test_broadcast_1
buf = new_buffer
@@ -108,7 +108,7 @@ def test_broadcast
assert_equal "HELLO", a[0].read(5)
assert_equal "HELLO", b[0].read(5)
- return unless defined?(SleepyPenguin::F_GETPIPE_SZ)
+ return unless defined?(DTAS::Pipe::F_GETPIPE_SZ)
b[1].nonblock = true
b[1].write('*' * pipe_size(b[1]))
@@ -167,7 +167,7 @@ def test_broadcast_all_full
buf.wr.write "HELLO"
assert_equal tmp, buf.broadcast(tmp)
assert_equal [a[1], b[1]], tmp
- end if defined?(SleepyPenguin::F_GETPIPE_SZ)
+ end if defined?(DTAS::Pipe::F_GETPIPE_SZ)
def test_serialize
buf = new_buffer
@@ -206,6 +206,6 @@ def test_load_size
end
def pipe_size(io)
- io.fcntl(SleepyPenguin::F_GETPIPE_SZ)
+ io.fcntl(DTAS::Pipe::F_GETPIPE_SZ)
end
end
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/5] watchable: use fiddle for inotify support
2019-12-01 1:26 [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
` (2 preceding siblings ...)
2019-12-01 1:26 ` [PATCH 3/5] buffer: replace sleepy_penguin with fiddle Eric Wong
@ 2019-12-01 1:26 ` Eric Wong
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
5 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-01 1:26 UTC (permalink / raw)
To: 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 <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
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/5] doc: remove "sleepy_penguin" references
2019-12-01 1:26 [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
` (3 preceding siblings ...)
2019-12-01 1:26 ` [PATCH 4/5] watchable: use fiddle for inotify support Eric Wong
@ 2019-12-01 1:26 ` Eric Wong
2019-12-13 18:16 ` [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
5 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-01 1:26 UTC (permalink / raw)
To: dtas-all
Less to install, less to document, a win for everybody!
---
Documentation/dtas-sinkedit.pod | 2 +-
Documentation/dtas-sourceedit.pod | 2 +-
INSTALL | 19 -------------------
dtas-linux.gemspec | 19 -------------------
4 files changed, 2 insertions(+), 40 deletions(-)
delete mode 100644 dtas-linux.gemspec
diff --git a/Documentation/dtas-sinkedit.pod b/Documentation/dtas-sinkedit.pod
index ee2d5b7..6787e25 100644
--- a/Documentation/dtas-sinkedit.pod
+++ b/Documentation/dtas-sinkedit.pod
@@ -13,7 +13,7 @@ dtas-sinkedit SINKNAME
dtas-sinkedit spawns an editor to allow editing of a sink as a YAML file.
See L<dtas-player_protocol(7)> for details on SINKARGS.
-On Linux machines with the sleepy_penguin RubyGem installed, L<inotify(7)>
+On Linux machines with the "fiddle" default RubyGem installed, L<inotify(7)>
is used to monitor the file for changes while the text editor is running.
Each time a user finishes saving a file, changes are committed immediately.
This behavior may be disabled by using the -N or --no-watch command-line
diff --git a/Documentation/dtas-sourceedit.pod b/Documentation/dtas-sourceedit.pod
index ee88e8f..be158d3 100644
--- a/Documentation/dtas-sourceedit.pod
+++ b/Documentation/dtas-sourceedit.pod
@@ -16,7 +16,7 @@ a pipe or file, it is parsed as YAML and fed to the L<dtas-player(1)> instance
non-interactively. This is useful for loading various profiles from the
filesystem.
-On Linux machines with the sleepy_penguin RubyGem installed, L<inotify(7)>
+On Linux machines with the "fiddle" default RubyGem installed, L<inotify(7)>
is used to monitor the file for changes while the text editor is running.
Each time a user finishes saving a file, changes are committed immediately.
This behavior may be disabled by using the -N or --no-watch command-line
diff --git a/INSTALL b/INSTALL
index d0b8a24..16d3d34 100644
--- a/INSTALL
+++ b/INSTALL
@@ -16,21 +16,6 @@ Debian 7+ users can install dependencies easily:
sudo apt-get install sox libsox-fmt-all mp3gain flac ruby-dev
-# installing dtas RubyGem on GNU/Linux (Linux kernel 2.6.32+)
-
-Be sure to have Ruby development headers and a working C compiler.
-This will pull in the sleepy_penguin RubyGems for minor
-speedups. If you cannot be bothered to have a development
-environment, just use "gem install dtas".
-
- sudo gem install dtas-linux
-
-This should pull in the "sleepy_penguin" RubyGems
-
-For future upgrades of dtas (upgrades to dtas-linux will be infrequent)
-
- sudo gem update dtas
-
# installing the dtas RubyGem on non-GNU/Linux or old GNU/Linux systems
sudo gem install dtas
@@ -45,10 +30,6 @@ Grab the latest tarball from our HTTPS site:
$ cd dtas-0.17.0
$ sudo ruby setup.rb
-GNU/Linux users may optionally install the "sleepy_penguin" package:
-
- * sleepy_penguin - https://bogomips.org/sleepy_penguin/
-
# CONTACT
Please do not hesitate to send plain-text mail to <dtas-all@nongnu.org>
diff --git a/dtas-linux.gemspec b/dtas-linux.gemspec
deleted file mode 100644
index cc9a8c8..0000000
--- a/dtas-linux.gemspec
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2013-2019 all contributors <dtas-all@nongnu.org>
-# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
-#
-# this just declares dependencies to make gem installation a little easier
-# for Linux users
-Gem::Specification.new do |s|
- s.name = %q{dtas-linux}
- s.version = '1.1.0'
- s.authors = ["dtas hackers"]
- s.summary = "meta-package for dtas users on the Linux kernel"
- s.description = "gives small performance improvements for dtas users\n" \
- "via tee(), splice() and eventfd() on Linux"
- s.email = %q{e@80x24.org}
- s.files = []
- s.homepage = 'https://80x24.org/dtas.git/about/'
- s.add_dependency(%q<dtas>, '~> 0.16')
- s.add_dependency(%q<sleepy_penguin>, '~> 3.5')
- s.licenses = 'GPL-3.0+'
-end
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 0/5] use fiddle for Linux-specific APIs
2019-12-01 1:26 [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
` (4 preceding siblings ...)
2019-12-01 1:26 ` [PATCH 5/5] doc: remove "sleepy_penguin" references Eric Wong
@ 2019-12-13 18:16 ` Eric Wong
2019-12-15 20:39 ` fiddle vs sleepy_penguin vs Perl syscall() bench scripts Eric Wong
5 siblings, 1 reply; 8+ messages in thread
From: Eric Wong @ 2019-12-13 18:16 UTC (permalink / raw)
To: dtas-all
I'll need to rework this series to maintain sleepy_penguin
support and only use fiddle as a fallback. libffi and fiddle
use more CPU, which is noticeable on an ancient laptop...
^ permalink raw reply [flat|nested] 8+ messages in thread
* fiddle vs sleepy_penguin vs Perl syscall() bench scripts
2019-12-13 18:16 ` [PATCH 0/5] use fiddle for Linux-specific APIs Eric Wong
@ 2019-12-15 20:39 ` Eric Wong
0 siblings, 0 replies; 8+ messages in thread
From: Eric Wong @ 2019-12-15 20:39 UTC (permalink / raw)
To: dtas-all
[-- Attachment #1: Type: text/plain, Size: 254 bytes --]
Eric Wong <e@80x24.org> wrote:
> I'll need to rework this series to maintain sleepy_penguin
> support and only use fiddle as a fallback. libffi and fiddle
> use more CPU, which is noticeable on an ancient laptop...
scripts used for testing attached :>
[-- Attachment #2: splice_bench.pl --]
[-- Type: text/x-perl, Size: 258 bytes --]
#!/usr/bin/perl -w
use strict;
use Benchmark qw(:all :hireswallclock);
BEGIN { require 'sys/syscall.ph' };
my $s;
my $t = timeit(1, sub {
do {
$s = syscall(SYS_splice, 0, undef, 1, undef, 4096, 0);
} while $s;
});
print STDERR "OK: ", timestr($t), "\n";
[-- Attachment #3: splice_bench.rb --]
[-- Type: application/x-ruby, Size: 884 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread