sleepy_penguin 3.4.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.document +1 -0
  3. data/.olddoc.yml +3 -4
  4. data/GIT-VERSION-GEN +1 -1
  5. data/LICENSE +3 -3
  6. data/README +7 -4
  7. data/TODO +1 -0
  8. data/ext/sleepy_penguin/cfr.c +62 -0
  9. data/ext/sleepy_penguin/epoll.c +34 -24
  10. data/ext/sleepy_penguin/eventfd.c +6 -5
  11. data/ext/sleepy_penguin/extconf.rb +6 -0
  12. data/ext/sleepy_penguin/init.c +83 -12
  13. data/ext/sleepy_penguin/inotify.c +48 -36
  14. data/ext/sleepy_penguin/kqueue.c +22 -21
  15. data/ext/sleepy_penguin/sendfile.c +120 -0
  16. data/ext/sleepy_penguin/sleepy_penguin.h +15 -28
  17. data/ext/sleepy_penguin/sp_copy.h +33 -0
  18. data/ext/sleepy_penguin/splice.c +174 -0
  19. data/ext/sleepy_penguin/timerfd.c +1 -5
  20. data/ext/sleepy_penguin/util.c +12 -0
  21. data/lib/sleepy_penguin.rb +28 -0
  22. data/lib/sleepy_penguin/cfr.rb +29 -0
  23. data/lib/sleepy_penguin/epoll.rb +13 -10
  24. data/lib/sleepy_penguin/kqueue.rb +6 -6
  25. data/lib/sleepy_penguin/sp.rb +1 -1
  26. data/lib/sleepy_penguin/splice.rb +125 -0
  27. data/pkg.mk +5 -12
  28. data/sleepy_penguin.gemspec +13 -15
  29. data/test/helper.rb +2 -7
  30. data/test/test_cfr.rb +35 -0
  31. data/test/test_constants.rb +2 -4
  32. data/test/test_epoll.rb +35 -6
  33. data/test/test_epoll_gc.rb +2 -5
  34. data/test/test_epoll_io.rb +3 -6
  35. data/test/test_epoll_optimizations.rb +2 -2
  36. data/test/test_eventfd.rb +2 -5
  37. data/test/test_inotify.rb +2 -4
  38. data/test/test_kqueue.rb +35 -7
  39. data/test/test_kqueue_io.rb +2 -5
  40. data/test/test_pipesize.rb +22 -0
  41. data/test/test_sendfile.rb +26 -0
  42. data/test/test_splice.rb +250 -0
  43. data/test/test_splice_eintr.rb +31 -0
  44. data/test/test_timerfd.rb +2 -5
  45. metadata +27 -34
  46. data/lib/sleepy_penguin/epoll/io.rb +0 -28
  47. data/lib/sleepy_penguin/kqueue/io.rb +0 -30
data/pkg.mk CHANGED
@@ -13,14 +13,6 @@ RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
13
13
  RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
14
14
  lib := lib
15
15
 
