dtas-all
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 3/5] buffer: replace sleepy_penguin with fiddle


From: Eric Wong
Subject: [PATCH 3/5] buffer: replace sleepy_penguin with fiddle
Date: Sun, 1 Dec 2019 01:26:51 +0000

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]