io_splice 2.2.0 → 2.2.0.18.g3025

Sign up to get free protection for your applications and to get access to all the features.
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 }