16
- ifeq ($(shell test -f script/isolate_for_tests && echo t),t)
17
- isolate_libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/isolate.mk
18
- $(isolate_libs): script/isolate_for_tests
19
- @$(RUBY) script/isolate_for_tests
20
- -include $(isolate_libs)
21
- lib := $(lib):$(ISOLATE_LIBS)
22
- endif
23
-
24
16
  ext := $(firstword $(wildcard ext/*))
25
17
  ifneq ($(ext),)
26
18
  ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
@@ -94,7 +86,7 @@ fix-perms:
94
86
  gem: $(pkggem)
95
87
 
96
88
  install-gem: $(pkggem)
97
- gem install $(CURDIR)/$<
89
+ gem install --local $(CURDIR)/$<
98
90
 
99
91
  $(pkggem): manifest fix-perms
100
92
  gem build $(rfpackage).gemspec
@@ -121,9 +113,10 @@ gem install-gem: GIT-VERSION-FILE
121
113
  $(MAKE) $@ VERSION=$(GIT_VERSION)
122
114
  endif
123
115
 
124
- all:: test
116
+ all:: check
125
117
  test_units := $(wildcard test/test_*.rb)
126
- test: test-unit
118
+ test: check
119
+ check: test-unit
127
120
  test-unit: $(test_units)
128
121
  $(test_units): build
129
122
  $(RUBY) -I $(lib) $@ $(RUBY_TEST_OPTS)
@@ -153,5 +146,5 @@ $(PLACEHOLDERS):
153
146
  echo olddoc_placeholder > $@
154
147
  endif
155
148
 
156
- .PHONY: all .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
149
+ .PHONY: all .FORCE-GIT-VERSION-FILE doc check test $(test_units) manifest
157
150
  .PHONY: check-warnings
@@ -1,24 +1,22 @@
1
- ENV["VERSION"] or abort "VERSION= must be specified"
2
- manifest = File.readlines('.manifest').map! { |x| x.chomp! }
3
- require 'olddoc'
4
- extend Olddoc::Gemspec
5
- name, summary, title = readme_metadata
1
+ manifest = File.exist?('.manifest') ?
2
+ IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
6
3
 
7
4
  Gem::Specification.new do |s|
8
5
  s.name = %q{sleepy_penguin}
9
- s.version = ENV["VERSION"].dup
10
- s.homepage = Olddoc.config['rdoc_url']
11
- s.authors = ["#{name} hackers"]
12
- s.description = readme_description
6
+ s.version = (ENV['VERSION'] || '3.5.0').dup
7
+ s.homepage = 'https://bogomips.org/sleepy_penguin/'
8
+ s.authors = ['sleepy_penguin hackers']
9
+ s.description = File.read('README').split("\n\n")[1]
13
10
  s.email = %q{sleepy-penguin@bogomips.org}
14
- s.extra_rdoc_files = extra_rdoc_files(manifest)
15
11
  s.files = manifest
16
- s.summary = summary
12
+ s.summary = 'Linux I/O events for Ruby'
17
13
  s.test_files = Dir['test/test_*.rb']
18
14
  s.extensions = %w(ext/sleepy_penguin/extconf.rb)
19
- s.add_development_dependency('minitest', '~> 5.0')
20
- s.add_development_dependency('olddoc', '~> 1.0')
15
+ s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
16
+ File.exist?(f)
17
+ end
18
+ s.add_development_dependency('test-unit', '~> 3.0')
21
19
  s.add_development_dependency('strace_me', '~> 1.0')
22
-
23
- s.licenses = %w(LGPLv2.1+)
20
+ s.required_ruby_version = '>= 2.0'
21
+ s.licenses = %w(LGPL-2.1+)
24
22
  end
@@ -1,11 +1,6 @@
1
1
  $-w = $stdout.sync = $stderr.sync = Thread.abort_on_exception = true
2
- gem 'minitest'
3
- require 'minitest/autorun'
4
- Testcase = begin
5
- Minitest::Test # minitest 5
6
- rescue NameError
7
- Minitest::Unit::TestCase # minitest 4
8
- end
2
+ require 'test/unit'
3
+ require 'sleepy_penguin'
9
4
 
10
5
  def check_cloexec(io)
11
6
  pipe = IO.pipe
@@ -0,0 +1,35 @@
1
+ # -*- encoding: binary -*-
2
+ require_relative 'helper'
3
+ require 'tempfile'
4
+
5
+ class TestCfr < Test::Unit::TestCase
6
+ def test_copy_file_range
7
+ str = 'abcde'
8
+ size = 5
9
+ src = Tempfile.new('ruby_cfr_src')
10
+ dst = Tempfile.new('ruby_cfr_dst')
11
+ assert_equal 5, src.syswrite(str)
12
+ src.sysseek(0)
13
+ begin
14
+ nr = SleepyPenguin.copy_file_range(src, dst, size)
15
+ rescue Errno::EINVAL
16
+ warn 'copy_file_range not supported (requires Linux 4.5+)'
17
+ warn "We have: #{`uname -a`}"
18
+ return
19
+ end
20
+ assert_equal nr, 5
21
+ dst.sysseek(0)
22
+ assert_equal str, dst.sysread(5)
23
+
24
+ nr = SleepyPenguin.copy_file_range(src, dst, size, off_in: 1, off_out: 0)
25
+ assert_equal 4, nr
26
+ dst.sysseek(0)
27
+ assert_equal 'bcde', dst.sysread(4)
28
+
29
+ nr = SleepyPenguin.copy_file_range(src, dst, size, off_in: 9)
30
+ assert_equal 0, nr, 'no EOFError'
31
+ ensure
32
+ dst.close!
33
+ src.close!
34
+ end
35
+ end if SleepyPenguin.respond_to?(:copy_file_range)
@@ -1,9 +1,7 @@
1
- require './test/helper'
2
- $-w = true
3
- Thread.abort_on_exception = true
4
1
  require 'sleepy_penguin/sp'
2
+ require_relative 'helper'
5
3
 
6
- class TestConstants < Testcase
4
+ class TestConstants < Test::Unit::TestCase
7
5
  def test_constants
8
6
  assert_equal SleepyPenguin::SLEEPY_PENGUIN_VERSION,
9
7
  SP::SLEEPY_PENGUIN_VERSION
@@ -1,13 +1,9 @@
1
- require './test/helper'
1
+ require_relative 'helper'
2
2
  require 'fcntl'
3
3
  require 'socket'
4
4
  require 'thread'
5
- $-w = true
6
- Thread.abort_on_exception = true
7
5
 
8
- require 'sleepy_penguin'
9
-
10
- class TestEpoll < Testcase
6
+ class TestEpoll < Test::Unit::TestCase
11
7
  include SleepyPenguin
12
8
 
13
9
  def setup
@@ -343,6 +339,13 @@ class TestEpoll < Testcase
343
339
  @ep.close
344
340
  io = Epoll.new(Epoll::CLOEXEC).to_io
345
341
  assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == Fcntl::FD_CLOEXEC)
342
+ io.close
343
+
344
+ # prettier, slower, but more memory efficient due to lack of caching
345
+ # due to the constant cache:
346
+ io = Epoll.new(:CLOEXEC).to_io
347
+
348
+ assert((io.fcntl(Fcntl::F_GETFD) & Fcntl::FD_CLOEXEC) == Fcntl::FD_CLOEXEC)
346
349
  end
347
350
 
348
351
  def test_new
@@ -531,4 +534,30 @@ class TestEpoll < Testcase
531
534
  end
532
535
  @ep.wait(1) { |flags, io| assert_equal(first[0], io) }
533
536
  end
537
+
538
+ def test_epoll_nest
539
+ ep2 = Epoll.new
540
+ r, w = IO.pipe
541
+ @ep.add(@rd, :IN)
542
+ @ep.add(@wr, :OUT)
543
+ ep2.add(r, :IN)
544
+ ep2.add(w, :OUT)
545
+ w.write('.')
546
+ @wr.write('.')
547
+ outer = []
548
+ inner = []
549
+ nr = 0
550
+ @ep.wait(2) do |_, io|
551
+ outer << io
552
+ ep2.wait(2) do |_, io2|
553
+ (inner[nr] ||= []) << io2
554
+ end
555
+ nr += 1
556
+ end
557
+ assert_equal [ @rd, @wr ].sort_by(&:fileno), outer.sort_by(&:fileno)
558
+ exp = [ r, w ].sort_by(&:fileno)
559
+ assert_equal [ exp, exp ], inner.map { |x| x.sort_by(&:fileno) }
560
+ ensure
561
+ [ r, w, ep2 ].compact.each(&:close)
562
+ end
534
563
  end if defined?(SleepyPenguin::Epoll)
@@ -1,9 +1,6 @@
1
- require './test/helper'
2
- $-w = true
1
+ require_relative 'helper'
3
2
 
4
- require 'sleepy_penguin'
5
-
6
- class TestEpollGC < Testcase
3
+ class TestEpollGC < Test::Unit::TestCase
7
4
  include SleepyPenguin
8
5
 
9
6
  def setup
@@ -1,12 +1,9 @@
1
- require './test/helper'
1
+ require_relative 'helper'
2
2
  require 'fcntl'
3
3
  require 'socket'
4
4
  require 'thread'
5
- $-w = true
6
- Thread.abort_on_exception = true
7
- require 'sleepy_penguin'
8
5
 
9
- class TestEpollIO < Testcase
6
+ class TestEpollIO < Test::Unit::TestCase
10
7
  include SleepyPenguin
11
8
 
12
9
  def setup
@@ -23,7 +20,7 @@ class TestEpollIO < Testcase
23
20
 
24
21
  class EpSub < Epoll::IO
25
22
  def self.new
26
- super(SleepyPenguin::Epoll::CLOEXEC)
23
+ super(:CLOEXEC)
27
24
  end
28
25
  end
29
26
 
@@ -1,4 +1,4 @@
1
- require './test/helper'
1
+ require_relative 'helper'
2
2
  begin
3
3
  require 'strace'
4
4
  rescue LoadError
@@ -7,7 +7,7 @@ $-w = true
7
7
 
8
8
  require 'sleepy_penguin'
9
9
 
10
- class TestEpollOptimizations < Testcase
10
+ class TestEpollOptimizations < Test::Unit::TestCase
11
11
  include SleepyPenguin
12
12
  IO_PURGATORY = []
13
13
 
@@ -1,10 +1,7 @@
1
- require './test/helper'
1
+ require_relative 'helper'
2
2
  require 'fcntl'
3
- $-w = true
4
3
 
5
- require 'sleepy_penguin'
6
-
7
- class TestEventFD < Testcase
4
+ class TestEventFD < Test::Unit::TestCase
8
5
  include SleepyPenguin
9
6
 
10
7
  def test_constants
@@ -1,11 +1,9 @@
1
- require './test/helper'
1
+ require_relative 'helper'
2
2
  require 'fcntl'
3
3
  require 'tempfile'
4
4
  require 'set'
5
- $-w = true
6
- require 'sleepy_penguin'
7
5
 
8
- class TestInotify < Testcase
6
+ class TestInotify < Test::Unit::TestCase
9
7
  include SleepyPenguin
10
8
  attr_reader :ino
11
9
 
@@ -1,9 +1,6 @@
1
- require './test/helper'
2
- $-w = true
3
- Thread.abort_on_exception = true
4
- require 'sleepy_penguin'
1
+ require_relative 'helper'
5
2
 
6
- class TestKqueue < Testcase
3
+ class TestKqueue < Test::Unit::TestCase
7
4
  include SleepyPenguin
8
5
 
9
6
  def test_kqueue
@@ -71,5 +68,36 @@ class TestKqueue < Testcase
71
68
  ensure
72
69
  kq.close
73
70
  end
74
- end if defined?(SleepyPenguin::Kqueue) &&
75
- IO.instance_methods.include?(:autoclose=)
71
+
72
+ def test_epoll_nest
73
+ kq1 = Kqueue.new
74
+ kq2 = Kqueue.new
75
+ r1, w1 = IO.pipe
76
+ r2, w2 = IO.pipe
77
+ w1.write '.'
78
+ w2.write '.'
79
+ kq1.kevent([
80
+ Kevent[r1.fileno, EvFilt::READ, Ev::ADD, 0, 0, r1],
81
+ Kevent[w1.fileno, EvFilt::WRITE, Ev::ADD, 0, 0, w1]
82
+ ])
83
+ kq2.kevent([
84
+ Kevent[r2.fileno, EvFilt::READ, Ev::ADD, 0, 0, r2],
85
+ Kevent[w2.fileno, EvFilt::WRITE, Ev::ADD, 0, 0, w2]
86
+ ])
87
+ outer = []
88
+ inner = []
89
+ nr = 0
90
+ kq1.kevent(nil, 2) do |kev1|
91
+ outer << kev1.udata
92
+ kq2.kevent(nil, 2) do |kev2|
93
+ (inner[nr] ||= []) << kev2.udata
94
+ end
95
+ nr += 1
96
+ end
97
+ assert_equal [ r1, w1 ].sort_by(&:fileno), outer.sort_by(&:fileno)
98
+ exp = [ r2, w2 ].sort_by(&:fileno)
99
+ assert_equal [ exp, exp ], inner.map { |x| x.sort_by(&:fileno) }
100
+ ensure
101
+ [ r1, w1, r2, w2, kq1, kq2 ].compact.each(&:close)
102
+ end
103
+ end if defined?(SleepyPenguin::Kqueue)
@@ -1,9 +1,6 @@
1
- require './test/helper'
2
- $-w = true
3
- Thread.abort_on_exception = true
4
- require 'sleepy_penguin'
1
+ require_relative 'helper'
5
2
 
6
- class TestKqueueIO < Testcase
3
+ class TestKqueueIO < Test::Unit::TestCase
7
4
  include SleepyPenguin
8
5
 
9
6
  def setup
@@ -0,0 +1,22 @@
1
+ # -*- encoding: binary -*-
2
+ require_relative 'helper'
3
+ require 'fcntl'
4
+
5
+ class TestPipesize < Test::Unit::TestCase
6
+ def test_pipe_size
7
+ return unless RUBY_PLATFORM =~ /linux/
8
+ [ :F_GETPIPE_SZ, :F_SETPIPE_SZ ].each do |c|
9
+ return unless SleepyPenguin.const_defined?(c)
10
+ end
11
+ r, w = pipe = IO.pipe
12
+ nr = r.fcntl(SleepyPenguin::F_GETPIPE_SZ)
13
+ assert_kind_of Integer, nr
14
+ assert_operator nr, :>, 0
15
+
16
+ set = 131072
17
+ r.fcntl(SleepyPenguin::F_SETPIPE_SZ, set)
18
+ assert_equal set, r.fcntl(SleepyPenguin::F_GETPIPE_SZ)
19
+ ensure
20
+ pipe.each(&:close) if pipe
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: binary -*-
2
+ require_relative 'helper'
3
+ require 'tempfile'
4
+ require 'socket'
5
+
6
+ class TestSendfile < Test::Unit::TestCase
7
+ def test_linux_sendfile
8
+ rd, wr = UNIXSocket.pair
9
+ size = 5
10
+ src = Tempfile.new('ruby_sf_src')
11
+ assert_equal 0, SleepyPenguin.linux_sendfile(wr, src, size)
12
+ str = 'abcde'.freeze
13
+ assert_equal str.bytesize, src.syswrite(str)
14
+ assert_equal 0, SleepyPenguin.linux_sendfile(wr, src, size)
15
+ src.sysseek(0, IO::SEEK_SET)
16
+ assert_equal str.bytesize,
17
+ SleepyPenguin.linux_sendfile(wr, src, size, offset: 0)
18
+ assert_equal str, rd.read(size)
19
+ assert_equal 0, src.sysseek(0, IO::SEEK_CUR), 'handle offset not changed'
20
+ assert_equal 3, SleepyPenguin.linux_sendfile(wr, src, 3)
21
+ assert_equal 3, src.sysseek(0, IO::SEEK_CUR), 'handle offset changed'
22
+ ensure
23
+ [ rd, wr ].compact.each(&:close)
24
+ src.close! if src
25
+ end
26
+ end
@@ -0,0 +1,250 @@
1
+ # -*- encoding: binary -*-
2
+ require_relative 'helper'
3
+ require 'tempfile'
4
+ require 'socket'
5
+ require 'io/nonblock'
6
+ require 'timeout'
7
+
8
+ class TestSplice < Test::Unit::TestCase
9
+
10
+ def test_splice
11
+ str = 'abcde'
12
+ size = 5
13
+ rd, wr = IO.pipe
14
+ tmp = Tempfile.new('ruby_splice')
15
+
16
+ assert_equal 5, tmp.syswrite(str)
17
+ tmp.sysseek(0)
18
+
19
+ nr = SleepyPenguin.splice(tmp.fileno, wr.fileno, size)
20
+ assert_equal size, nr
21
+ assert_equal str, rd.sysread(size)
22
+ end
23
+
24
+ def test_splice_io
25
+ str = 'abcde'
26
+ size = 5
27
+ rd, wr = IO.pipe
28
+ tmp = Tempfile.new('ruby_splice')
29
+
30
+ assert_equal 5, tmp.syswrite(str)
31
+ tmp.sysseek(0)
32
+
33
+ nr = SleepyPenguin.splice(tmp, wr, size)
34
+ assert_equal size, nr
35
+ assert_equal str, rd.sysread(size)
36
+ end
37
+
38
+ def test_splice_io_noflags
39
+ str = 'abcde'
40
+ size = 5
41
+ rd, wr = IO.pipe
42
+ tmp = Tempfile.new('ruby_splice')
43
+
44
+ assert_equal 5, tmp.syswrite(str)
45
+ tmp.sysseek(0)
46
+
47
+ nr = SleepyPenguin.splice(tmp, wr, size)
48
+ assert_equal size, nr
49
+ assert_equal str, rd.sysread(size)
50
+ end
51
+
52
+ def test_trysplice_io_noflags
53
+ str = 'abcde'
54
+ size = 5
55
+ rd, wr = IO.pipe
56
+ tmp = Tempfile.new('ruby_splice')
57
+
58
+ assert_equal 5, tmp.syswrite(str)
59
+ tmp.sysseek(0)
60
+
61
+ nr = SleepyPenguin.splice(tmp, wr, size, :nonblock, exception: false)
62
+ assert_equal size, nr
63
+ assert_equal str, rd.sysread(size)
64
+ end
65
+
66
+ def test_splice_io_ish
67
+ str = 'abcde'
68
+ size = 5
69
+ rd, wr = IO.pipe
70
+ tmp = Tempfile.new('ruby_splice')
71
+ io_ish = [ tmp ]
72
+ def io_ish.to_io
73
+ first.to_io
74
+ end
75
+
76
+ assert_equal 5, tmp.syswrite(str)
77
+ tmp.sysseek(0)
78
+
79
+ nr = SleepyPenguin.splice(io_ish, wr, size)
80
+ assert_equal size, nr
81
+ assert_equal str, rd.sysread(size)
82
+ end
83
+
84
+ def test_splice_in_offset
85
+ str = 'abcde'
86
+ off = 3
87
+ len = 2
88
+ rd, wr = IO.pipe
89
+ tmp = Tempfile.new('ruby_splice')
90
+
91
+ assert_equal 5, tmp.syswrite(str)
92
+ tmp.sysseek(0)
93
+
94
+ nr = SleepyPenguin.splice(tmp.fileno, wr.fileno, len, off_in: off)
95
+ assert_equal len, nr
96
+ assert_equal 'de', rd.sysread(len)
97
+ end
98
+
99
+ def test_splice_out_offset
100
+ str = 'abcde'
101
+ rd, wr = IO.pipe
102
+ tmp = Tempfile.new('ruby_splice')
103
+
104
+ assert_equal 5, wr.syswrite(str)
105
+ nr = SleepyPenguin.splice(rd.fileno, tmp.fileno, str.size, off_out: 3)
106
+ assert_equal 5, nr
107
+ tmp.sysseek(0)
108
+ assert_equal "\0\0\0abcde", tmp.sysread(9)
109
+ end
110
+
111
+ def test_splice_nonblock
112
+ rd, wr = IO.pipe
113
+ tmp = Tempfile.new('ruby_splice')
114
+
115
+ assert_raises(Errno::EAGAIN) {
116
+ SleepyPenguin.splice(rd.fileno, tmp.fileno, 5, :nonblock, off_out: 0)
117
+ }
118
+ end
119
+
120
+ def test_trysplice_nonblock
121
+ rd, wr = IO.pipe
122
+ tmp = Tempfile.new('ruby_splice')
123
+ assert_equal :EAGAIN, SleepyPenguin.splice(rd, tmp, 5, :nonblock,
124
+ off_out: 0, exception: false)
125
+ end
126
+
127
+ def test_trysplice_nonblock_noargs
128
+ rd, wr = IO.pipe
129
+ tmp = Tempfile.new('ruby_splice')
130
+ assert_equal :EAGAIN, SleepyPenguin.splice(rd, tmp, 5, :nonblock,
131
+ off_out: 0, exception: false)
132
+ assert_equal :EAGAIN, SleepyPenguin.splice(rd, tmp, 5, [:more,:nonblock],
133
+ off_out: 0,
134
+ exception: false)
135
+ end
136
+
137
+ def test_splice_eof
138
+ rd, wr = IO.pipe
139
+ tmp = Tempfile.new('ruby_splice')
140
+ wr.syswrite 'abc'
141
+ wr.close
142
+
143
+ nr = SleepyPenguin.splice(rd.fileno, tmp.fileno, 5, :nonblock, off_out: 0)
144
+ assert_equal 3, nr
145
+ assert_raises(EOFError) {
146
+ SleepyPenguin.splice(rd.fileno, tmp.fileno, 5, :nonblock, off_out: 0)
147
+ }
148
+ end
149
+
150
+ def test_trysplice_eof
151
+ rd, wr = IO.pipe
152
+ tmp = Tempfile.new('ruby_splice')
153
+ wr.syswrite 'abc'
154
+ wr.close
155
+
156
+ nr = SleepyPenguin.splice(rd, tmp, 5, off_out: 0, exception: false)
157
+ assert_equal 3, nr
158
+ assert_nil SleepyPenguin.splice(rd, tmp, 5, :nonblock,
159
+ off_out: 0, exception: false)
160
+ end
161
+
162
+ def test_splice_nonblock_socket
163
+ server = TCPServer.new('127.0.0.1', 0)
164
+ port = server.addr[1]
165
+ rp, wp = IO.pipe
166
+ rs = TCPSocket.new('127.0.0.1', port)
167
+ rs.nonblock = true
168
+ assert_raises(Errno::EAGAIN) {
169
+ SleepyPenguin.splice(rs, wp, 1024)
170
+ }
171
+ rs.close
172
+ server.close
173
+ end
174
+
175
+ def test_tee
176
+ str = 'abcde'
177
+ size = 5
178
+ rda, wra = IO.pipe
179
+ rdb, wrb = IO.pipe
180
+
181
+ assert_equal 5, wra.syswrite(str)
182
+ nr = SleepyPenguin.tee(rda.fileno, wrb.fileno, size)
183
+ assert_equal 5, nr
184
+ assert_equal str, rdb.sysread(5)
185
+ assert_equal str, rda.sysread(5)
186
+ end
187
+
188
+ def test_trytee
189
+ str = 'abcde'
190
+ size = 5
191
+ rda, wra = IO.pipe
192
+ rdb, wrb = IO.pipe
193
+
194
+ assert_equal 5, wra.syswrite(str)
195
+ nr = SleepyPenguin.tee(rda, wrb, size, :nonblock, exception: false)
196
+ assert_equal 5, nr
197
+ assert_equal str, rdb.sysread(5)
198
+ assert_equal str, rda.sysread(5)
199
+ end
200
+
201
+ def test_tee_eof
202
+ rda, wra = IO.pipe
203
+ rdb, wrb = IO.pipe
204
+ wra.close
205
+ assert_raises(EOFError) {
206
+ SleepyPenguin.tee(rda.fileno, wrb.fileno, 4096)
207
+ }
208
+ end
209
+
210
+ def test_trytee_eof
211
+ rda, wra = IO.pipe
212
+ rdb, wrb = IO.pipe
213
+ wra.close
214
+ assert_nil SleepyPenguin.tee(rda, wrb, 4096, :nonblock, exception: false)
215
+ end
216
+
217
+ def test_tee_nonblock
218
+ rda, wra = IO.pipe
219
+ rdb, wrb = IO.pipe
220
+ assert_raises(Errno::EAGAIN) {
221
+ SleepyPenguin.tee(rda.fileno, wrb.fileno, 4096, SleepyPenguin::F_NONBLOCK)
222
+ }
223
+ end
224
+
225
+ def test_trytee_nonblock
226
+ rda, wra = IO.pipe
227
+ rdb, wrb = IO.pipe
228
+ assert_equal :EAGAIN, SleepyPenguin.tee(rda, wrb, 4096, :nonblock,
229
+ exception: false)
230
+ end
231
+
232
+ def test_tee_io
233
+ str = 'abcde'
234
+ size = 5
235
+ rda, wra = IO.pipe
236
+ rdb, wrb = IO.pipe
237
+
238
+ assert_equal 5, wra.syswrite(str)
239
+ nr = SleepyPenguin.tee(rda, wrb, size)
240
+ assert_equal 5, nr
241
+ assert_equal str, rdb.sysread(5)
242
+ assert_equal str, rda.sysread(5)
243
+ end
244
+
245
+ def test_constants
246
+ %w(move nonblock more).each { |x|
247
+ assert Integer === SleepyPenguin.const_get("F_#{x.upcase}")
248
+ }
249
+ end
250
+ end if SleepyPenguin.respond_to?(:splice)