io_splice 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.so
3
3
  *.log
4
4
  *.rbc
5
+ .rbx
5
6
  Makefile
6
7
  /GIT-VERSION-FILE
7
8
  /local.mk
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v4.2.0
4
+ DEF_VER=v4.3.0
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -6,7 +6,6 @@ rfpackage := io_splice
6
6
  include pkg.mk
7
7
  ifneq ($(VERSION),)
8
8
  release::
9
- $(RAKE) raa_update VERSION=$(VERSION)
10
9
  $(RAKE) publish_news VERSION=$(VERSION)
11
10
  endif
12
11
  rcov: build
data/README CHANGED
@@ -14,11 +14,9 @@ buffer.
14
14
  arbitrary file descriptors (assuming kernel support), not just
15
15
  file-to-socket (or file-to-anything in newer Linux).
16
16
 
17
- * Thread-safe blocking operations under Ruby 1.9, releases GVL
17
+ * Thread-safe blocking operations under Ruby 1.9+, releases GVL
18
18
  if blocking operations are used.
19
19
 
20
- * Almost drop-in replacement for IO.copy_stream: IO::Splice.copy_stream
21
-
22
20
  * Safely usable with non-blocking I/O frameworks (unlike IO.copy_stream)
23
21
  when combined with the IO::Splice::F_NONBLOCK flag.
24
22
 
data/Rakefile CHANGED
@@ -31,40 +31,3 @@ task :publish_news do
31
31
  rf.login
32
32
  rf.post_news('qrp', subject, body)
33
33
  end
34
-
35
- desc "post to RAA"
36
- task :raa_update do
37
- require 'net/http'
38
- require 'net/netrc'
39
- rc = Net::Netrc.locate('io_splice-raa') or abort "~/.netrc not found"
40
- password = rc.password
41
-
42
- s = Gem::Specification.load('io_splice.gemspec')
43
- desc = [ s.description.strip ]
44
- desc << ""
45
- desc << "* #{s.email}"
46
- desc << "* #{git_url}"
47
- desc << "* #{cgit_url}"
48
- desc = desc.join("\n")
49
- uri = URI.parse('http://raa.ruby-lang.org/regist.rhtml')
50
- form = {
51
- :name => s.name,
52
- :short_description => s.summary,
53
- :version => s.version.to_s,
54
- :status => 'stable',
55
- :owner => s.authors.first,
56
- :email => s.email,
57
- :category_major => 'Library',
58
- :category_minor => 'System',
59
- :url => s.homepage,
60
- :download => 'http://rubyforge.org/frs/?group_id=5626',
61
- :license => "LGPL",
62
- :description_style => 'Plain',
63
- :description => desc,
64
- :pass => password,
65
- :submit => 'Update',
66
- }
67
- res = Net::HTTP.post_form(uri, form)
68
- p res
69
- puts res.body
70
- end
@@ -1,13 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- encoding: binary -*-
3
-
4
- # Example of using IO.splice to copy a file
5
- # This can be significantly faster than IO.copy_stream as data
6
- # is never copied into userspace.
7
-
8
- require 'io/splice'
9
-
10
- usage = "#$0 SOURCE DEST"
11
- source = ARGV.shift or abort usage
12
- dest = ARGV.shift or abort usage
13
- IO::Splice.copy_stream(source, dest)
3
+ # This example is no longer valid, IO.copy_stream is faster in Ruby 2.2+
4
+ # since it uses sendfile directly, which now allows direct file-to-file
5
+ # copying (on Linux only) with fewer syscalls than splice.
@@ -3,7 +3,9 @@ $CPPFLAGS << ' -D_GNU_SOURCE=1'
3
3
 
4
4
  have_func('splice', %w(fcntl.h)) or abort 'splice(2) not defined'
5
5
  have_func('tee', %w(fcntl.h)) or abort 'tee(2) not defined'
6
+ have_func('pipe2', %w(fcntl.h unistd.h))
6
7
  have_func('rb_thread_blocking_region')
8
+ have_func('rb_thread_call_without_gvl')
7
9
  have_macro('F_GETPIPE_SZ', %w(fcntl.h))
8
10
  have_macro('F_SETPIPE_SZ', %w(fcntl.h))
9
11
 
@@ -79,23 +79,32 @@ static int check_fileno(VALUE io)
79
79
  errno = saved_errno;
80
80
  return fd;
81
81
  }
