io_splice 2.2.0 → 2.2.0.18.g3025

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.
data/io_splice.gemspec CHANGED
@@ -1,38 +1,26 @@
1
1
  # -*- encoding: binary -*-
2
-
3
2
  ENV["VERSION"] or abort "VERSION= must be specified"
4
3
  manifest = File.readlines('.manifest').map! { |x| x.chomp! }
5
- test_files = manifest.grep(%r{\Atest/test_.*\.rb\z})
4
+ require 'wrongdoc'
5
+ extend Wrongdoc::Gemspec
6
+ name, summary, title = readme_metadata
6
7
 
7
8
  Gem::Specification.new do |s|
8
9
  s.name = %q{io_splice}
9
- s.version = ENV["VERSION"]
10
-
11
- s.authors = ["io_splice hackers"]
10
+ s.version = ENV["VERSION"].dup
11
+ s.authors = ["Ruby io_splice hackers"]
12
12
  s.date = Time.now.utc.strftime('%Y-%m-%d')
13
- s.description = File.read("README").split(/\n\n/)[1]
13
+ s.description = readme_description
14
14
  s.email = %q{ruby.io.splice@librelist.com}
15
15
  s.extensions = %w(ext/io_splice/extconf.rb)
16
-
17
- s.extra_rdoc_files = File.readlines('.document').map! do |x|
18
- x.chomp!
19
- if File.directory?(x)
20
- manifest.grep(%r{\A#{x}/})
21
- elsif File.file?(x)
22
- x
23
- else
24
- nil
25
- end
26
- end.flatten.compact
27
-
16
+ s.extra_rdoc_files = extra_rdoc_files(manifest)
28
17
  s.files = manifest
29
- s.homepage = %q{http://bogomips.org/ruby_io_splice/}
30
- s.summary = %q{zero-copy pipe I/O for Linux and Ruby}
31
- s.rdoc_options = [ "-Na", "-t", "io_splice - #{s.summary}" ]
32
- s.require_paths = %w(lib)
18
+ s.homepage = Wrongdoc.config[:rdoc_url]
19
+ s.summary = summary
20
+ s.rdoc_options = rdoc_options
33
21
  s.rubyforge_project = %q{qrp}
34
-
35
- s.test_files = test_files
22
+ s.test_files = Dir['test/test_*.rb']
23
+ s.add_development_dependency('wrongdoc', '~> 1.5')
36
24
 
37
25
  # s.licenses = %w(LGPL) # accessor not compatible with older RubyGems
38
26
  end
data/lib/io/splice.rb CHANGED
@@ -1,120 +1,114 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'io_splice_ext'
3
3
 
4
- class IO
4
+ module IO::Splice
5
5
 
6
- module Splice
6
+ # the version of IO::Splice, currently 2.2.0
7
+ VERSION = '2.2.0'
7
8
 
8
- # the version of IO::Splice, currently 2.2.0
9
- VERSION = '2.2.0'
10
-
11
- # The maximum default capacity of the pipe in bytes.
12
- # Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before
13
- # We detect this at runtime as it is easy to recompile the kernel
14
- # and set a new value.
15
- # Starting with Linux 2.6.35, pipe capacity will be tunable
16
- # and this will only represent the default capacity of a
17
- # newly-created pipe.
18
- PIPE_CAPA = begin
19
- rd, wr = IO.pipe
20
- buf = ' ' * PIPE_BUF
21
- n = 0
22
- begin
23
- n += wr.write_nonblock(buf)
24
- rescue Errno::EAGAIN
25
- break
26
- end while true
27
- wr.close
28
- rd.close
29
- n
30
- end
9
+ # The maximum default capacity of the pipe in bytes.
10
+ # Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before
11
+ # We detect this at runtime as it is easy to recompile the kernel
12
+ # and set a new value.
13
+ # Starting with Linux 2.6.35, pipe capacity will be tunable
14
+ # and this will only represent the default capacity of a
15
+ # newly-created pipe.
16
+ PIPE_CAPA = begin
17
+ rd, wr = IO.pipe
18
+ buf = ' ' * PIPE_BUF
19
+ n = 0
20
+ begin
21
+ n += wr.write_nonblock(buf)
22
+ rescue Errno::EAGAIN
23
+ break
24
+ end while true
25
+ wr.close
26
+ rd.close
27
+ n
28
+ end
31
29
 
32
- # copies the contents of the IO object given by +src+ to +dst+
33
- # If len is specified, then only len bytes are copied. Otherwise
34
- # the copy will be until EOF is reached on the +src+.
35
- # +src+ and +dst+ must be IO objects or respond to +to_io+
36
- def Splice.copy_stream(src, dst, len = nil, src_offset = nil)
37
- close = []
38
- src.kind_of?(String) and close << (src = File.open(src, 'rb'))
39
- dst.kind_of?(String) and close << (dst = File.open(dst, 'wb'))
40
- src, dst = src.to_io, dst.to_io
41
- rv = len
42
- src.sysseek(src_offset) if src_offset
43
- select_args = selectable(src, dst)
30
+ # copies the contents of the IO object given by +src+ to +dst+
31
+ # If +len+ is specified, then only +len+ bytes are copied and
32
+ # +EOFError+ is raised if fewer than +len+ bytes could be copied.
33
+ # Otherwise the copy will be until EOF is reached on the +src+.
34
+ # +src+ and +dst+ must be IO objects or respond to +to_io+
35
+ def self.copy_stream(src, dst, len = nil, src_offset = nil)
36
+ close = []
37
+ src.kind_of?(String) and close << (src = File.open(src))
38
+ dst.kind_of?(String) and close << (dst = File.open(dst, "w"))
39
+ src, dst = src.to_io, dst.to_io
40
+ rv = len
41
+ src.sysseek(src_offset) if src_offset
42
+ select_args = selectable(src, dst)
44
43
 
45
- if src.stat.pipe? || dst.stat.pipe?
46
- if len
47
- len -= full(src, dst, len, select_args) until len == 0
48
- else
49
- rv = 0
50
- begin
51
- rv += partial(src, dst, PIPE_CAPA, select_args)
52
- rescue EOFError
53
- break
54
- end while true
44
+ if src.stat.pipe? || dst.stat.pipe?
45
+ if len
46
+ len -= full(src, dst, len, select_args) until len == 0
47
+ else
48
+ rv = 0
49
+ while n = partial(src, dst, PIPE_CAPA, select_args)
50
+ rv += n
51
+ end
52
+ end
53
+ else
54
+ r, w = tmp = IO.pipe
55
+ close.concat(tmp)
56
+ if len
57
+ while len != 0 && n = partial(src, w, len, select_args)
58
+ len -= full(r, dst, n, select_args)
55
59
  end
56
60
  else
57
- r, w = tmp = IO.pipe
58
- close.concat(tmp)
59
- if len
60
- while len != 0
61
- nr = partial(src, w, len, select_args)
62
- len -= full(r, dst, nr, select_args)
63
- end
64
- else
65
- rv = 0
66
- begin
67
- nr = partial(src, w, PIPE_CAPA, select_args)
68
- rv += full(r, dst, nr, select_args)
69
- rescue EOFError
70
- break
71
- end while true
61
+ rv = 0
62
+ while n = partial(src, w, PIPE_CAPA, select_args)
63
+ rv += full(r, dst, n, select_args)
72
64
  end
73
65
  end
74
-
75
- rv
76
- ensure
77
- close.each { |io| io.close }
78
66
  end
79
67
 
80
- # splice the full amount specified from +src+ to +dst+
81
- # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
82
- # may BOTH be pipes in Linux 2.6.31 or later.
83
- # This will block and wait for IO completion of +len+
84
- # bytes. Returns the nubmer of bytes actually spliced (always +len+)
85
- # The +_select_args+ parameter is reserved for internal use and
86
- # may be removed in future versions. Do not write code that
87
- # depends on +_select_args+.
88
- def Splice.full(src, dst, len, _select_args = selectable(src, dst))
89
- nr = len
90
- nr -= partial(src, dst, nr, _select_args) until nr == 0
91
- len
92
- end
68
+ rv
69
+ ensure
70
+ close.each { |io| io.close }
71
+ end
93
72
 
94
- # splice up to +len+ bytes from +src+ to +dst+.
95
- # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
96
- # may BOTH be pipes in Linux 2.6.31 or later.
97
- # Returns the number of bytes actually spliced.
98
- # Like IO#readpartial, this never returns Errno::EAGAIN
99
- # The +_select_args+ parameter is reserved for internal use and
100
- # may be removed in future versions. Do not write code that
101
- # depends on +_select_args+.
102
- def Splice.partial(src, dst, len, _select_args = selectable(src, dst))
103
- begin
104
- IO.splice(src, nil, dst, nil, len, F_MOVE)
105
- rescue Errno::EAGAIN
106
- IO.select(*_select_args)
107
- retry
108
- end
73
+ # splice the full amount specified from +src+ to +dst+
74
+ # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
75
+ # may BOTH be pipes in Linux 2.6.31 or later.
76
+ # This will block and wait for IO completion of +len+
77
+ # Raises +EOFError+ if end of file is reached.
78
+ # bytes. Returns the number of bytes actually spliced (always +len+)
79
+ # The +_select_args+ parameter is reserved for internal use and
80
+ # may be removed in future versions. Do not write code that
81
+ # depends on +_select_args+.
82
+ def self.full(src, dst, len, _select_args = selectable(src, dst))
83
+ nr = len
84
+ while nr > 0
85
+ n = partial(src, dst, nr, _select_args) or
86
+ raise EOFError, "end of file reached"
87
+ nr -= n
109
88
  end
89
+ len
90
+ end
110
91
 
111
- # returns an array suitable for splat-ing to IO.select for blocking I/O
112
- def Splice.selectable(src, dst)
113
- rv = []
114
- src.stat.pipe? or rv[0] = [ src ]
115
- dst.stat.pipe? or rv[1] = [ dst ]
116
- rv
117
- end
92
+ # splice up to +len+ bytes from +src+ to +dst+.
93
+ # Either +dst+ or +src+ must be a pipe. +dst+ and +src+
94
+ # may BOTH be pipes in Linux 2.6.31 or later.
95
+ # Returns the number of bytes actually spliced.
96
+ # Like IO#readpartial, this never returns Errno::EAGAIN
97
+ # The +_select_args+ parameter is reserved for internal use and
98
+ # may be removed in future versions. Do not write code that
99
+ # depends on +_select_args+.
100
+ def self.partial(src, dst, len, _select_args = selectable(src, dst))
101
+ begin
102
+ rv = IO.trysplice(src, nil, dst, nil, len, F_MOVE)
103
+ end while rv == :EAGAIN and IO.select(*_select_args)
104
+ rv
105
+ end
118
106
 
107
+ # returns an array suitable for splat-ing to IO.select for blocking I/O
108
+ def self.selectable(src, dst)
109
+ rv = []
110
+ src.stat.pipe? or rv[0] = [ src ]
111
+ dst.stat.pipe? or rv[1] = [ dst ]
112
+ rv
119
113
  end
120
114
  end
data/pkg.mk ADDED
@@ -0,0 +1,168 @@
1
+ RUBY = ruby
2
+ RAKE = rake
3
+ RSYNC = rsync
4
+ WRONGDOC = wrongdoc
5
+
6
+ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
7
+ @./GIT-VERSION-GEN
8
+ -include GIT-VERSION-FILE
9
+ -include local.mk
10
+ DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
11
+ RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
12
+ RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
13
+ lib := lib
14
+
15
+ ifeq ($(shell test -f script/isolate_for_tests && echo t),t)
16
+ isolate_libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/isolate.mk
17
+ $(isolate_libs): script/isolate_for_tests
18
+ @$(RUBY) script/isolate_for_tests
19
+ -include $(isolate_libs)
20
+ lib := $(lib):$(ISOLATE_LIBS)
21
+ endif
22
+
23
+ ext := $(firstword $(wildcard ext/*))
24
+ ifneq ($(ext),)
25
+ ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
26
+ ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
27
+ ext_src := $(wildcard $(ext)/*.c $(ext_h))
28
+ ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
29
+ ext_d := $(ext_pfx)/$(ext)/.d
30
+ $(ext)/extconf.rb: $(wildcard $(ext)/*.h)
31
+ @>> $@
32
+ $(ext_d):
33
+ @mkdir -p $(@D)
34
+ @> $@
35
+ $(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
36
+ install -m 644 $< $@
37
+ $(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
38
+ $(RM) -f $(@D)/*.o
39
+ cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb
40
+ ext_sfx := _ext.$(DLEXT)
41
+ ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
42
+ $(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
43
+ @echo $^ == $@
44
+ $(MAKE) -C $(@D)
45
+ lib := $(lib):$(ext_pfx)/$(ext)
46
+ build: $(ext_dl)
47
+ endif
48
+
49
+ pkg_extra := GIT-VERSION-FILE NEWS ChangeLog LATEST
50
+ ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
51
+ $(WRONGDOC) prepare
52
+
53
+ manifest:
54
+ $(RM) .manifest
55
+ $(MAKE) .manifest
56
+
57
+ .manifest: ChangeLog
58
+ (git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
59
+ LC_ALL=C sort > $@+
60
+ cmp $@+ $@ || mv $@+ $@
61
+ $(RM) $@+
62
+
63
+ doc:: .document .wrongdoc.yml
64
+ find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
65
+ -find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
66
+ $(RM) -r doc
67
+ $(WRONGDOC) all
68
+ install -m644 COPYING doc/COPYING
69
+ install -m644 $(shell grep '^[A-Z]' .document) doc/
70
+
71
+ ifneq ($(VERSION),)
72
+ pkggem := pkg/$(rfpackage)-$(VERSION).gem
73
+ pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
74
+ release_notes := release_notes-$(VERSION)
75
+ release_changes := release_changes-$(VERSION)
76
+
77
+ release-notes: $(release_notes)
78
+ release-changes: $(release_changes)
79
+ $(release_changes):
80
+ $(WRONGDOC) release_changes > $@+
81
+ $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
82
+ $(release_notes):
83
+ $(WRONGDOC) release_notes > $@+
84
+ $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
85
+
86
+ # ensures we're actually on the tagged $(VERSION), only used for release
87
+ verify:
88
+ test x"$(shell umask)" = x0022
89
+ git rev-parse --verify refs/tags/v$(VERSION)^{}
90
+ git diff-index --quiet HEAD^0
91
+ test $$(git rev-parse --verify HEAD^0) = \
92
+ $$(git rev-parse --verify refs/tags/v$(VERSION)^{})
93
+
94
+ fix-perms:
95
+ -git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
96
+ -git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
97
+
98
+ gem: $(pkggem)
99
+
100
+ install-gem: $(pkggem)
101
+ gem install $(CURDIR)/$<
102
+
103
+ $(pkggem): manifest fix-perms
104
+ gem build $(rfpackage).gemspec
105
+ mkdir -p pkg
106
+ mv $(@F) $@
107
+
108
+ $(pkgtgz): distdir = $(basename $@)
109
+ $(pkgtgz): HEAD = v$(VERSION)
110
+ $(pkgtgz): manifest fix-perms
111
+ @test -n "$(distdir)"
112
+ $(RM) -r $(distdir)
113
+ mkdir -p $(distdir)
114
+ tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
115
+ cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
116
+ mv $@+ $@
117
+
118
+ package: $(pkgtgz) $(pkggem)
119
+
120
+ test-release:: verify package $(release_notes) $(release_changes)
121
+ # make tgz release on RubyForge
122
+ @echo rubyforge add_release -f \
123
+ -n $(release_notes) -a $(release_changes) \
124
+ $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
125
+ @echo gem push $(pkggem)
126
+ @echo rubyforge add_file \
127
+ $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
128
+ release:: verify package $(release_notes) $(release_changes)
129
+ # make tgz release on RubyForge
130
+ rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
131
+ $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
132
+ # push gem to RubyGems.org
133
+ gem push $(pkggem)
134
+ # in case of gem downloads from RubyForge releases page
135
+ rubyforge add_file \
136
+ $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
137
+ else
138
+ gem install-gem: GIT-VERSION-FILE
139
+ $(MAKE) $@ VERSION=$(GIT_VERSION)
140
+ endif
141
+
142
+ all:: test
143
+ test_units := $(wildcard test/test_*.rb)
144
+ test: test-unit
145
+ test-unit: $(test_units)
146
+ $(test_units): build
147
+ $(RUBY) -I $(lib) $@
148
+
149
+ # this requires GNU coreutils variants
150
+ ifneq ($(RSYNC_DEST),)
151
+ publish_doc:
152
+ -git set-file-times
153
+ $(MAKE) doc
154
+ find doc/images -type f | \
155
+ TZ=UTC xargs touch -d '1970-01-01 00:00:06' doc/rdoc.css
156
+ $(MAKE) doc_gz
157
+ $(RSYNC) -av doc/ $(RSYNC_DEST)/
158
+ git ls-files | xargs touch
159
+ endif
160
+
161
+ # Create gzip variants of the same timestamp as the original so nginx
162
+ # "gzip_static on" can serve the gzipped versions directly.
163
+ doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
164
+ doc_gz:
165
+ for i in $(docs); do \
166
+ gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
167
+
168
+ .PHONY: all .FORCE-GIT-VERSION-FILE doc test $(test_units) manifest
@@ -7,48 +7,6 @@ require 'timeout'
7
7
  $-w = true
8
8
  require 'io/splice'
9
9
 
10
- # unused_port provides an unused port on +addr+ usable for TCP that is
11
- # guaranteed to be unused across all unicorn builds on that system. It
12
- # prevents race conditions by using a lock file other unicorn builds
13
- # will see. This is required if you perform several builds in parallel
14
- # with a continuous integration system or run tests in parallel via
15
- # gmake. This is NOT guaranteed to be race-free if you run other
16
- # processes that bind to random ports for testing (but the window
17
- # for a race condition is very small).
18
- def unused_port(addr = '127.0.0.1')
19
- retries = 100
20
- base = 5000
21
- port = sock = nil
22
- begin
23
- begin
24
- port = base + rand(32768 - base)
25
- while port == 8080
26
- port = base + rand(32768 - base)
27
- end
28
-
29
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
30
- sock.bind(Socket.pack_sockaddr_in(port, addr))
31
- sock.listen(5)
32
- rescue Errno::EADDRINUSE, Errno::EACCES
33
- sock.close rescue nil
34
- retry if (retries -= 1) >= 0
35
- end
36
-
37
- # since we'll end up closing the random port we just got, there's a race
38
- # condition could allow the random port we just chose to reselect itself
39
- # when running tests in parallel with gmake. Create a lock file while
40
- # we have the port here to ensure that does not happen .
41
- lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock"
42
- lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
43
- at_exit { File.unlink(lock_path) rescue nil }
44
- rescue Errno::EEXIST
45
- sock.close rescue nil
46
- retry
47
- end
48
- sock.close rescue nil
49
- port
50
- end
51
-
52
10
  class Test_IO_Splice < Test::Unit::TestCase
53
11
 
54
12
  def test_splice
@@ -83,6 +41,38 @@ class Test_IO_Splice < Test::Unit::TestCase
83
41
  assert_equal str, rd.sysread(size)
84
42
  end
85
43
 
44
+ def test_splice_io_noflags
45
+ str = 'abcde'
46
+ size = 5
47
+ rd, wr = IO.pipe
48
+ tmp = Tempfile.new('ruby_io_splice')
49
+
50
+ assert_nothing_raised {
51
+ tmp.syswrite(str)
52
+ tmp.sysseek(0)
53
+ }
54
+
55
+ nr = IO.splice(tmp, nil, wr, nil, size)
56
+ assert_equal size, nr
57
+ assert_equal str, rd.sysread(size)
58
+ end
59
+
60
+ def test_trysplice_io_noflags
61
+ str = 'abcde'
62
+ size = 5
63
+ rd, wr = IO.pipe
64
+ tmp = Tempfile.new('ruby_io_splice')
65
+
66
+ assert_nothing_raised {
67
+ tmp.syswrite(str)
68
+ tmp.sysseek(0)
69
+ }
70
+
71
+ nr = IO.trysplice(tmp, nil, wr, nil, size)
72
+ assert_equal size, nr
73
+ assert_equal str, rd.sysread(size)
74
+ end
75
+
86
76
  def test_splice_io_ish
87
77
  str = 'abcde'
88
78
  size = 5
@@ -141,6 +131,20 @@ class Test_IO_Splice < Test::Unit::TestCase
141
131
  }
142
132
  end
143
133
 
134
+ def test_trysplice_nonblock
135
+ rd, wr = IO.pipe
136
+ tmp = Tempfile.new('ruby_io_splice')
137
+ assert_equal :EAGAIN,
138
+ IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
139
+ end
140
+
141
+ def test_trysplice_nonblock_noargs
142
+ rd, wr = IO.pipe
143
+ tmp = Tempfile.new('ruby_io_splice')
144
+ assert_equal :EAGAIN, IO.trysplice(rd, nil, tmp, 0, 5)
145
+ assert_equal :EAGAIN, IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_MORE)
146
+ end
147
+
144
148
  def test_splice_eof
145
149
  rd, wr = IO.pipe
146
150
  tmp = Tempfile.new('ruby_io_splice')
@@ -154,9 +158,20 @@ class Test_IO_Splice < Test::Unit::TestCase
154
158
  }
155
159
  end
156
160
 
161
+ def test_trysplice_eof
162
+ rd, wr = IO.pipe
163
+ tmp = Tempfile.new('ruby_io_splice')
164
+ wr.syswrite 'abc'
165
+ wr.close
166
+
167
+ nr = IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
168
+ assert_equal 3, nr
169
+ assert_nil IO.trysplice(rd, nil, tmp, 0, 5, IO::Splice::F_NONBLOCK)
170
+ end
171
+
157
172
  def test_splice_nonblock_socket
158
- port = unused_port
159
- server = TCPServer.new('127.0.0.1', port)
173
+ server = TCPServer.new('127.0.0.1', 0)
174
+ port = server.addr[1]
160
175
  rp, wp = IO.pipe
161
176
  rs = TCPSocket.new('127.0.0.1', port)
162
177
  rs.nonblock = true
@@ -178,6 +193,19 @@ class Test_IO_Splice < Test::Unit::TestCase
178
193
  assert_equal str, rda.sysread(5)
179
194
  end
180
195
 
196
+ def test_trytee
197
+ str = 'abcde'
198
+ size = 5
199
+ rda, wra = IO.pipe
200
+ rdb, wrb = IO.pipe
201
+
202
+ assert_nothing_raised { wra.syswrite(str) }
203
+ nr = IO.trytee(rda, wrb, size, 0)
204
+ assert_equal 5, nr
205
+ assert_equal str, rdb.sysread(5)
206
+ assert_equal str, rda.sysread(5)
207
+ end
208
+
181
209
  def test_tee_eof
182
210
  rda, wra = IO.pipe
183
211
  rdb, wrb = IO.pipe
@@ -185,6 +213,13 @@ class Test_IO_Splice < Test::Unit::TestCase
185
213
  assert_raises(EOFError) { IO.tee(rda.fileno, wrb.fileno, 4096, 0) }
186
214
  end
187
215
 
216
+ def test_trytee_eof
217
+ rda, wra = IO.pipe
218
+ rdb, wrb = IO.pipe
219
+ wra.close
220
+ assert_nil IO.trytee(rda, wrb, 4096)
221
+ end
222
+
188
223
  def test_tee_nonblock
189
224
  rda, wra = IO.pipe
190
225
  rdb, wrb = IO.pipe
@@ -193,6 +228,12 @@ class Test_IO_Splice < Test::Unit::TestCase
193
228
  }
194
229
  end
195
230
 
231
+ def test_trytee_nonblock
232
+ rda, wra = IO.pipe
233
+ rdb, wrb = IO.pipe
234
+ assert_equal :EAGAIN, IO.trytee(rda, wrb, 4096)
235
+ end
236
+
196
237
  def test_tee_io
197
238
  str = 'abcde'
198
239
  size = 5
@@ -214,6 +255,14 @@ class Test_IO_Splice < Test::Unit::TestCase
214
255
  assert_equal data.join(''), r.readpartial(16384)
215
256
  end
216
257
 
258
+ def test_vmsplice_noflags
259
+ data = %w(hello world how are you today)
260
+ r, w = IO.pipe
261
+ n = IO.vmsplice(w, data)
262
+ assert_equal data.join('').size, n
263
+ assert_equal data.join(''), r.readpartial(16384)
264
+ end
265
+
217
266
  def test_vmsplice_string
218
267
  r, w = IO.pipe
219
268
  assert_equal 5, IO.vmsplice(w, 'hello', 0)
@@ -344,8 +393,8 @@ class Test_IO_Splice < Test::Unit::TestCase
344
393
  end
345
394
 
346
395
  def test_copy_stream_nonblock_src
347
- port = unused_port
348
- server = TCPServer.new('127.0.0.1', port)
396
+ server = TCPServer.new('127.0.0.1', 0)
397
+ port = server.addr[1]
349
398
  rp, wp = IO.pipe
350
399
  rs = TCPSocket.new('127.0.0.1', port)
351
400
  rs.nonblock = true
@@ -359,8 +408,8 @@ class Test_IO_Splice < Test::Unit::TestCase
359
408
  end
360
409
 
361
410
  def test_copy_stream_nonblock_dst
362
- port = unused_port
363
- server = TCPServer.new('127.0.0.1', port)
411
+ server = TCPServer.new('127.0.0.1', 0)
412
+ port = server.addr[1]
364
413
  rp, wp = IO.pipe
365
414
  rs = TCPSocket.new('127.0.0.1', port)
366
415
  rs.nonblock = true
@@ -395,10 +444,10 @@ class Test_IO_Splice < Test::Unit::TestCase
395
444
 
396
445
  def test_pipe_size
397
446
  r, w = IO.pipe
398
- assert Integer, r.pipe_size
447
+ assert_kind_of Integer, r.pipe_size
399
448
  assert(r.pipe_size >= 512)
400
449
  assert_nothing_raised { w.pipe_size = 8192 }
401
- assert 8192, r.pipe_size
450
+ assert_equal 8192, r.pipe_size
402
451
 
403
452
  w.write('*' * 4097)
404
453
  assert_raises(Errno::EBUSY) { r.pipe_size = 4096 }