io_splice 4.2.0 → 4.3.0

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