82
- #ifndef HAVE_RB_THREAD_BLOCKING_REGION
82
+
83
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && defined(HAVE_RUBY_THREAD_H)
84
+ /* Ruby 2.0+ */
85
+ # include <ruby/thread.h>
86
+ # define WITHOUT_GVL(fn,a,ubf,b) \
87
+ rb_thread_call_without_gvl((fn),(a),(ubf),(b))
88
+ #elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
89
+ typedef VALUE (*my_blocking_fn_t)(void*);
90
+ # define WITHOUT_GVL(fn,a,ubf,b) \
91
+ rb_thread_blocking_region((my_blocking_fn_t)(fn),(a),(ubf),(b))
92
+
93
+ #else /* Ruby 1.8 */
83
94
  /* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
84
95
  # include <rubysig.h>
85
96
  # define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
86
97
  typedef void rb_unblock_function_t(void *);
87
- typedef VALUE rb_blocking_function_t(void *);
88
- static VALUE
89
- rb_thread_blocking_region(
90
- rb_blocking_function_t *fn, void *data1,
91
- rb_unblock_function_t *ubf, void *data2)
98
+ typedef void * rb_blocking_function_t(void *);
99
+ static void * WITHOUT_GVL(rb_blocking_function_t *func, void *data1,
100
+ rb_unblock_function_t *ubf, void *data2)
92
101
  {
93
- VALUE rv;
102
+ void *rv;
94
103
 
95
104
  assert(RUBY_UBF_IO == ubf && "RUBY_UBF_IO required for emulation");
96
105
 
97
106
  TRAP_BEG;
98
- rv = fn(data1);
107
+ rv = func(data1);
99
108
  TRAP_END;
100
109
 
101
110
  return rv;
@@ -108,17 +117,11 @@ rb_thread_blocking_region(
108
117
  #ifndef RSTRING_LEN
109
118
  # define RSTRING_LEN(s) (RSTRING(s)->len)
110
119
  #endif
111
- #ifndef RARRAY_PTR
112
- # define RARRAY_PTR(s) (RARRAY(s)->ptr)
113
- #endif
114
120
  #ifndef RARRAY_LEN
115
121
  # define RARRAY_LEN(s) (RARRAY(s)->len)
116
122
  #endif
117
123
 
118
- static VALUE io_run(rb_blocking_function_t *fn, void *data)
119
- {
120
- return rb_thread_blocking_region(fn, data, RUBY_UBF_IO, 0);
121
- }
124
+ #define io_run(fn,data) WITHOUT_GVL((fn),(data),RUBY_UBF_IO,0)
122
125
 
123
126
  struct splice_args {
124
127
  int fd_in;
@@ -129,14 +132,14 @@ struct splice_args {
129
132
  unsigned flags;
130
133
  };
131
134
 
132
- static VALUE nogvl_splice(void *ptr)
135
+ static void * nogvl_splice(void *ptr)
133
136
  {
134
137
  struct splice_args *a = ptr;
135
138
 
136
139
  if (a->len > MAX_AT_ONCE)
137
140
  a->len = MAX_AT_ONCE;
138
141
 
139
- return (VALUE)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
142
+ return (void *)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
140
143
  a->len, a->flags);
141
144
  }
142
145
 
@@ -210,7 +213,6 @@ static ssize_t do_splice(int argc, VALUE *argv, unsigned dflags)
210
213
  * * IO::Splice::F_MOVE
211
214
  * * IO::Splice::F_NONBLOCK
212
215
  * * IO::Splice::F_MORE
213
- * * IO::Splice::WAITALL
214
216
  *
215
217
  * Returns the number of bytes spliced.
216
218
  * Raises EOFError when +io_in+ has reached end of file.
@@ -278,14 +280,14 @@ struct tee_args {
278
280
  };
279
281
 
280
282
  /* runs without GVL */
281
- static VALUE nogvl_tee(void *ptr)
283
+ static void * nogvl_tee(void *ptr)
282
284
  {
283
285
  struct tee_args *a = ptr;
284
286
 
285
287
  if (a->len > MAX_AT_ONCE)
286
288
  a->len = MAX_AT_ONCE;
287
289
 
288
- return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
290
+ return (void *)tee(a->fd_in, a->fd_out, a->len, a->flags);
289
291
  }
290
292
 
291
293
  static ssize_t do_tee(int argc, VALUE *argv, unsigned dflags)
@@ -344,7 +346,6 @@ static ssize_t do_tee(int argc, VALUE *argv, unsigned dflags)
344
346
  *
345
347
  * +flags+ may be zero (the default) or a combination of:
346
348
  * * IO::Splice::F_NONBLOCK
347
- * * IO::Splice::WAITALL
348
349
  *
349
350
  * Other IO::Splice flags are currently unimplemented or have no effect.
350
351
  *
@@ -406,30 +407,28 @@ struct vmsplice_args {
406
407
  unsigned flags;
407
408
  };
408
409
 
409
- static VALUE nogvl_vmsplice(void *ptr)
410
+ static void * nogvl_vmsplice(void *ptr)
410
411
  {
411
412
  struct vmsplice_args *a = ptr;
412
413
 
413
- return (VALUE)vmsplice(a->fd, a->iov, a->nr_segs, a->flags);
414
+ return (void *)vmsplice(a->fd, a->iov, a->nr_segs, a->flags);
414
415
  }
415
416
 
416
417
  /* this can't be a function since we use alloca() */
