io_splice 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/GNUmakefile +30 -5
- data/LICENSE +3 -3
- data/README +10 -0
- data/ext/io_splice/io_splice_ext.c +136 -62
- data/lib/io/splice.rb +2 -2
- data/local.mk.sample +3 -52
- data/test/test_io_splice.rb +152 -5
- metadata +2 -2
data/GNUmakefile
CHANGED
@@ -3,6 +3,7 @@ all::
|
|
3
3
|
RUBY = ruby
|
4
4
|
RAKE = rake
|
5
5
|
GIT_URL = git://git.bogomips.org/ruby_io_splice.git
|
6
|
+
RSYNC = rsync
|
6
7
|
|
7
8
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
8
9
|
@./GIT-VERSION-GEN
|
@@ -40,7 +41,7 @@ manifest: $(pkg_extra)
|
|
40
41
|
|
41
42
|
.manifest:
|
42
43
|
(git ls-files && \
|
43
|
-
for i in $@ $(pkg_extra)
|
44
|
+
for i in $@ $(pkg_extra); \
|
44
45
|
do echo $$i; done) | LC_ALL=C sort > $@+
|
45
46
|
cmp $@+ $@ || mv $@+ $@
|
46
47
|
$(RM) $@+
|
@@ -67,10 +68,10 @@ cgit_atom := http://git.bogomips.org/cgit/ruby_io_splice.git/atom/?h=master
|
|
67
68
|
atom = <link rel="alternate" title="Atom feed" href="$(1)" \
|
68
69
|
type="application/atom+xml"/>
|
69
70
|
|
70
|
-
# using rdoc 2.
|
71
|
+
# using rdoc 2.5.x + workaround patch here:
|
72
|
+
# rubyforge.org/tracker/index.php?func=detail&aid=28230&group_id=627&atid=2472
|
71
73
|
doc: .document NEWS ChangeLog
|
72
|
-
|
73
|
-
rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
|
74
|
+
rdoc -a -t "$(shell sed -ne '1s/^= //p' README)"
|
74
75
|
install -m644 COPYING doc/COPYING
|
75
76
|
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
76
77
|
cd doc && for i in $(base_bins); do \
|
@@ -85,7 +86,31 @@ doc: .document NEWS ChangeLog
|
|
85
86
|
doc/NEWS.html doc/README.html
|
86
87
|
$(RAKE) -s news_atom > doc/NEWS.atom.xml
|
87
88
|
cd doc && ln README.html tmp && mv tmp index.html
|
88
|
-
|
89
|
+
|
90
|
+
latest: NEWS
|
91
|
+
@awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' $<
|
92
|
+
|
93
|
+
# publishes docs to http://bogomips.org/ruby_io_splice/,
|
94
|
+
publish_doc:
|
95
|
+
-git set-file-times
|
96
|
+
$(RM) -r doc ChangeLog NEWS
|
97
|
+
$(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
|
98
|
+
awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
|
99
|
+
NEWS > doc/LATEST
|
100
|
+
find doc/images doc/js -type f | \
|
101
|
+
TZ=UTC xargs touch -d '1970-01-01 00:00:01' doc/rdoc.css
|
102
|
+
$(MAKE) doc_gz
|
103
|
+
chmod 644 $$(find doc -type f)
|
104
|
+
$(RSYNC) -av doc/ bogomips.org:/srv/bogomips/ruby_io_splice/
|
105
|
+
git ls-files | xargs touch
|
106
|
+
|
107
|
+
# Create gzip variants of the same timestamp as the original so nginx
|
108
|
+
# "gzip_static on" can serve the gzipped versions directly.
|
109
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
110
|
+
doc_gz:
|
111
|
+
touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
|
112
|
+
for i in $(docs); do \
|
113
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
89
114
|
|
90
115
|
ifneq ($(VERSION),)
|
91
116
|
rfproject := qrp
|
data/LICENSE
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
io_splice is copyrighted Free Software by all contributors, see logs in
|
2
2
|
revision control for names and email addresses of all of them.
|
3
3
|
|
4
|
-
You can redistribute it and/or modify it under
|
4
|
+
You can redistribute it and/or modify it under the terms of the GNU
|
5
5
|
Lesser General Public License as published by the Free Software Foundation,
|
6
6
|
version 3.0 {LGPLv3}[http://www.gnu.org/licenses/lgpl-3.0.txt] (see
|
7
7
|
link:COPYING).
|
8
8
|
|
9
|
-
|
9
|
+
io_splice is distributed in the hope that it will be useful, but WITHOUT
|
10
10
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
11
11
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
12
12
|
License for more details.
|
13
13
|
|
14
14
|
You should have received a copy of the GNU Lesser General Public License
|
15
|
-
along with
|
15
|
+
along with this library; if not, write to the Free Software
|
16
16
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
data/README
CHANGED
@@ -85,3 +85,13 @@ don't email the git mailing list or maintainer with io_splice patches.
|
|
85
85
|
|
86
86
|
All feedback (bug reports, user/development discussion, patches, pull
|
87
87
|
requests) go to the mailing list: mailto:ruby.io.splice@librelist.com
|
88
|
+
|
89
|
+
== Mailing List Archives
|
90
|
+
|
91
|
+
In addition to the rsync-able archives provided by http://librelist.com/, we
|
92
|
+
are also mirrored to
|
93
|
+
{Gmane}[http://gmane.org/info.php?group=gmane.comp.lang.ruby.io-splice.general]
|
94
|
+
and maintain our own mbox mirrors downloadable via HTTP.
|
95
|
+
|
96
|
+
* nntp://news.gmane.org/gmane.comp.lang.ruby.io-splice.general
|
97
|
+
* http://bogomips.org/ruby_io_splice/archives/
|
@@ -10,10 +10,38 @@
|
|
10
10
|
#include <limits.h>
|
11
11
|
#include <alloca.h>
|
12
12
|
|
13
|
-
#
|
14
|
-
# define
|
15
|
-
#
|
13
|
+
#if ! HAVE_RB_IO_T
|
14
|
+
# define rb_io_t OpenFile
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#ifdef GetReadFile
|
18
|
+
# define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
16
19
|
#else
|
20
|
+
# if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
21
|
+
# define FPTR_TO_FD(fptr) fileno(fptr->f)
|
22
|
+
# else
|
23
|
+
# define FPTR_TO_FD(fptr) fptr->fd
|
24
|
+
# endif
|
25
|
+
#endif
|
26
|
+
|
27
|
+
static int my_fileno(VALUE io)
|
28
|
+
{
|
29
|
+
rb_io_t *fptr;
|
30
|
+
|
31
|
+
for (;;) {
|
32
|
+
switch (TYPE(io)) {
|
33
|
+
case T_FIXNUM: return NUM2INT(io);
|
34
|
+
case T_FILE: {
|
35
|
+
GetOpenFile(io, fptr);
|
36
|
+
return FPTR_TO_FD(fptr);
|
37
|
+
}
|
38
|
+
default:
|
39
|
+
io = rb_convert_type(io, T_FILE, "IO", "to_io");
|
40
|
+
/* retry */
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
17
45
|
/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
|
18
46
|
# include <rubysig.h>
|
19
47
|
# define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
@@ -34,8 +62,6 @@ rb_thread_blocking_region(
|
|
34
62
|
|
35
63
|
return rv;
|
36
64
|
}
|
37
|
-
# define RUBY_1_8_TRAP_BEG TRAP_BEG
|
38
|
-
# define RUBY_1_8_TRAP_END TRAP_END
|
39
65
|
#endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
40
66
|
|
41
67
|
#ifndef RSTRING_PTR
|
@@ -77,21 +103,9 @@ struct splice_args {
|
|
77
103
|
static VALUE nogvl_splice(void *ptr)
|
78
104
|
{
|
79
105
|
struct splice_args *a = ptr;
|
80
|
-
long n;
|
81
106
|
|
82
|
-
|
83
|
-
|
84
|
-
* only affects the pipe descriptor, not the non-pipe descriptor.
|
85
|
-
* So use TRAP_BEG/TRAP_END (only) to make Ruby 1.8 happy. We also
|
86
|
-
* don't want the TRAP_BEG/TRAP_END compatibility layer in 1.9,
|
87
|
-
* so we use the 1.8-only versions
|
88
|
-
*/
|
89
|
-
RUBY_1_8_TRAP_BEG;
|
90
|
-
n = splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
|
91
|
-
a->len, a->flags);
|
92
|
-
RUBY_1_8_TRAP_END;
|
93
|
-
|
94
|
-
return (VALUE)n;
|
107
|
+
return (VALUE)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
|
108
|
+
a->len, a->flags);
|
95
109
|
}
|
96
110
|
|
97
111
|
/*
|
@@ -140,13 +154,13 @@ static VALUE my_splice(VALUE self,
|
|
140
154
|
struct splice_args a = {
|
141
155
|
.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i),
|
142
156
|
.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o),
|
143
|
-
.fd_in =
|
144
|
-
.fd_out =
|
157
|
+
.fd_in = my_fileno(fd_in),
|
158
|
+
.fd_out = my_fileno(fd_out),
|
145
159
|
.len = (size_t)NUM2ULONG(len),
|
146
160
|
.flags = NUM2UINT(flags),
|
147
161
|
};
|
148
162
|
|
149
|
-
n = (long)
|
163
|
+
n = (long)rb_thread_blocking_region(nogvl_splice, &a, RUBY_UBF_IO, 0);
|
150
164
|
if (n == 0)
|
151
165
|
rb_eof_error();
|
152
166
|
if (n < 0)
|
@@ -194,8 +208,8 @@ static VALUE my_tee(VALUE self,
|
|
194
208
|
{
|
195
209
|
long n;
|
196
210
|
struct tee_args a = {
|
197
|
-
.fd_in =
|
198
|
-
.fd_out =
|
211
|
+
.fd_in = my_fileno(fd_in),
|
212
|
+
.fd_out = my_fileno(fd_out),
|
199
213
|
.len = (size_t)NUM2ULONG(len),
|
200
214
|
.flags = NUM2UINT(flags),
|
201
215
|
};
|
@@ -223,6 +237,58 @@ static VALUE nogvl_vmsplice(void *ptr)
|
|
223
237
|
return (VALUE)vmsplice(a->fd, a->iov, a->nr_segs, a->flags);
|
224
238
|
}
|
225
239
|
|
240
|
+
/* this can't be a function since we use alloca() */
|
241
|
+
#define ARY2IOVEC(iov,iovcnt,expect,ary) \
|
242
|
+
do { \
|
243
|
+
VALUE *cur; \
|
244
|
+
struct iovec *tmp; \
|
245
|
+
long n; \
|
246
|
+
Check_Type(ary, T_ARRAY); \
|
247
|
+
cur = RARRAY_PTR(ary); \
|
248
|
+
n = RARRAY_LEN(ary); \
|
249
|
+
if (n > IOV_MAX) \
|
250
|
+
rb_raise(rb_eArgError, "array is larger than IOV_MAX"); \
|
251
|
+
iov = tmp = alloca(sizeof(struct iovec) * n); \
|
252
|
+
expect = 0; \
|
253
|
+
iovcnt = n; \
|
254
|
+
for (; --n >= 0; tmp++, cur++) { \
|
255
|
+
Check_Type(*cur, T_STRING); \
|
256
|
+
tmp->iov_base = RSTRING_PTR(*cur); \
|
257
|
+
tmp->iov_len = RSTRING_LEN(*cur); \
|
258
|
+
expect += tmp->iov_len; \
|
259
|
+
} \
|
260
|
+
} while (0)
|
261
|
+
|
262
|
+
static void advance_vmsplice_args(struct vmsplice_args *a, long n)
|
263
|
+
{
|
264
|
+
struct iovec *new_iov = a->iov;
|
265
|
+
int i;
|
266
|
+
|
267
|
+
/* skip over iovecs we've already written completely */
|
268
|
+
for (i = 0; i < a->nr_segs; i++, new_iov++) {
|
269
|
+
if (n == 0)
|
270
|
+
break;
|
271
|
+
/*
|
272
|
+
* partially written iov,
|
273
|
+
* modify and retry with current iovec in
|
274
|
+
* front
|
275
|
+
*/
|
276
|
+
if (new_iov->iov_len > (size_t)n) {
|
277
|
+
VALUE base = (VALUE)new_iov->iov_base;
|
278
|
+
|
279
|
+
new_iov->iov_len -= n;
|
280
|
+
new_iov->iov_base = (void *)(base + n);
|
281
|
+
break;
|
282
|
+
}
|
283
|
+
|
284
|
+
n -= new_iov->iov_len;
|
285
|
+
}
|
286
|
+
|
287
|
+
/* setup to retry without the already-written iovecs */
|
288
|
+
a->nr_segs -= i;
|
289
|
+
a->iov = new_iov;
|
290
|
+
}
|
291
|
+
|
226
292
|
/*
|
227
293
|
* call-seq:
|
228
294
|
* IO.vmsplice(fd, string_array, flags) => integer
|
@@ -238,46 +304,48 @@ static VALUE nogvl_vmsplice(void *ptr)
|
|
238
304
|
*/
|
239
305
|
static VALUE my_vmsplice(VALUE self, VALUE fd, VALUE data, VALUE flags)
|
240
306
|
{
|
241
|
-
long
|
307
|
+
long rv = 0;
|
308
|
+
ssize_t left;
|
242
309
|
struct vmsplice_args a;
|
243
|
-
struct iovec *tmp;
|
244
|
-
VALUE *ary;
|
245
|
-
|
246
|
-
switch (TYPE(data)) {
|
247
|
-
case T_ARRAY:
|
248
|
-
ary = RARRAY_PTR(data);
|
249
|
-
a.nr_segs = RARRAY_LEN(data);
|
250
|
-
|
251
|
-
if (a.nr_segs > IOV_MAX)
|
252
|
-
rb_raise(rb_eArgError, "array larger than IOV_MAX");
|
253
310
|
|
254
|
-
|
311
|
+
ARY2IOVEC(a.iov, a.nr_segs, left, data);
|
312
|
+
a.fd = my_fileno(fd);
|
313
|
+
a.flags = NUM2UINT(flags);
|
255
314
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
315
|
+
for (;;) {
|
316
|
+
long n = (long)nb_io_run(nogvl_vmsplice, &a, a.flags);
|
317
|
+
|
318
|
+
if (n < 0) {
|
319
|
+
if (errno == EAGAIN) {
|
320
|
+
if (a.flags & SPLICE_F_NONBLOCK)
|
321
|
+
rb_sys_fail("vmsplice");
|
322
|
+
else if (rb_io_wait_writable(a.fd))
|
323
|
+
continue;
|
324
|
+
/* fall through on error */
|
325
|
+
}
|
326
|
+
/*
|
327
|
+
* unlikely to hit this case, return the
|
328
|
+
* already written bytes, we'll let the next
|
329
|
+
* write (or close) fail instead
|
330
|
+
*/
|
331
|
+
if (rv > 0)
|
332
|
+
break;
|
333
|
+
rb_sys_fail("vmsplice");
|
262
334
|
}
|
263
|
-
break;
|
264
|
-
default:
|
265
|
-
rb_raise(rb_eArgError, "must be an array of strings");
|
266
|
-
}
|
267
|
-
|
268
|
-
a.fd = NUM2INT(fd);
|
269
|
-
a.flags = NUM2UINT(flags);
|
270
335
|
|
271
|
-
|
272
|
-
|
273
|
-
|
336
|
+
rv += n;
|
337
|
+
left -= n;
|
338
|
+
if (left == 0)
|
339
|
+
break;
|
340
|
+
advance_vmsplice_args(&a, n);
|
341
|
+
}
|
274
342
|
|
275
|
-
return LONG2NUM(
|
343
|
+
return LONG2NUM(rv);
|
276
344
|
}
|
277
345
|
|
278
346
|
void Init_io_splice_ext(void)
|
279
347
|
{
|
280
|
-
VALUE
|
348
|
+
VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
|
281
349
|
|
282
350
|
rb_define_singleton_method(rb_cIO, "splice", my_splice, 6);
|
283
351
|
rb_define_singleton_method(rb_cIO, "tee", my_tee, 4);
|
@@ -288,32 +356,38 @@ void Init_io_splice_ext(void)
|
|
288
356
|
* and support for it was removed in Linux 2.6.21 and has not been
|
289
357
|
* readded as of 2.6.30.
|
290
358
|
*/
|
291
|
-
rb_define_const(
|
359
|
+
rb_define_const(mSplice, "F_MOVE", UINT2NUM(SPLICE_F_MOVE));
|
292
360
|
|
293
361
|
/*
|
294
|
-
* Do not block on I/O. This flag only affects the pipe(s)
|
295
|
-
* spliced from/to and has no effect on the non-pipe
|
296
|
-
* (which requires non-blocking operation to be set
|
362
|
+
* Do not block on pipe I/O. This flag only affects the pipe(s)
|
363
|
+
* being spliced from/to and has no effect on the non-pipe
|
364
|
+
* descriptor (which requires non-blocking operation to be set
|
365
|
+
* explicitly).
|
366
|
+
*
|
367
|
+
* The non-blocking flag (O_NONBLOCK) on the pipe descriptors
|
368
|
+
* themselves are ignored by this family of functions, and
|
369
|
+
* using this flag is the only way to get non-blocking operation
|
370
|
+
* out of them.
|
297
371
|
*/
|
298
|
-
rb_define_const(
|
372
|
+
rb_define_const(mSplice, "F_NONBLOCK", UINT2NUM(SPLICE_F_NONBLOCK));
|
299
373
|
|
300
374
|
/*
|
301
375
|
* Indicate that there may be more data coming into the outbound
|
302
376
|
* descriptor. This can allow the kernel to avoid sending partial
|
303
377
|
* frames from sockets. Currently only used with splice.
|
304
378
|
*/
|
305
|
-
rb_define_const(
|
379
|
+
rb_define_const(mSplice, "F_MORE", UINT2NUM(SPLICE_F_MORE));
|
306
380
|
|
307
381
|
/*
|
308
382
|
* Only usable by vmsplice. This flag probably not useful in the
|
309
383
|
* context of Ruby applications which cannot control alignment.
|
310
384
|
*/
|
311
|
-
rb_define_const(
|
385
|
+
rb_define_const(mSplice, "F_GIFT", UINT2NUM(SPLICE_F_GIFT));
|
312
386
|
|
313
387
|
/*
|
314
388
|
* The maximum size of an atomic write to a pipe
|
315
389
|
* POSIX requires this to be at least 512 bytes.
|
316
390
|
* Under Linux, this is 4096 bytes.
|
317
391
|
*/
|
318
|
-
rb_define_const(
|
392
|
+
rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));
|
319
393
|
}
|
data/lib/io/splice.rb
CHANGED
@@ -3,10 +3,10 @@ require 'io_splice_ext'
|
|
3
3
|
|
4
4
|
class IO
|
5
5
|
|
6
|
-
|
6
|
+
module Splice
|
7
7
|
|
8
8
|
# the version of IO::Splice, currently 0.1.0
|
9
|
-
VERSION = '
|
9
|
+
VERSION = '1.0.0'
|
10
10
|
|
11
11
|
# The maximum capacity of the pipe in bytes.
|
12
12
|
# Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before
|
data/local.mk.sample
CHANGED
@@ -1,64 +1,15 @@
|
|
1
|
-
# this is a sample local.mk file, feel free to modify it for your needs
|
2
|
-
# GNUmakefile will source local.mk in the top-level source tree
|
3
|
-
# if it is present.
|
4
|
-
#
|
5
|
-
# This is depends on a bunch of GNU-isms from bash, touch.
|
6
|
-
|
7
|
-
RSYNC = rsync
|
8
1
|
DLEXT := so
|
9
|
-
gems :=
|
10
2
|
|
11
3
|
# Avoid loading rubygems to speed up tests because gmake is
|
12
4
|
# fork+exec heavy with Ruby.
|
13
5
|
prefix = $(HOME)
|
6
|
+
|
14
7
|
ifeq ($(r19),)
|
15
8
|
RUBY := $(prefix)/bin/ruby
|
16
|
-
|
9
|
+
RAKE := $(prefix)/bin/rake
|
17
10
|
else
|
18
11
|
prefix := $(prefix)/ruby-1.9
|
19
12
|
export PATH := $(prefix)/bin:$(PATH)
|
20
13
|
RUBY := $(prefix)/bin/ruby --disable-gems
|
21
|
-
|
14
|
+
RAKE := $(prefix)/bin/rake
|
22
15
|
endif
|
23
|
-
|
24
|
-
ifdef gem_paths
|
25
|
-
sp :=
|
26
|
-
sp +=
|
27
|
-
export RUBYLIB := $(subst $(sp),:,$(addsuffix /lib,$(gem_paths)))
|
28
|
-
endif
|
29
|
-
|
30
|
-
# pipefail is THE reason to use bash (v3+) or never revisions of ksh93
|
31
|
-
# SHELL := /bin/bash -e -o pipefail
|
32
|
-
SHELL := /bin/ksh93 -e -o pipefail
|
33
|
-
|
34
|
-
# trace execution of tests
|
35
|
-
# TRACER = strace -f -o $(t_pfx).strace -s 100000
|
36
|
-
TRACER = /usr/bin/time -v -o $(t_pfx).time
|
37
|
-
|
38
|
-
latest: NEWS
|
39
|
-
@awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' $<
|
40
|
-
|
41
|
-
# publishes docs to http://bogomips.org/ruby_io_splice/
|
42
|
-
publish_doc:
|
43
|
-
-git set-file-times
|
44
|
-
$(RM) -r doc ChangeLog NEWS
|
45
|
-
$(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
|
46
|
-
$(MAKE) -s latest > doc/LATEST
|
47
|
-
find doc/images doc/js -type f | \
|
48
|
-
TZ=UTC xargs touch -d '1970-01-01 00:00:00' doc/rdoc.css
|
49
|
-
$(MAKE) doc_gz
|
50
|
-
chmod 644 $$(find doc -type f)
|
51
|
-
$(RSYNC) -av doc/ dcvr:/srv/bogomips/ruby_io_splice/
|
52
|
-
git ls-files | xargs touch
|
53
|
-
|
54
|
-
# Create gzip variants of the same timestamp as the original so nginx
|
55
|
-
# "gzip_static on" can serve the gzipped versions directly.
|
56
|
-
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
|
57
|
-
doc_gz:
|
58
|
-
touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
|
59
|
-
for i in $(docs); do \
|
60
|
-
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
61
|
-
|
62
|
-
# launches any of the following shells with RUBYLIB set
|
63
|
-
irb sh bash ksh:
|
64
|
-
$@
|
data/test/test_io_splice.rb
CHANGED
@@ -1,15 +1,60 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'test/unit'
|
3
3
|
require 'tempfile'
|
4
|
+
require 'socket'
|
5
|
+
require 'io/nonblock'
|
6
|
+
$-w = true
|
4
7
|
require 'io/splice'
|
5
8
|
|
9
|
+
# unused_port provides an unused port on +addr+ usable for TCP that is
|
10
|
+
# guaranteed to be unused across all unicorn builds on that system. It
|
11
|
+
# prevents race conditions by using a lock file other unicorn builds
|
12
|
+
# will see. This is required if you perform several builds in parallel
|
13
|
+
# with a continuous integration system or run tests in parallel via
|
14
|
+
# gmake. This is NOT guaranteed to be race-free if you run other
|
15
|
+
# processes that bind to random ports for testing (but the window
|
16
|
+
# for a race condition is very small).
|
17
|
+
def unused_port(addr = '127.0.0.1')
|
18
|
+
retries = 100
|
19
|
+
base = 5000
|
20
|
+
port = sock = nil
|
21
|
+
begin
|
22
|
+
begin
|
23
|
+
port = base + rand(32768 - base)
|
24
|
+
while port == 8080
|
25
|
+
port = base + rand(32768 - base)
|
26
|
+
end
|
27
|
+
|
28
|
+
sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
29
|
+
sock.bind(Socket.pack_sockaddr_in(port, addr))
|
30
|
+
sock.listen(5)
|
31
|
+
rescue Errno::EADDRINUSE, Errno::EACCES
|
32
|
+
sock.close rescue nil
|
33
|
+
retry if (retries -= 1) >= 0
|
34
|
+
end
|
35
|
+
|
36
|
+
# since we'll end up closing the random port we just got, there's a race
|
37
|
+
# condition could allow the random port we just chose to reselect itself
|
38
|
+
# when running tests in parallel with gmake. Create a lock file while
|
39
|
+
# we have the port here to ensure that does not happen .
|
40
|
+
lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock"
|
41
|
+
lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
|
42
|
+
at_exit { File.unlink(lock_path) rescue nil }
|
43
|
+
rescue Errno::EEXIST
|
44
|
+
sock.close rescue nil
|
45
|
+
retry
|
46
|
+
end
|
47
|
+
sock.close rescue nil
|
48
|
+
port
|
49
|
+
end
|
50
|
+
|
6
51
|
class Test_IO_Splice < Test::Unit::TestCase
|
7
52
|
|
8
53
|
def test_splice
|
9
54
|
str = 'abcde'
|
10
55
|
size = 5
|
11
56
|
rd, wr = IO.pipe
|
12
|
-
tmp = Tempfile.new(
|
57
|
+
tmp = Tempfile.new('ruby_io_splice')
|
13
58
|
|
14
59
|
assert_nothing_raised {
|
15
60
|
tmp.syswrite(str)
|
@@ -21,12 +66,48 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
21
66
|
assert_equal str, rd.sysread(size)
|
22
67
|
end
|
23
68
|
|
69
|
+
def test_splice_io
|
70
|
+
str = 'abcde'
|
71
|
+
size = 5
|
72
|
+
rd, wr = IO.pipe
|
73
|
+
tmp = Tempfile.new('ruby_io_splice')
|
74
|
+
|
75
|
+
assert_nothing_raised {
|
76
|
+
tmp.syswrite(str)
|
77
|
+
tmp.sysseek(0)
|
78
|
+
}
|
79
|
+
|
80
|
+
nr = IO.splice(tmp, nil, wr, nil, size, 0)
|
81
|
+
assert_equal size, nr
|
82
|
+
assert_equal str, rd.sysread(size)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_splice_io_ish
|
86
|
+
str = 'abcde'
|
87
|
+
size = 5
|
88
|
+
rd, wr = IO.pipe
|
89
|
+
tmp = Tempfile.new('ruby_io_splice')
|
90
|
+
io_ish = [ tmp ]
|
91
|
+
def io_ish.to_io
|
92
|
+
first.to_io
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_nothing_raised {
|
96
|
+
tmp.syswrite(str)
|
97
|
+
tmp.sysseek(0)
|
98
|
+
}
|
99
|
+
|
100
|
+
nr = IO.splice(io_ish, nil, wr, nil, size, 0)
|
101
|
+
assert_equal size, nr
|
102
|
+
assert_equal str, rd.sysread(size)
|
103
|
+
end
|
104
|
+
|
24
105
|
def test_splice_in_offset
|
25
106
|
str = 'abcde'
|
26
107
|
off = 3
|
27
108
|
len = 2
|
28
109
|
rd, wr = IO.pipe
|
29
|
-
tmp = Tempfile.new(
|
110
|
+
tmp = Tempfile.new('ruby_io_splice')
|
30
111
|
|
31
112
|
assert_nothing_raised {
|
32
113
|
tmp.syswrite(str)
|
@@ -41,7 +122,7 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
41
122
|
def test_splice_out_offset
|
42
123
|
str = 'abcde'
|
43
124
|
rd, wr = IO.pipe
|
44
|
-
tmp = Tempfile.new(
|
125
|
+
tmp = Tempfile.new('ruby_io_splice')
|
45
126
|
|
46
127
|
assert_nothing_raised { wr.syswrite(str) }
|
47
128
|
nr = IO.splice(rd.fileno, nil, tmp.fileno, 3, str.size, 0)
|
@@ -52,7 +133,7 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
52
133
|
|
53
134
|
def test_splice_nonblock
|
54
135
|
rd, wr = IO.pipe
|
55
|
-
tmp = Tempfile.new(
|
136
|
+
tmp = Tempfile.new('ruby_io_splice')
|
56
137
|
|
57
138
|
assert_raises(Errno::EAGAIN) {
|
58
139
|
IO.splice(rd.fileno, nil, tmp.fileno, 0, 5, IO::Splice::F_NONBLOCK)
|
@@ -61,7 +142,7 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
61
142
|
|
62
143
|
def test_splice_eof
|
63
144
|
rd, wr = IO.pipe
|
64
|
-
tmp = Tempfile.new(
|
145
|
+
tmp = Tempfile.new('ruby_io_splice')
|
65
146
|
wr.syswrite 'abc'
|
66
147
|
wr.close
|
67
148
|
|
@@ -72,6 +153,17 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
72
153
|
}
|
73
154
|
end
|
74
155
|
|
156
|
+
def test_splice_nonblock_socket
|
157
|
+
port = unused_port
|
158
|
+
server = TCPServer.new('127.0.0.1', port)
|
159
|
+
rp, wp = IO.pipe
|
160
|
+
rs = TCPSocket.new('127.0.0.1', port)
|
161
|
+
rs.nonblock = true
|
162
|
+
assert_raises(Errno::EAGAIN) { IO.splice(rs, nil, wp, nil, 1024, 0) }
|
163
|
+
rs.close
|
164
|
+
server.close
|
165
|
+
end
|
166
|
+
|
75
167
|
def test_tee
|
76
168
|
str = 'abcde'
|
77
169
|
size = 5
|
@@ -100,6 +192,19 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
100
192
|
}
|
101
193
|
end
|
102
194
|
|
195
|
+
def test_tee_io
|
196
|
+
str = 'abcde'
|
197
|
+
size = 5
|
198
|
+
rda, wra = IO.pipe
|
199
|
+
rdb, wrb = IO.pipe
|
200
|
+
|
201
|
+
assert_nothing_raised { wra.syswrite(str) }
|
202
|
+
nr = IO.tee(rda, wrb, size, 0)
|
203
|
+
assert_equal 5, nr
|
204
|
+
assert_equal str, rdb.sysread(5)
|
205
|
+
assert_equal str, rda.sysread(5)
|
206
|
+
end
|
207
|
+
|
103
208
|
def test_vmsplice_array
|
104
209
|
data = %w(hello world how are you today)
|
105
210
|
r, w = IO.pipe
|
@@ -108,6 +213,14 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
108
213
|
assert_equal data.join(''), r.readpartial(16384)
|
109
214
|
end
|
110
215
|
|
216
|
+
def test_vmsplice_array_io
|
217
|
+
data = %w(hello world how are you today)
|
218
|
+
r, w = IO.pipe
|
219
|
+
n = IO.vmsplice(w, data, 0)
|
220
|
+
assert_equal data.join('').size, n
|
221
|
+
assert_equal data.join(''), r.readpartial(16384)
|
222
|
+
end
|
223
|
+
|
111
224
|
def test_vmsplice_nonblock
|
112
225
|
data = %w(hello world how are you today)
|
113
226
|
r, w = IO.pipe
|
@@ -117,6 +230,40 @@ class Test_IO_Splice < Test::Unit::TestCase
|
|
117
230
|
}
|
118
231
|
end
|
119
232
|
|
233
|
+
def test_vmsplice_in_full
|
234
|
+
empty = ""
|
235
|
+
|
236
|
+
# bs * count should be > PIPE_BUF
|
237
|
+
[ [ 512, 512 ], [ 131073, 3 ], [ 4098, 64 ] ].each do |(bs,count)|
|
238
|
+
rd, wr = IO.pipe
|
239
|
+
buf = File.open('/dev/urandom', 'rb') { |fp| fp.sysread(bs) }
|
240
|
+
|
241
|
+
vec = (1..count).map { buf }
|
242
|
+
pid = fork do
|
243
|
+
wr.close
|
244
|
+
tmp = []
|
245
|
+
begin
|
246
|
+
sleep 0.005
|
247
|
+
tmp << rd.readpartial(8192, buf)
|
248
|
+
rescue EOFError
|
249
|
+
break
|
250
|
+
end while true
|
251
|
+
ok = (vec.join(empty) == tmp.join(empty))
|
252
|
+
exit! ok
|
253
|
+
end
|
254
|
+
assert_nothing_raised { rd.close }
|
255
|
+
assert_equal(bs * count, IO.vmsplice(wr.fileno, vec, 0))
|
256
|
+
assert_nothing_raised { wr.close }
|
257
|
+
_, status = Process.waitpid2(pid)
|
258
|
+
assert status.success?
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_vmsplice_nil
|
263
|
+
data = %w(hello world how are you today)
|
264
|
+
assert_raises(TypeError) { IO.vmsplice(nil, data, 0) }
|
265
|
+
end
|
266
|
+
|
120
267
|
def test_constants
|
121
268
|
assert IO::Splice::PIPE_BUF > 0
|
122
269
|
%w(move nonblock more gift).each { |x|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io_splice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- io_splice hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-05-27 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|