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/.document +1 -0
- data/.gitignore +2 -0
- data/.wrongdoc.yml +5 -0
- data/GNUmakefile +7 -193
- data/README +2 -2
- data/Rakefile +20 -106
- data/ext/io_splice/io_splice_ext.c +129 -36
- data/io_splice.gemspec +12 -24
- data/lib/io/splice.rb +95 -101
- data/pkg.mk +168 -0
- data/test/test_io_splice.rb +99 -50
- metadata +37 -13
data/.document
CHANGED
data/.gitignore
CHANGED
data/.wrongdoc.yml
ADDED
data/GNUmakefile
CHANGED
@@ -1,200 +1,14 @@
|
|
1
|
-
# use GNU Make to run tests in parallel, and without depending on RubyGems
|
2
1
|
all::
|
3
|
-
RUBY = ruby
|
4
|
-
RAKE = rake
|
5
|
-
GIT_URL = git://git.bogomips.org/ruby_io_splice.git
|
6
|
-
RSYNC = rsync
|
7
2
|
RCOV = rcov
|
8
|
-
|
9
|
-
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
10
|
-
@./GIT-VERSION-GEN
|
11
|
-
-include GIT-VERSION-FILE
|
12
|
-
-include local.mk
|
13
|
-
ifeq ($(DLEXT),) # "so" for Linux
|
14
|
-
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
|
15
|
-
endif
|
16
|
-
ifeq ($(RUBY_VERSION),)
|
17
|
-
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
18
|
-
endif
|
19
|
-
|
20
|
-
install: $(bins)
|
21
|
-
$(prep_setup_rb)
|
22
|
-
$(RM) -r .install-tmp
|
23
|
-
mkdir .install-tmp
|
24
|
-
cp -p bin/* .install-tmp
|
25
|
-
$(RUBY) setup.rb all
|
26
|
-
$(RM) $^
|
27
|
-
mv .install-tmp/* bin/
|
28
|
-
$(RM) -r .install-tmp
|
29
|
-
$(prep_setup_rb)
|
30
|
-
|
31
|
-
setup_rb_files := .config InstalledFiles
|
32
|
-
prep_setup_rb := @-$(RM) $(setup_rb_files);$(MAKE) -C $(ext) clean
|
33
|
-
|
34
|
-
clean:
|
35
|
-
-$(MAKE) -C ext/io_splice clean
|
36
|
-
$(RM) $(setup_rb_files) ext/io_splice/Makefile
|
37
|
-
|
38
|
-
pkg_extra := GIT-VERSION-FILE NEWS ChangeLog
|
39
|
-
manifest: $(pkg_extra)
|
40
|
-
$(RM) .manifest
|
41
|
-
$(MAKE) .manifest
|
42
|
-
|
43
|
-
.manifest:
|
44
|
-
(git ls-files && \
|
45
|
-
for i in $@ $(pkg_extra); \
|
46
|
-
do echo $$i; done) | LC_ALL=C sort > $@+
|
47
|
-
cmp $@+ $@ || mv $@+ $@
|
48
|
-
$(RM) $@+
|
49
|
-
|
50
|
-
NEWS: GIT-VERSION-FILE
|
51
|
-
$(RAKE) -s news_rdoc > $@+
|
52
|
-
mv $@+ $@
|
53
|
-
|
54
|
-
SINCE = 1.0.0
|
55
|
-
ChangeLog: LOG_VERSION = \
|
56
|
-
$(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
|
57
|
-
echo $(GIT_VERSION) || git describe)
|
58
|
-
ifneq ($(SINCE),)
|
59
|
-
ChangeLog: log_range = v$(SINCE)..$(LOG_VERSION)
|
60
|
-
endif
|
61
|
-
ChangeLog: GIT-VERSION-FILE
|
62
|
-
@echo "ChangeLog from $(GIT_URL) ($(log_range))" > $@+
|
63
|
-
@echo >> $@+
|
64
|
-
git log $(log_range) | sed -e 's/^/ /' >> $@+
|
65
|
-
mv $@+ $@
|
66
|
-
|
67
|
-
news_atom := http://bogomips.org/ruby_io_splice/NEWS.atom.xml
|
68
|
-
cgit_atom := http://git.bogomips.org/cgit/ruby_io_splice.git/atom/?h=master
|
69
|
-
atom = <link rel="alternate" title="Atom feed" href="$(1)" \
|
70
|
-
type="application/atom+xml"/>
|
71
|
-
|
72
|
-
# using rdoc 2.5.x + workaround patch here:
|
73
|
-
# rubyforge.org/tracker/index.php?func=detail&aid=28230&group_id=627&atid=2472
|
74
|
-
doc: .document NEWS ChangeLog
|
75
|
-
rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
|
76
|
-
install -m644 COPYING doc/COPYING
|
77
|
-
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
78
|
-
cd doc && for i in $(base_bins); do \
|
79
|
-
html=$$(echo $$i | sed 's/\.rb/_rb/')_1.html; \
|
80
|
-
sed -e '/"documentation">/r man1/'$$i'.1.html' \
|
81
|
-
< $$html > tmp && mv tmp $$html; done
|
82
|
-
$(RUBY) -i -p -e \
|
83
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
|
84
|
-
doc/ChangeLog.html
|
85
|
-
$(RUBY) -i -p -e \
|
86
|
-
'$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
|
87
|
-
doc/NEWS.html doc/README.html
|
88
|
-
$(RAKE) -s news_atom > doc/NEWS.atom.xml
|
89
|
-
cd doc && ln README.html tmp && mv tmp index.html
|
90
|
-
|
91
|
-
latest: NEWS
|
92
|
-
@awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' $<
|
93
|
-
|
94
|
-
# publishes docs to http://bogomips.org/ruby_io_splice/,
|
95
|
-
publish_doc:
|
96
|
-
-git set-file-times
|
97
|
-
$(RM) -r doc ChangeLog NEWS
|
98
|
-
$(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
|
99
|
-
awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
|
100
|
-
NEWS > doc/LATEST
|
101
|
-
find doc/images doc/js -type f | \
|
102
|
-
TZ=UTC xargs touch -d '1970-01-01 00:00:01' doc/rdoc.css
|
103
|
-
$(MAKE) doc_gz
|
104
|
-
chmod 644 $$(find doc -type f)
|
105
|
-
$(RSYNC) -av doc/ bogomips.org:/srv/bogomips/ruby_io_splice/
|
106
|
-
git ls-files | xargs touch
|
107
|
-
|
108
|
-
# Create gzip variants of the same timestamp as the original so nginx
|
109
|
-
# "gzip_static on" can serve the gzipped versions directly.
|
110
|
-
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
111
|
-
doc_gz:
|
112
|
-
touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
|
113
|
-
for i in $(docs); do \
|
114
|
-
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
115
|
-
|
116
|
-
ifneq ($(VERSION),)
|
3
|
+
RSYNC_DEST := bogomips.org:/srv/bogomips/ruby_io_splice
|
117
4
|
rfproject := qrp
|
118
5
|
rfpackage := io_splice
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
release-notes: $(release_notes)
|
125
|
-
release-changes: $(release_changes)
|
126
|
-
$(release_changes):
|
127
|
-
$(RAKE) -s release_changes > $@+
|
128
|
-
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
129
|
-
$(release_notes):
|
130
|
-
GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
|
131
|
-
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
132
|
-
|
133
|
-
# ensures we're actually on the tagged $(VERSION), only used for release
|
134
|
-
verify:
|
135
|
-
test x"$(shell umask)" = x0022
|
136
|
-
git rev-parse --verify refs/tags/v$(VERSION)^{}
|
137
|
-
git diff-index --quiet HEAD^0
|
138
|
-
test `git rev-parse --verify HEAD^0` = \
|
139
|
-
`git rev-parse --verify refs/tags/v$(VERSION)^{}`
|
140
|
-
|
141
|
-
fix-perms:
|
142
|
-
-git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
|
143
|
-
-git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
|
144
|
-
|
145
|
-
gem: $(pkggem)
|
146
|
-
|
147
|
-
install-gem: $(pkggem)
|
148
|
-
gem install $(CURDIR)/$<
|
149
|
-
|
150
|
-
$(pkggem): manifest fix-perms
|
151
|
-
gem build $(rfpackage).gemspec
|
152
|
-
mkdir -p pkg
|
153
|
-
mv $(@F) $@
|
154
|
-
|
155
|
-
$(pkgtgz): distdir = $(basename $@)
|
156
|
-
$(pkgtgz): HEAD = v$(VERSION)
|
157
|
-
$(pkgtgz): manifest fix-perms
|
158
|
-
@test -n "$(distdir)"
|
159
|
-
$(RM) -r $(distdir)
|
160
|
-
mkdir -p $(distdir)
|
161
|
-
tar c `cat .manifest` | (cd $(distdir) && tar x)
|
162
|
-
cd pkg && tar c $(basename $(@F)) | gzip -9 > $(@F)+
|
163
|
-
mv $@+ $@
|
164
|
-
|
165
|
-
package: $(pkgtgz) $(pkggem)
|
166
|
-
|
167
|
-
test-release: verify package $(release_notes) $(release_changes)
|
168
|
-
release: verify package $(release_notes) $(release_changes)
|
169
|
-
# make tgz release on RubyForge
|
170
|
-
rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
|
171
|
-
$(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
|
172
|
-
# push gem to Gemcutter
|
173
|
-
gem push $(pkggem)
|
174
|
-
# in case of gem downloads from RubyForge releases page
|
175
|
-
-rubyforge add_file \
|
176
|
-
$(rfproject) $(rfpackage) $(VERSION) $(pkggem)
|
177
|
-
else
|
178
|
-
gem install-gem: GIT-VERSION-FILE
|
179
|
-
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
6
|
+
include pkg.mk
|
7
|
+
ifneq ($(VERSION),)
|
8
|
+
release::
|
9
|
+
$(RAKE) raa_update VERSION=$(VERSION)
|
10
|
+
$(RAKE) publish_news VERSION=$(VERSION)
|
180
11
|
endif
|
181
|
-
|
182
|
-
ext := ext/io_splice/io_splice_ext.$(DLEXT)
|
183
|
-
ext/io_splice/Makefile: ext/io_splice/extconf.rb
|
184
|
-
cd $(@D) && $(RUBY) extconf.rb
|
185
|
-
$(ext): $(wildcard $(addprefix ext/io_splice/,*.c *.h)) ext/io_splice/Makefile
|
186
|
-
$(MAKE) -C $(@D)
|
187
|
-
|
188
|
-
all:: test
|
189
|
-
|
190
|
-
build: $(ext)
|
191
|
-
test: test-unit
|
192
12
|
rcov: build
|
193
13
|
$(RCOV) -I lib:ext/io_splice $(test_unit)
|
194
|
-
|
195
|
-
test_unit := $(wildcard test/test_*.rb)
|
196
|
-
$(test_unit): build
|
197
|
-
$(RUBY) -I lib:ext/io_splice $@ $(TEST_UNIT_OPTS)
|
198
|
-
test-unit: $(test_unit)
|
199
|
-
|
200
|
-
.PHONY: .FORCE-GIT-VERSION-FILE doc manifest man test $(test_unit)
|
14
|
+
.PHONY: rcov
|
data/README
CHANGED
@@ -66,13 +66,13 @@ standardized and available in non-Linux kernels some day.
|
|
66
66
|
|
67
67
|
You can get the latest source via git from the following locations:
|
68
68
|
|
69
|
-
git://
|
69
|
+
git://bogomips.org/ruby_io_splice.git
|
70
70
|
git://repo.or.cz/ruby_io_splice.git (mirror)
|
71
71
|
|
72
72
|
You may browse the code from the web and download the latest snapshot
|
73
73
|
tarballs here:
|
74
74
|
|
75
|
-
* http://
|
75
|
+
* http://bogomips.org/cgit/ruby_io_splice.git (cgit)
|
76
76
|
* http://repo.or.cz/w/ruby_io_splice.git (gitweb)
|
77
77
|
|
78
78
|
Inline patches (from "git format-patch") to the mailing list are
|
data/Rakefile
CHANGED
@@ -1,112 +1,26 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
require 'wrongdoc'
|
3
|
+
cgit_url = Wrongdoc.config[:cgit_url]
|
4
|
+
git_url = Wrongdoc.config[:git_url]
|
2
5
|
|
3
|
-
|
4
|
-
|
5
|
-
def tags
|
6
|
-
timefmt = '%Y-%m-%dT%H:%M:%SZ'
|
7
|
-
@tags ||= `git tag -l`.split(/\n/).map do |tag|
|
8
|
-
if %r{\Av[\d\.]+\z} =~ tag
|
9
|
-
header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
|
10
|
-
header = header.split(/\n/)
|
11
|
-
tagger = header.grep(/\Atagger /).first
|
12
|
-
body ||= "initial"
|
13
|
-
{
|
14
|
-
:time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
|
15
|
-
:tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
|
16
|
-
:tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
|
17
|
-
:id => `git rev-parse refs/tags/#{tag}`.chomp!,
|
18
|
-
:tag => tag,
|
19
|
-
:subject => subject,
|
20
|
-
:body => body,
|
21
|
-
}
|
22
|
-
end
|
23
|
-
end.compact.sort { |a,b| b[:time] <=> a[:time] }
|
24
|
-
end
|
25
|
-
|
26
|
-
cgit_url = "http://git.bogomips.org/cgit/ruby_io_splice.git"
|
27
|
-
git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/ruby_io_splice.git'
|
28
|
-
web_url = "http://bogomips.org/ruby_io_splice/"
|
29
|
-
|
30
|
-
desc 'prints news as an Atom feed'
|
31
|
-
task :news_atom do
|
32
|
-
require 'nokogiri'
|
33
|
-
new_tags = tags[0,10]
|
34
|
-
puts(Nokogiri::XML::Builder.new do
|
35
|
-
feed :xmlns => "http://www.w3.org/2005/Atom" do
|
36
|
-
id! "#{web_url}NEWS.atom.xml"
|
37
|
-
title "Ruby io_splice news"
|
38
|
-
subtitle "splice and tee Linux syscalls from Ruby"
|
39
|
-
link! :rel => "alternate", :type => "text/html",
|
40
|
-
:href => "#{web_url}NEWS.html"
|
41
|
-
updated(new_tags.empty? ? "1970-01-01T00:00:00Z" : new_tags.first[:time])
|
42
|
-
new_tags.each do |tag|
|
43
|
-
entry do
|
44
|
-
title tag[:subject]
|
45
|
-
updated tag[:time]
|
46
|
-
published tag[:time]
|
47
|
-
author {
|
48
|
-
name tag[:tagger_name]
|
49
|
-
email tag[:tagger_email]
|
50
|
-
}
|
51
|
-
url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
|
52
|
-
link! :rel => "alternate", :type => "text/html", :href =>url
|
53
|
-
id! url
|
54
|
-
message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
|
55
|
-
content({:type =>:text}, message_only)
|
56
|
-
content(:type =>:xhtml) { pre tag[:body] }
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end.to_xml)
|
61
|
-
end
|
62
|
-
|
63
|
-
desc 'prints RDoc-formatted news'
|
64
|
-
task :news_rdoc do
|
65
|
-
tags.each do |tag|
|
66
|
-
time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
|
67
|
-
puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
|
68
|
-
puts ""
|
69
|
-
|
70
|
-
body = tag[:body]
|
71
|
-
puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
|
72
|
-
puts ""
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
desc "print release changelog for Rubyforge"
|
77
|
-
task :release_changes do
|
78
|
-
version = ENV['VERSION'] or abort "VERSION= needed"
|
79
|
-
version = "v#{version}"
|
80
|
-
vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
|
81
|
-
prev = vtags[vtags.index(version) - 1]
|
82
|
-
if prev
|
83
|
-
system('git', 'diff', '--stat', prev, version) or abort $?
|
84
|
-
puts ""
|
85
|
-
system('git', 'log', "#{prev}..#{version}") or abort $?
|
86
|
-
else
|
87
|
-
system('git', 'log', version) or abort $?
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
desc "print release notes for Rubyforge"
|
92
|
-
task :release_notes do
|
93
|
-
spec = Gem::Specification.load('io_splice.gemspec')
|
94
|
-
puts spec.description.strip
|
95
|
-
puts ""
|
96
|
-
puts "* #{spec.homepage}"
|
97
|
-
puts "* #{spec.email}"
|
98
|
-
puts "* #{git_url}"
|
99
|
-
|
100
|
-
_, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
|
101
|
-
print "\nChanges:\n\n"
|
102
|
-
puts body
|
103
|
-
end
|
104
|
-
|
105
|
-
desc "read news article from STDIN and post to rubyforge"
|
6
|
+
desc "post news article to rubyforge"
|
106
7
|
task :publish_news do
|
107
8
|
require 'rubyforge'
|
108
|
-
|
109
|
-
|
9
|
+
spec = Gem::Specification.load('io_splice.gemspec')
|
10
|
+
tmp = Tempfile.new('rf-news')
|
11
|
+
_, subject, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
|
12
|
+
tmp.puts subject
|
13
|
+
tmp.puts
|
14
|
+
tmp.puts spec.description.strip
|
15
|
+
tmp.puts ""
|
16
|
+
tmp.puts "* #{spec.homepage}"
|
17
|
+
tmp.puts "* #{spec.email}"
|
18
|
+
tmp.puts "* #{git_url}"
|
19
|
+
tmp.print "\nChanges:\n\n"
|
20
|
+
tmp.puts body
|
21
|
+
tmp.flush
|
22
|
+
system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
|
23
|
+
msg = File.readlines(tmp.path)
|
110
24
|
subject = msg.shift
|
111
25
|
blank = msg.shift
|
112
26
|
blank == "\n" or abort "no newline after subject!"
|
@@ -144,7 +58,7 @@ task :raa_update do
|
|
144
58
|
:category_minor => 'System',
|
145
59
|
:url => s.homepage,
|
146
60
|
:download => 'http://rubyforge.org/frs/?group_id=5626',
|
147
|
-
:license =>
|
61
|
+
:license => "LGPL",
|
148
62
|
:description_style => 'Plain',
|
149
63
|
:description => desc,
|
150
64
|
:pass => password,
|
@@ -12,6 +12,8 @@
|
|
12
12
|
#include <alloca.h>
|
13
13
|
#include <sys/utsname.h>
|
14
14
|
|
15
|
+
static VALUE sym_EAGAIN;
|
16
|
+
|
15
17
|
#ifndef F_LINUX_SPECIFIC_BASE
|
16
18
|
# define F_LINUX_SPECIFIC_BASE 1024
|
17
19
|
#endif
|
@@ -88,8 +90,14 @@ rb_thread_blocking_region(
|
|
88
90
|
# define RARRAY_LEN(s) (RARRAY(s)->len)
|
89
91
|
#endif
|
90
92
|
|
93
|
+
static VALUE io_run(rb_blocking_function_t *fn, void *data)
|
94
|
+
{
|
95
|
+
return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0);
|
96
|
+
}
|
97
|
+
|
91
98
|
/*
|
92
99
|
* Releases GVL only iff blocking I/O is used.
|
100
|
+
* Only use this if all file descriptors in data are pipes.
|
93
101
|
* We'll trust programmers who use non-blocking I/O explicitly to
|
94
102
|
* want the fastest possible performance without resorting to threads,
|
95
103
|
* so releasing and them immediately reacquiring the GVL would be
|
@@ -99,7 +107,7 @@ static VALUE nb_io_run(rb_blocking_function_t *fn, void *data, unsigned flags)
|
|
99
107
|
{
|
100
108
|
if (flags & SPLICE_F_NONBLOCK)
|
101
109
|
return fn(data);
|
102
|
-
return
|
110
|
+
return io_run(fn, data);
|
103
111
|
}
|
104
112
|
|
105
113
|
struct splice_args {
|
@@ -119,8 +127,28 @@ static VALUE nogvl_splice(void *ptr)
|
|
119
127
|
a->len, a->flags);
|
120
128
|
}
|
121
129
|
|
130
|
+
static long do_splice(int argc, VALUE *argv, unsigned dflags)
|
131
|
+
{
|
132
|
+
off_t i, o;
|
133
|
+
VALUE fd_in, off_in, fd_out, off_out, len, flags;
|
134
|
+
struct splice_args a;
|
135
|
+
|
136
|
+
rb_scan_args(argc, argv, "51",
|
137
|
+
&fd_in, &off_in, &fd_out, &off_out, &len, &flags);
|
138
|
+
|
139
|
+
a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i);
|
140
|
+
a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o);
|
141
|
+
a.fd_in = my_fileno(fd_in);
|
142
|
+
a.fd_out = my_fileno(fd_out);
|
143
|
+
a.len = (size_t)NUM2ULONG(len);
|
144
|
+
a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags;
|
145
|
+
|
146
|
+
return (long)io_run(nogvl_splice, &a);
|
147
|
+
}
|
148
|
+
|
122
149
|
/*
|
123
150
|
* call-seq:
|
151
|
+
* IO.splice(fd_in, off_in, fd_out, off_out, len) => integer
|
124
152
|
* IO.splice(fd_in, off_in, fd_out, off_out, len, flags) => integer
|
125
153
|
*
|
126
154
|
* Splice +len+ bytes from/to a pipe. Either +fd_in+ or +fd_out+
|
@@ -130,6 +158,7 @@ static VALUE nogvl_splice(void *ptr)
|
|
130
158
|
* +off_in+ and +off_out+ if non-nil may be used to
|
131
159
|
* specify an offset for the non-pipe file descriptor.
|
132
160
|
*
|
161
|
+
* +flags+ defaults to zero if unspecified.
|
133
162
|
* +flags+ may be a bitmask of the following flags:
|
134
163
|
*
|
135
164
|
* IO::Splice::F_MOVE, IO::Splice::F_NONBLOCK, IO::Splice::F_MORE
|
@@ -152,26 +181,17 @@ static VALUE nogvl_splice(void *ptr)
|
|
152
181
|
* into account userspace buffering done by Ruby or stdio. It is
|
153
182
|
* also not subject to encoding/decoding filters under Ruby 1.9.
|
154
183
|
*
|
184
|
+
* Consider using IO.trysplice if you are using non-blocking I/O on
|
185
|
+
* both descriptors as it avoids the cost of raising common Errno::EAGAIN
|
186
|
+
* exceptions.
|
187
|
+
*
|
155
188
|
* See manpage for full documentation:
|
156
189
|
* http://kernel.org/doc/man-pages/online/pages/man2/splice.2.html
|
157
190
|
*/
|
158
|
-
static VALUE my_splice(VALUE self
|
159
|
-
VALUE fd_in, VALUE off_in,
|
160
|
-
VALUE fd_out, VALUE off_out,
|
161
|
-
VALUE len, VALUE flags)
|
191
|
+
static VALUE my_splice(int argc, VALUE *argv, VALUE self)
|
162
192
|
{
|
163
|
-
|
164
|
-
|
165
|
-
struct splice_args a = {
|
166
|
-
.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i),
|
167
|
-
.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o),
|
168
|
-
.fd_in = my_fileno(fd_in),
|
169
|
-
.fd_out = my_fileno(fd_out),
|
170
|
-
.len = (size_t)NUM2ULONG(len),
|
171
|
-
.flags = NUM2UINT(flags),
|
172
|
-
};
|
173
|
-
|
174
|
-
n = (long)rb_thread_blocking_region(nogvl_splice, &a, RUBY_UBF_IO, 0);
|
193
|
+
long n = do_splice(argc, argv, 0);
|
194
|
+
|
175
195
|
if (n == 0)
|
176
196
|
rb_eof_error();
|
177
197
|
if (n < 0)
|
@@ -179,6 +199,33 @@ static VALUE my_splice(VALUE self,
|
|
179
199
|
return LONG2NUM(n);
|
180
200
|
}
|
181
201
|
|
202
|
+
/*
|
203
|
+
* call-seq:
|
204
|
+
* IO.trysplice(fd_in, off_in, fd_out, off_out, len) => integer
|
205
|
+
* IO.trysplice(fd_in, off_in, fd_out, off_out, len, flags) => integer
|
206
|
+
*
|
207
|
+
* Exactly like IO.splice, except +:EAGAIN+ is returned when either
|
208
|
+
* the read or write end would block instead of raising Errno::EAGAIN.
|
209
|
+
*
|
210
|
+
* IO::Splice::F_NONBLOCK is always passed for the pipe descriptor,
|
211
|
+
* but this can still block if the non-pipe descriptor is blocking.
|
212
|
+
*
|
213
|
+
* See IO.splice documentation for more details.
|
214
|
+
*/
|
215
|
+
static VALUE trysplice(int argc, VALUE *argv, VALUE self)
|
216
|
+
{
|
217
|
+
long n = do_splice(argc, argv, SPLICE_F_NONBLOCK);
|
218
|
+
|
219
|
+
if (n == 0)
|
220
|
+
return Qnil;
|
221
|
+
if (n < 0) {
|
222
|
+
if (errno == EAGAIN)
|
223
|
+
return sym_EAGAIN;
|
224
|
+
rb_sys_fail("splice");
|
225
|
+
}
|
226
|
+
return LONG2NUM(n);
|
227
|
+
}
|
228
|
+
|
182
229
|
struct tee_args {
|
183
230
|
int fd_in;
|
184
231
|
int fd_out;
|
@@ -194,15 +241,30 @@ static VALUE nogvl_tee(void *ptr)
|
|
194
241
|
return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
|
195
242
|
}
|
196
243
|
|
244
|
+
static long do_tee(int argc, VALUE *argv, unsigned dflags)
|
245
|
+
{
|
246
|
+
VALUE fd_in, fd_out, len, flags;
|
247
|
+
struct tee_args a;
|
248
|
+
|
249
|
+
rb_scan_args(argc, argv, "31", &fd_in, &fd_out, &len, &flags);
|
250
|
+
a.fd_in = my_fileno(fd_in);
|
251
|
+
a.fd_out = my_fileno(fd_out);
|
252
|
+
a.len = (size_t)NUM2ULONG(len);
|
253
|
+
a.flags = NIL_P(flags) ? dflags : NUM2UINT(flags) | dflags;
|
254
|
+
|
255
|
+
return (long)nb_io_run(nogvl_tee, &a, a.flags);
|
256
|
+
}
|
257
|
+
|
197
258
|
/*
|
198
259
|
* call-seq:
|
260
|
+
* IO.tee(fd_in, fd_out, len) => integer
|
199
261
|
* IO.tee(fd_in, fd_out, len, flags) => integer
|
200
262
|
*
|
201
263
|
* Copies up to +len+ bytes of data from +fd_in+ to +fd_out+. +fd_in+
|
202
264
|
* and +fd_out+ must both refer to pipe descriptors. +fd_in+ and +fd_out+
|
203
265
|
* may not be endpoints of the same pipe.
|
204
266
|
*
|
205
|
-
* +flags+ may be zero or IO::Splice::F_NONBLOCK
|
267
|
+
* +flags+ may be zero (the default) or IO::Splice::F_NONBLOCK
|
206
268
|
* Other IO::Splice flags are currently unimplemented or have no effect.
|
207
269
|
*
|
208
270
|
* Returns the number of bytes duplicated if successful.
|
@@ -210,22 +272,16 @@ static VALUE nogvl_tee(void *ptr)
|
|
210
272
|
* Raises Errno::EAGAIN when +fd_in+ is empty and/or +fd_out+ is full
|
211
273
|
* and +flags+ contains IO::Splice::F_NONBLOCK
|
212
274
|
*
|
275
|
+
* Consider using IO.trytee if you are using IO::Splice::F_NONBLOCK
|
276
|
+
* as it avoids the cost of raising common Errno::EAGAIN exceptions.
|
277
|
+
*
|
213
278
|
* See manpage for full documentation:
|
214
279
|
* http://kernel.org/doc/man-pages/online/pages/man2/tee.2.html
|
215
280
|
*/
|
216
|
-
static VALUE my_tee(VALUE self
|
217
|
-
VALUE fd_in, VALUE fd_out,
|
218
|
-
VALUE len, VALUE flags)
|
281
|
+
static VALUE my_tee(int argc, VALUE *argv, VALUE self)
|
219
282
|
{
|
220
|
-
long n;
|
221
|
-
|
222
|
-
.fd_in = my_fileno(fd_in),
|
223
|
-
.fd_out = my_fileno(fd_out),
|
224
|
-
.len = (size_t)NUM2ULONG(len),
|
225
|
-
.flags = NUM2UINT(flags),
|
226
|
-
};
|
227
|
-
|
228
|
-
n = (long)nb_io_run(nogvl_tee, &a, a.flags);
|
283
|
+
long n = do_tee(argc, argv, 0);
|
284
|
+
|
229
285
|
if (n == 0)
|
230
286
|
rb_eof_error();
|
231
287
|
if (n < 0)
|
@@ -234,6 +290,34 @@ static VALUE my_tee(VALUE self,
|
|
234
290
|
return LONG2NUM(n);
|
235
291
|
}
|
236
292
|
|
293
|
+
/*
|
294
|
+
* call-seq:
|
295
|
+
* IO.trytee(fd_in, fd_out, len) => integer
|
296
|
+
* IO.trytee(fd_in, fd_out, len, flags) => integer
|
297
|
+
*
|
298
|
+
* Exactly like IO.tee, except +:EAGAIN+ is returned when either
|
299
|
+
* the read or write end would block instead of raising Errno::EAGAIN.
|
300
|
+
*
|
301
|
+
* IO::Splice::F_NONBLOCK is always passed for the pipe descriptor,
|
302
|
+
* but this can still block if the non-pipe descriptor is blocking.
|
303
|
+
*
|
304
|
+
* See IO.tee documentation for more details.
|
305
|
+
*/
|
306
|
+
static VALUE trytee(int argc, VALUE *argv, VALUE self)
|
307
|
+
{
|
308
|
+
long n = do_tee(argc, argv, SPLICE_F_NONBLOCK);
|
309
|
+
|
310
|
+
if (n == 0)
|
311
|
+
return Qnil;
|
312
|
+
if (n < 0) {
|
313
|
+
if (errno == EAGAIN)
|
314
|
+
return sym_EAGAIN;
|
315
|
+
rb_sys_fail("tee");
|
316
|
+
}
|
317
|
+
|
318
|
+
return LONG2NUM(n);
|
319
|
+
}
|
320
|
+
|
237
321
|
struct vmsplice_args {
|
238
322
|
int fd;
|
239
323
|
struct iovec *iov;
|
@@ -272,7 +356,7 @@ do { \
|
|
272
356
|
static void advance_vmsplice_args(struct vmsplice_args *a, long n)
|
273
357
|
{
|
274
358
|
struct iovec *new_iov = a->iov;
|
275
|
-
|
359
|
+
unsigned long i;
|
276
360
|
|
277
361
|
/* skip over iovecs we've already written completely */
|
278
362
|
for (i = 0; i < a->nr_segs; i++, new_iov++) {
|
@@ -301,7 +385,9 @@ static void advance_vmsplice_args(struct vmsplice_args *a, long n)
|
|
301
385
|
|
302
386
|
/*
|
303
387
|
* call-seq:
|
388
|
+
* IO.vmsplice(fd, string_array) => integer
|
304
389
|
* IO.vmsplice(fd, string_array, flags) => integer
|
390
|
+
* IO.vmsplice(fd, string) => integer
|
305
391
|
* IO.vmsplice(fd, string, flags) => integer
|
306
392
|
*
|
307
393
|
* Transfers an array of strings into the pipe descriptor given by fd.
|
@@ -313,11 +399,14 @@ static void advance_vmsplice_args(struct vmsplice_args *a, long n)
|
|
313
399
|
* See manpage for full documentation:
|
314
400
|
* http://kernel.org/doc/man-pages/online/pages/man2/vmsplice.2.html
|
315
401
|
*/
|
316
|
-
static VALUE my_vmsplice(
|
402
|
+
static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
|
317
403
|
{
|
318
404
|
long rv = 0;
|
319
405
|
ssize_t left;
|
320
406
|
struct vmsplice_args a;
|
407
|
+
VALUE fd, data, flags;
|
408
|
+
|
409
|
+
rb_scan_args(argc, argv, "21", &fd, &data, &flags);
|
321
410
|
|
322
411
|
switch (TYPE(data)) {
|
323
412
|
case T_STRING: {
|
@@ -338,7 +427,7 @@ static VALUE my_vmsplice(VALUE self, VALUE fd, VALUE data, VALUE flags)
|
|
338
427
|
rb_obj_classname(data));
|
339
428
|
}
|
340
429
|
a.fd = my_fileno(fd);
|
341
|
-
a.flags = NUM2UINT(flags);
|
430
|
+
a.flags = NIL_P(flags) ? 0 : NUM2UINT(flags);
|
342
431
|
|
343
432
|
for (;;) {
|
344
433
|
long n = (long)nb_io_run(nogvl_vmsplice, &a, a.flags);
|
@@ -442,9 +531,11 @@ void Init_io_splice_ext(void)
|
|
442
531
|
VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
|
443
532
|
struct utsname utsname;
|
444
533
|
|
445
|
-
rb_define_singleton_method(rb_cIO, "splice", my_splice,
|
446
|
-
rb_define_singleton_method(rb_cIO, "
|
447
|
-
rb_define_singleton_method(rb_cIO, "
|
534
|
+
rb_define_singleton_method(rb_cIO, "splice", my_splice, -1);
|
535
|
+
rb_define_singleton_method(rb_cIO, "trysplice", trysplice, -1);
|
536
|
+
rb_define_singleton_method(rb_cIO, "tee", my_tee, -1);
|
537
|
+
rb_define_singleton_method(rb_cIO, "trytee", trytee, -1);
|
538
|
+
rb_define_singleton_method(rb_cIO, "vmsplice", my_vmsplice, -1);
|
448
539
|
|
449
540
|
/*
|
450
541
|
* Attempt to move pages instead of copying. This is only a hint
|
@@ -510,4 +601,6 @@ void Init_io_splice_ext(void)
|
|
510
601
|
rb_define_const(mSplice, "F_SETPIPE_SZ",
|
511
602
|
UINT2NUM(F_SETPIPE_SZ));
|
512
603
|
}
|
604
|
+
|
605
|
+
sym_EAGAIN = ID2SYM(rb_intern("EAGAIN"));
|
513
606
|
}
|