417
418
  #define ARY2IOVEC(iov,iovcnt,expect,ary) \
418
419
  do { \
419
- VALUE *cur; \
420
420
  struct iovec *tmp; \
421
- long n; \
422
- cur = RARRAY_PTR(ary); \
423
- n = RARRAY_LEN(ary); \
424
- if (n > IOV_MAX) \
421
+ unsigned long i; \
422
+ iovcnt = (unsigned long)RARRAY_LEN(ary); \
423
+ if (iovcnt > IOV_MAX) \
425
424
  rb_raise(rb_eArgError, "array is larger than IOV_MAX"); \
426
- iov = tmp = alloca(sizeof(struct iovec) * n); \
425
+ iov = tmp = alloca(sizeof(struct iovec) * iovcnt); \
427
426
  expect = 0; \
428
- iovcnt = n; \
429
- for (; --n >= 0; tmp++, cur++) { \
430
- Check_Type(*cur, T_STRING); \
431
- tmp->iov_base = RSTRING_PTR(*cur); \
432
- tmp->iov_len = RSTRING_LEN(*cur); \
427
+ for (i = 0; i < iovcnt; tmp++, i++) { \
428
+ VALUE cur = rb_ary_entry(ary, (long)i); \
429
+ Check_Type(cur, T_STRING); \
430
+ tmp->iov_base = RSTRING_PTR(cur); \
431
+ tmp->iov_len = RSTRING_LEN(cur); \
433
432
  expect += tmp->iov_len; \
434
433
  } \
435
434
  } while (0)
@@ -619,8 +618,14 @@ static VALUE set_pipe_size(VALUE self, VALUE size)
619
618
 
620
619
  static int can_mod_pipe_size(void)
621
620
  {
621
+ /*
622
+ * pipe2 appeared in Linux 2.6.27, F_*PIPE_SZ appeared in 2.6.35,
623
+ * thus not having pipe2 automatically disqualifies us from having
624
+ * F_*PIPE_SZ support
625
+ */
626
+ #ifdef HAVE_PIPE2
622
627
  int fds[2];
623
- int rc = pipe(fds);
628
+ int rc = pipe2(fds, O_CLOEXEC);
624
629
 
625
630
  if (rc == 0) {
626
631
  rc = fcntl(fds[0], F_GETPIPE_SZ);
@@ -629,13 +634,22 @@ static int can_mod_pipe_size(void)
629
634
  (void)close(fds[0]);
630
635
  (void)close(fds[1]);
631
636
  } else {
632
- /* weird error, but don't raise during init */
637
+ /*
638
+ * weird error, but don't raise during init, this could be
639
+ * ENOSYS, even..
640
+ */
633
641
  rc = 0;
634
642
  }
635
643
  errno = 0;
636
644
  return rc;
645
+ #else /* ! HAVE_PIPE2 */
646
+ return 0;
647
+ #endif /* ! HAVE_PIPE2 */
637
648
  }
638
649
 
650
+ #define NODOC_CONST(klass,name,value) \
651
+ rb_define_const((klass),(name),(value))
652
+
639
653
  void Init_io_splice_ext(void)
640
654
  {
641
655
  VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
@@ -696,7 +710,7 @@ void Init_io_splice_ext(void)
696
710
  *
697
711
  * IO.vmsplice always defaults to this behavior.
698
712
  */
699
- rb_define_const(mSplice, "WAITALL", UINT2NUM(WAITALL));
713
+ NODOC_CONST(mSplice, "WAITALL", UINT2NUM(WAITALL));
700
714
 
701
715
  /*
702
716
  * The maximum size of an atomic write to a pipe
data/io_splice.gemspec CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |s|
21
21
  s.rubyforge_project = %q{qrp}
22
22
  s.test_files = Dir['test/test_*.rb']
23
23
  s.add_development_dependency('wrongdoc', '~> 1.5')
24
- s.add_development_dependency('rack', '~> 1.2')
25
24
 
26
25
  # s.licenses = %w(LGPL) # accessor not compatible with older RubyGems
27
26
  end
data/lib/io/splice.rb CHANGED
@@ -3,6 +3,14 @@ require 'io_splice_ext'
3
3
  require 'io/wait'
4
4
 
5
5
  module IO::Splice
6
+ @warned = false
7
+
8
+ def self.__deprecated
9
+ return if @warned
10
+ warn("IO::Splice.{copy_stream,full} are deprecated " \
11
+ "and to be removed in io_splice 5.x")
12
+ @warned = true
13
+ end
6
14
 
7
15
  # The maximum default capacity of the pipe in bytes.
8
16
  # Under stock Linux, this is 65536 bytes as of 2.6.11, and 4096 before
@@ -36,10 +44,19 @@ module IO::Splice
36
44
  # Otherwise the copy will be until EOF is reached on the +src+.
37
45
  # +src+ and +dst+ must be IO objects or respond to +to_io+
38
46
  #
39
- # This is nearly a drop-in replacement for IO.copy_stream (in Ruby 1.9)
40
- # but does not take into account userspace I/O buffers nor IO-like
41
- # objects with no underlying file descriptor (e.g. StringIO).
47
+ # Unlike IO.copy_stream, this does not take into account
48
+ # userspace I/O buffers nor IO-like objects with no underlying
49
+ # file descriptor (e.g. StringIO).
50
+ #
51
+ # This is unsafe for socket-to-socket copies unless there is an
52
+ # active (blocking) reader on the other end.
53
+ #
54
+ # This method is deprecated and will be removed in a future, as it is
55
+ # potentially unsafe for socket-to-socket operations and difficult-to-use.
56
+ # IO.copy_stream on Linux 2.6.33 and later allows using sendfile for
57
+ # file-to-file copies, so this offers no advantage.
42
58
  def self.copy_stream(src, dst, len = nil, src_offset = nil)
59
+ __deprecated
43
60
  close = []
44
61
  need_open?(src) and close << (src = File.open(src))
45
62
  need_open?(dst) and close << (dst = File.open(dst, "w"))
@@ -90,6 +107,7 @@ module IO::Splice
90
107
  #
91
108
  # This method is safe for splicing a pipe +src+ into any type of +dst+ IO.
92
109
  def self.full(src, dst, len, src_offset)
110
+ __deprecated
93
111
  IO.splice(src, src_offset, dst, nil, len, F_MOVE | WAITALL)
94
112
  end
95
113
 
@@ -332,130 +332,6 @@ class Test_IO_Splice < Test::Unit::TestCase
332
332
  assert IO::Splice::PIPE_CAPA >= IO::Splice::PIPE_BUF
333
333
  end
334
334
 
335
- def test_splice_copy_stream_file_to_file_small
336
- a, b = Tempfile.new('a'), Tempfile.new('b')
337
- a.syswrite 'hello world'
338
- a.sysseek(0)
339
- IO::Splice.copy_stream(a, b)
340
- b.rewind
341
- assert_equal 'hello world', b.read
342
- end
343
-
344
- def test_splice_copy_stream_file_to_file_big
345
- buf = ('ab' * IO::Splice::PIPE_CAPA) + 'hi'
346
- a, b = Tempfile.new('a'), Tempfile.new('b')
347
- a.syswrite buf
348
- a.sysseek(0)
349
- IO::Splice.copy_stream(a, b)
350
- b.rewind
351
- assert_equal buf, b.read
352
- end
353
-
354
- def test_splice_copy_stream_file_to_file_big_partial
355
- nr = IO::Splice::PIPE_CAPA
356
- buf = ('ab' * nr) + 'hi'
357
- a, b = Tempfile.new('a'), Tempfile.new('b')
358
- a.syswrite buf
359
- a.sysseek(0)
360
- assert_equal nr, IO::Splice.copy_stream(a, b, nr)
361
- b.rewind
362
- assert_equal('ab' * (nr/2), b.read)
363
- end
364
-
365
- def test_splice_copy_stream_file_to_file_len
366
- a, b = Tempfile.new('a'), Tempfile.new('b')
367
- a.syswrite 'hello world'
368
- a.sysseek(0)
369
- IO::Splice.copy_stream(a, b, 5)
370
- b.rewind
371
- assert_equal 'hello', b.read
372
- end
373
-
374
- def test_splice_copy_stream_pipe_to_file_len
375
- a = Tempfile.new('a')
376
- r, w = IO.pipe
377
- w.syswrite 'hello world'
378
- IO::Splice.copy_stream(r, a, 5)
379
- a.rewind
380
- assert_equal 'hello', a.read
381
- end
382
-
383
- def test_splice_copy_stream_paths
384
- a = Tempfile.new('a')
385
- b = Tempfile.new('a')
386
- a.syswrite('hello world')
387
- IO::Splice.copy_stream(a.path, b.path, 5)
388
- assert_equal 'hello', b.read
389
- end
390
-
391
- def test_splice_copy_stream_src_offset
392
- a = Tempfile.new('a')
393
- b = Tempfile.new('a')
394
- a.syswrite('hello world')
395
- IO::Splice.copy_stream(a.path, b.path, 5, 6)
396
- assert_equal 'world', b.read
397
- end
398
-
399
- def test_splice_copy_stream_src_offset_unchanged
400
- a = Tempfile.new('a')
401
- b = Tempfile.new('a')
402
- a.syswrite('hello world')
403
- assert_equal 0, a.sysseek(0, IO::SEEK_SET)
404
- IO::Splice.copy_stream(a, b.path, 5, 6)
405
- assert_equal 'world', b.read
406
- assert_equal 0, a.sysseek(0, IO::SEEK_CUR)
407
- end
408
-
409
- def test_copy_stream_nonblock_src
410
- server = TCPServer.new('127.0.0.1', 0)
411
- port = server.addr[1]
412
- rp, wp = IO.pipe
413
- rs = TCPSocket.new('127.0.0.1', port)
414
- rs.nonblock = true
415
- nr = 0
416
- assert_raises(Timeout::Error) do
417
- timeout(0.05) { nr += IO::Splice.copy_stream(rs, wp, 5) }
418
- end
419
- assert_equal 0, nr
420
- rs.close
421
- server.close
422
- end if mri?
423
-
424
- def test_copy_stream_nonblock_dst
425
- server = TCPServer.new('127.0.0.1', 0)
426
- port = server.addr[1]
427
- rp, wp = IO.pipe
428
- rs = TCPSocket.new('127.0.0.1', port)
429
- rs.nonblock = true
430
- client = server.accept
431
- buf = ' ' * IO::Splice::PIPE_CAPA
432
- nr = 0
433
- assert_raises(Timeout::Error) do
434
- loop do
435
- begin
436
- wp.write_nonblock(buf)
437
- rescue Errno::EAGAIN
438
- end
439
- timeout(0.05) do
440
- nr += IO::Splice.copy_stream(rp, rs, IO::Splice::PIPE_CAPA)
441
- end
442
- end
443
- end
444
- assert_equal nr, client.read(nr).size
445
- rs.close
446
- server.close
447
- end if mri?
448
-
449
- def test_copy_stream_eof
450
- r, w = IO.pipe
451
- w.syswrite 'hello world'
452
- w.close
453
- a = Tempfile.new('a')
454
- assert_equal 11, IO::Splice.copy_stream(r, a)
455
- a.rewind
456
- assert_equal 'hello world', a.read
457
- end
458
-
459
335
  def test_pipe_size
460
336
  r, w = IO.pipe
461
337
  assert_kind_of Integer, r.pipe_size
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: !binary |-
3
3
  aW9fc3BsaWNl
4
4
  version: !ruby/object:Gem::Version
5
- version: 4.2.0
5
+ version: 4.3.0
6
6
  prerelease:
7
7
  platform: ruby
8
8
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-01-19 00:00:00.000000000 Z
14
+ date: 2014-02-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: !binary |-
@@ -34,27 +34,6 @@ dependencies:
34
34
  - !ruby/object:Gem::Version
35
35
  version: !binary |-
36
36
  MS41
37
- - !ruby/object:Gem::Dependency
38
- name: !binary |-
39
- cmFjaw==
40
- requirement: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - !binary |-
44
- fj4=
45
- - !ruby/object:Gem::Version
46
- version: !binary |-
47
- MS4y
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - !binary |-
54
- fj4=
55
- - !ruby/object:Gem::Version
56
- version: !binary |-
57
- MS4y
58
37
  description: ! 'The splice family of Linux system calls can transfer data between
59
38
  file
60
39
 
@@ -103,12 +82,9 @@ files:
103
82
  - local.mk.sample
104
83
  - pkg.mk
105
84
  - setup.rb
106
- - test/test_copy_stream.rb
107
85
  - test/test_io_splice.rb
108
86
  - test/test_io_splice_eintr.rb
109
87
  - test/test_io_splice_in_full.rb
110
- - test/test_rack_file_compat.rb
111
- - test/test_tcp_splice.rb
112
88
  homepage: http://bogomips.org/ruby_io_splice/
113
89
  licenses: []
114
90
  post_install_message:
@@ -139,15 +115,9 @@ signing_key:
139
115
  specification_version: 3
140
116
  summary: zero-copy pipe I/O for Linux and Ruby
141
117
  test_files:
142
- - !binary |-
143
- dGVzdC90ZXN0X3JhY2tfZmlsZV9jb21wYXQucmI=
144
118
  - !binary |-
145
119
  dGVzdC90ZXN0X2lvX3NwbGljZV9pbl9mdWxsLnJi
146
- - !binary |-
147
- dGVzdC90ZXN0X3RjcF9zcGxpY2UucmI=
148
120
  - !binary |-
149
121
  dGVzdC90ZXN0X2lvX3NwbGljZS5yYg==
150
- - !binary |-
151
- dGVzdC90ZXN0X2NvcHlfc3RyZWFtLnJi
152
122
  - !binary |-
153
123
  dGVzdC90ZXN0X2lvX3NwbGljZV9laW50ci5yYg==
@@ -1,340 +0,0 @@
1
- require 'test/unit'
2
- require 'tmpdir'
3
- require "fcntl"
4
- require 'io/nonblock'
5
- require 'socket'
6
- require 'timeout'
7
- require 'tempfile'
8
- require 'io/splice'
9
-
10
- class TestIOCopyStreamCompat < Test::Unit::TestCase
11
- def have_nonblock?
12
- IO.method_defined?("nonblock=")
13
- end
14
-
15
- def pipe(wp, rp)
16
- re, we = nil, nil
17
- r, w = IO.pipe
18
- rt = Thread.new do
19
- begin
20
- rp.call(r)
21
- rescue Exception
22
- r.close
23
- re = $!
24
- end
25
- end
26
- wt = Thread.new do
27
- begin
28
- wp.call(w)
29
- rescue Exception
30
- w.close
31
- we = $!
32
- end
33
- end
34
- flunk("timeout") unless wt.join(10) && rt.join(10)
35
- ensure
36
- w.close unless !w || w.closed?
37
- r.close unless !r || r.closed?
38
- (wt.kill; wt.join) if wt
39
- (rt.kill; rt.join) if rt
40
- raise we if we
41
- raise re if re
42
- end
43
-
44
- def with_pipe
45
- r, w = IO.pipe
46
- begin
47
- yield r, w
48
- ensure
49
- r.close unless r.closed?
50
- w.close unless w.closed?
51
- end
52
- end
53
-
54
- def with_read_pipe(content)
55
- pipe(proc do |w|
56
- w << content
57
- w.close
58
- end, proc do |r|
59
- yield r
60
- end)
61
- end
62
-
63
- def mkcdtmpdir
64
- Dir.mktmpdir {|d|
65
- Dir.chdir(d) {
66
- yield
67
- }
68
- }
69
- end
70
-
71
- def trapping_usr1
72
- @usr1_rcvd = 0
73
- trap(:USR1) { @usr1_rcvd += 1 }
74
- yield
75
- ensure
76
- trap(:USR1, "DEFAULT")
77
- end
78
-
79
- def test_copy_stream
80
- mkcdtmpdir {
81
- content = "foobar"
82
- File.open("src", "w") {|f| f << content }
83
- ret = IO::Splice.copy_stream("src", "dst")
84
- assert_equal(content.bytesize, ret)
85
- assert_equal(content, File.read("dst"))
86
-
87
- # overwrite by smaller file.
88
- content = "baz"
89
- File.open("src", "w") {|f| f << content }
90
- ret = IO::Splice.copy_stream("src", "dst")
91
- assert_equal(content.bytesize, ret)
92
- assert_equal(content, File.read("dst"))
93
-
94
- ret = IO::Splice.copy_stream("src", "dst", 2)
95
- assert_equal(2, ret)
96
- assert_equal(content[0,2], File.read("dst"))
97
-
98
- ret = IO::Splice.copy_stream("src", "dst", 0)
99
- assert_equal(0, ret)
100
- assert_equal("", File.read("dst"))
101
-
102
- ret = IO::Splice.copy_stream("src", "dst", nil, 1)
103
- assert_equal(content.bytesize-1, ret)
104
- assert_equal(content[1..-1], File.read("dst"))
105
-
106
- assert_raise(Errno::ENOENT) {
107
- IO::Splice.copy_stream("nodir/foo", "dst")
108
- }
109
-
110
- assert_raise(Errno::ENOENT) {
111
- IO::Splice.copy_stream("src", "nodir/bar")
112
- }
113
-
114
- pipe(proc do |w|
115
- ret = IO::Splice.copy_stream("src", w)
116
- assert_equal(content.bytesize, ret)
117
- w.close
118
- end, proc do |r|
119
- assert_equal(content, r.read)
120
- end)
121
-
122
- with_pipe {|r, w|
123
- w.close
124
- assert_raise(IOError) { IO::Splice.copy_stream("src", w) }
125
- }
126
-
127
- pipe_content = "abc"
128
- with_read_pipe(pipe_content) {|r|
129
- ret = IO::Splice.copy_stream(r, "dst")
130
- assert_equal(pipe_content.bytesize, ret)
131
- assert_equal(pipe_content, File.read("dst"))
132
- }
133
-
134
- pipe(proc do |w|
135
- ret = IO::Splice.copy_stream("src", w, 1, 1)
136
- assert_equal(1, ret)
137
- w.close
138
- end, proc do |r|
139
- assert_equal(content[1,1], r.read)
140
- end)
141
-
142
- bigcontent = "abc" * 123456
143
- File.open("bigsrc", "w") {|f| f << bigcontent }
144
- ret = IO::Splice.copy_stream("bigsrc", "bigdst")
145
- assert_equal(bigcontent.bytesize, ret)
146
- assert_equal(bigcontent, File.read("bigdst"))
147
-
148
- File.unlink("bigdst")
149
- ret = IO::Splice.copy_stream("bigsrc", "bigdst", nil, 100)
150
- assert_equal(bigcontent.bytesize-100, ret)
151
- assert_equal(bigcontent[100..-1], File.read("bigdst"))
152
-
153
- File.unlink("bigdst")
154
- ret = IO::Splice.copy_stream("bigsrc", "bigdst", 30000, 100)
155
- assert_equal(30000, ret)
156
- assert_equal(bigcontent[100, 30000], File.read("bigdst"))
157
-
158
- File.open("bigsrc") {|f|
159
- begin
160
- assert_equal(0, f.pos)
161
- ret = IO::Splice.copy_stream(f, "bigdst", nil, 10)
162
- assert_equal(bigcontent.bytesize-10, ret)
163
- assert_equal(bigcontent[10..-1], File.read("bigdst"))
164
- assert_equal(0, f.pos)
165
- ret = IO::Splice.copy_stream(f, "bigdst", 40, 30)
166
- assert_equal(40, ret)
167
- assert_equal(bigcontent[30, 40], File.read("bigdst"))
168
- assert_equal(0, f.pos)
169
- rescue NotImplementedError
170
- #skip "pread(2) is not implemtented."
171
- end
172
- }
173
-
174
- with_pipe {|r, w|
175
- w.close
176
- assert_raise(IOError) { IO::Splice.copy_stream("src", w) }
177
- }
178
-
179
- megacontent = "abc" * 1234567
180
- File.open("megasrc", "w") {|f| f << megacontent }
181
-
182
- if have_nonblock?
183
- with_pipe {|r1, w1|
184
- with_pipe {|r2, w2|
185
- begin
186
- r1.nonblock = true
187
- w2.nonblock = true
188
- rescue Errno::EBADF
189
- skip "nonblocking IO for pipe is not implemented"
190
- end
191
- t1 = Thread.new { w1 << megacontent; w1.close }
192
- t2 = Thread.new { r2.read }
193
- ret = IO::Splice.copy_stream(r1, w2)
194
- assert_equal(megacontent.bytesize, ret)
195
- w2.close
196
- t1.join
197
- assert_equal(megacontent, t2.value)
198
- }
199
- }
200
- end
201
-
202
- with_pipe {|r1, w1|
203
- with_pipe {|r2, w2|
204
- t1 = Thread.new { w1 << megacontent; w1.close }
205
- t2 = Thread.new { r2.read }
206
- ret = IO::Splice.copy_stream(r1, w2)
207
- assert_equal(megacontent.bytesize, ret)
208
- w2.close
209
- t1.join
210
- assert_equal(megacontent, t2.value)
211
- }
212
- }
213
-
214
- with_pipe {|r, w|
215
- t = Thread.new { r.read }
216
- ret = IO::Splice.copy_stream("megasrc", w)
217
- assert_equal(megacontent.bytesize, ret)
218
- w.close
219
- assert_equal(megacontent, t.value)
220
- }
221
- }
222
- end
223
-
224
- def with_socketpair
225
- s1, s2 = UNIXSocket.pair
226
- begin
227
- yield s1, s2
228
- ensure
229
- s1.close unless s1.closed?
230
- s2.close unless s2.closed?
231
- end
232
- end
233
-
234
- def test_copy_stream_socket
235
- mkcdtmpdir {
236
-
237
- content = "foobar"
238
- File.open("src", "w") {|f| f << content }
239
-
240
- with_socketpair {|s1, s2|
241
- ret = IO::Splice.copy_stream("src", s1)
242
- assert_equal(content.bytesize, ret)
243
- s1.close
244
- assert_equal(content, s2.read)
245
- }
246
-
247
- bigcontent = "abc" * 123456
248
- File.open("bigsrc", "w") {|f| f << bigcontent }
249
-
250
- with_socketpair {|s1, s2|
251
- t = Thread.new { s2.read }
252
- ret = IO::Splice.copy_stream("bigsrc", s1)
253
- assert_equal(bigcontent.bytesize, ret)
254
- s1.close
255
- result = t.value
256
- assert_equal(bigcontent, result)
257
- }
258
-
259
- with_socketpair {|s1, s2|
260
- t = Thread.new { s2.read }
261
- ret = IO::Splice.copy_stream("bigsrc", s1, 10000)
262
- assert_equal(10000, ret)
263
- s1.close
264
- result = t.value
265
- assert_equal(bigcontent[0,10000], result)
266
- }
267
-
268
- File.open("bigsrc") {|f|
269
- assert_equal(0, f.pos)
270
- with_socketpair {|s1, s2|
271
- t = Thread.new { s2.read }
272
- ret = IO::Splice.copy_stream(f, s1, nil, 100)
273
- assert_equal(bigcontent.bytesize-100, ret)
274
- assert_equal(0, f.pos)
275
- s1.close
276
- result = t.value
277
- assert_equal(bigcontent[100..-1], result)
278
- }
279
- }
280
-
281
- File.open("bigsrc") {|f|
282
- assert_equal(bigcontent[0,100], f.sysread(100))
283
- assert_equal(100, f.pos)
284
- with_socketpair {|s1, s2|
285
- t = Thread.new { s2.read }
286
- ret = IO::Splice.copy_stream(f, s1)
287
- assert_equal(bigcontent.bytesize-100, ret)
288
- assert_equal(bigcontent.length, f.sysseek(0, IO::SEEK_CUR))
289
- s1.close
290
- result = t.value
291
- assert_equal(bigcontent[100..-1], result)
292
- }
293
- }
294
-
295
- megacontent = "abc" * 1234567
296
- File.open("megasrc", "w") {|f| f << megacontent }
297
-
298
- if have_nonblock?
299
- with_socketpair {|s1, s2|
300
- begin
301
- s1.nonblock = true
302
- rescue Errno::EBADF
303
- skip "nonblocking IO for pipe is not implemented"
304
- end
305
- t = Thread.new { s2.read }
306
- ret = IO::Splice.copy_stream("megasrc", s1)
307
- assert_equal(megacontent.bytesize, ret)
308
- s1.close
309
- result = t.value
310
- assert_equal(megacontent, result)
311
- }
312
- with_socketpair {|s1, s2|
313
- begin
314
- s1.nonblock = true
315
- rescue Errno::EBADF
316
- skip "nonblocking IO for pipe is not implemented"
317
- end
318
- trapping_usr1 do
319
- nr = 10
320
- pid = fork do
321
- s1.close
322
- IO.select([s2])
323
- Process.kill(:USR1, Process.ppid)
324
- s2.read
325
- end
326
- s2.close
327
- nr.times do
328
- assert_equal megacontent.bytesize,
329
- IO::Splice.copy_stream("megasrc", s1)
330
- end
331
- assert_equal(1, @usr1_rcvd)
332
- s1.close
333
- _, status = Process.waitpid2(pid)
334
- assert status.success?, status.inspect
335
- end
336
- }
337
- end
338
- }
339
- end
340
- end
@@ -1,31 +0,0 @@
1
- # -*- encoding: binary -*-
2
- require "rack"
3
- require "test/unit"
4
- require "socket"
5
- require "io/splice"
6
-
7
- class TestRackFileCompat < Test::Unit::TestCase
8
- def setup
9
- @app = Rack::File.new(File.dirname(__FILE__))
10
- @req = Rack::MockRequest.new(@app)
11
- @base_file = File.basename(__FILE__)
12
- @r, @w = UNIXSocket.pair
13
- end
14
-
15
- def teardown
16
- [ @r, @w ].each { |io| io.closed? or io.close }
17
- end
18
-
19
- def test_get_rack_file
20
- env = Rack::MockRequest.env_for "http://example.com/#@base_file"
21
- status, headers, body = @app.call(env)
22
- assert_equal 200, status.to_i
23
- headers.each { |k,v|
24
- assert_instance_of String, k.to_str
25
- assert_instance_of String, v.to_str
26
- }
27
- thr = Thread.new { @r.read(File.size(__FILE__)) }
28
- assert_equal File.size(__FILE__), IO::Splice.copy_stream(body, @w)
29
- assert_equal File.read(__FILE__), thr.value
30
- end
31
- end if IO.respond_to?(:copy_stream)
@@ -1,66 +0,0 @@
1
- require 'socket'
2
- require 'io/wait'
3
- require 'io/splice'
4
- require 'io/nonblock'
5
- require "test/unit"
6
-
7
- class TestTCPCopyStream < Test::Unit::TestCase
8
- def setup
9
- host = ENV["TEST_HOST"] || "127.0.0.1"
10
- @srv = TCPServer.new(host, 0)
11
- @port = @srv.addr[1]
12
- @client = TCPSocket.new(host, @port)
13
- @client.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
14
- @accept = @srv.accept
15
- @accept.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
16
- @client.sync = @accept.sync = true
17
- @r, @w = IO.pipe
18
- end
19
-
20
- def teardown
21
- @srv.close
22
- [ @client, @accept, @r, @w ].each { |io| io.close unless io.closed? }
23
- end
24
-
25
- def test_client_to_server_eof
26
- nr = 2000
27
- buf = '0123456789abcdef' * 1024
28
- expect = buf.size * nr
29
- thr = Thread.new do
30
- nr.times { @client.write(buf) }
31
- @client.close
32
- end
33
- sleep 1 # wait for rcvbuf to fill up
34
- bytes = IO::Splice.copy_stream(@accept, "/dev/null")
35
- assert_equal expect, bytes
36
- end
37
-
38
- def test_client_to_server_expect
39
- nr = 2000
40
- buf = '0123456789abcdef' * 1024
41
- expect = buf.size * nr
42
- thr = Thread.new do
43
- nr.times { @client.write(buf) }
44
- end
45
- sleep 1 # wait for rcvbuf to fill up
46
- bytes = IO::Splice.copy_stream(@accept, "/dev/null", expect)
47
- assert_equal expect, bytes
48
- end
49
-
50
- def test_mega_splice
51
- nr = 2000
52
- buf = '0123456789abcdef' * 1024
53
- expect = buf.size * nr
54
- thr = Thread.new do
55
- nr.times { @client.write(buf) }
56
- @client.close
57
- end
58
- size_t_max = if (1 << 30).kind_of?(Bignum)
59
- 0xffffffff
60
- else
61
- 0xffffffffffffffff
62
- end
63
- bytes = IO::Splice.copy_stream(@accept, "/dev/null", size_t_max)
64
- assert_equal expect, bytes
65
- end
66
- end