0001-add-IO-pread-and-IO-pwrite-methods.patch

patch with tests to implement feature - Eric Wong, 03/28/2011 02:06 PM

Download (6.22 KB)

View differences:

configure.in
1311 1311
	      setsid telldir seekdir fchmod cosh sinh tanh log2 round\
1312 1312
	      setuid setgid daemon select_large_fdset setenv unsetenv\
1313 1313
              mktime timegm gmtime_r clock_gettime gettimeofday\
1314
              pread sendfile shutdown sigaltstack dl_iterate_phdr)
1314
              pread pwrite sendfile shutdown sigaltstack dl_iterate_phdr)
1315 1315

  
1316 1316
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
1317 1317
  [AC_TRY_COMPILE([
io.c
3925 3925
    return LONG2FIX(n);
3926 3926
}
3927 3927

  
3928
#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
3929
struct prdwr_args {
3930
    int fd;
3931
    void *buf;
3932
    size_t count;
3933
    off_t offset;
3934
};
3935
#endif
3936

  
3937
#if defined(HAVE_PREAD)
3938
static VALUE
3939
nogvl_pread(void *ptr)
3940
{
3941
    struct prdwr_args *args = ptr;
3942

  
3943
    return (VALUE)pread(args->fd, args->buf, args->count, args->offset);
3944
}
3945

  
3946
/*
3947
 *  call-seq:
3948
 *     ios.pread(maxlen, offset[, outbuf])    -> string
3949
 *
3950
 *  Reads <i>maxlen</i> bytes from <em>ios</em> using the pread system call
3951
 *  and returns them as a string without modifying the underlying
3952
 *  descriptor offset.  This is advantageous compared to combining IO#seek
3953
 *  and IO#read in that it is atomic, allowing multiple threads/process to
3954
 *  share the same IO object for reading the file at various locations.
3955
 *  This bypasses any userspace buffering of the IO layer.
3956
 *  If the optional <i>outbuf</i> argument is present, it must
3957
 *  reference a String, which will receive the data.
3958
 *  Raises <code>SystemCallError</code> on error and <code>EOFError</code>
3959
 *  at end of file.
3960
 *  Not implemented on all platforms.
3961
 *
3962
 *     f = File.new("testfile")
3963
 *     f.pread(16, 0)   #=> "This is line one"
3964
 */
3965
static VALUE
3966
rb_io_pread(int argc, VALUE *argv, VALUE io)
3967
{
3968
    VALUE len, offset, str;
3969
    rb_io_t *fptr;
3970
    ssize_t n;
3971
    struct prdwr_args args;
3972

  
3973
    rb_scan_args(argc, argv, "21", &len, &offset, &str);
3974
    args.count = NUM2SIZET(len);
3975
    args.offset = NUM2OFFT(offset);
3976

  
3977
    io_setstrbuf(&str, (long)args.count);
3978
    if (args.count == 0) return str;
3979
    args.buf = RSTRING_PTR(str);
3980

  
3981
    GetOpenFile(io, fptr);
3982
    rb_io_check_byte_readable(fptr);
3983

  
3984
    args.fd = fptr->fd;
3985
    rb_io_check_closed(fptr);
3986

  
3987
    rb_str_locktmp(str);
3988
    n = (ssize_t)rb_thread_io_blocking_region(nogvl_pread, &args, fptr->fd);
3989
    rb_str_unlocktmp(str);
3990

  
3991
    if (n == -1) {
3992
	rb_sys_fail_path(fptr->pathv);
3993
    }
3994
    rb_str_set_len(str, n);
3995
    if (n == 0 && args.count > 0) {
3996
	rb_eof_error();
3997
    }
3998
    rb_str_resize(str, n);
3999
    OBJ_TAINT(str);
4000

  
4001
    return str;
4002
}
4003
#endif /* HAVE_PREAD */
4004

  
4005
#if defined(HAVE_PWRITE)
4006
static VALUE
4007
nogvl_pwrite(void *ptr)
4008
{
4009
    struct prdwr_args *args = ptr;
4010

  
4011
    return (VALUE)pwrite(args->fd, args->buf, args->count, args->offset);
4012
}
4013

  
4014
/*
4015
 *  call-seq:
4016
 *     ios.pwrite(offset, string)    -> integer
4017
 *
4018
 *  Writes the given string to <em>ios</em> at <i>offset</i> using pwrite()
4019
 *  system call.  This is advantageous to combining IO#seek and IO#write
4020
 *  in that it is atomic, allowing multiple threads/process to share the
4021
 *  same IO object for reading the file at various locations.
4022
 *  This bypasses any userspace buffering of the IO layer.
4023
 *  Returns the number of bytes written.
4024
 *  Raises <code>SystemCallError</code> on error.
4025
 *
4026
 *     f = File.new("out", "w")
4027
 *     f.pwrite(3, "ABCDEF")   #=> 6
4028
 */
4029
static VALUE
4030
rb_io_pwrite(VALUE io, VALUE offset, VALUE string)
4031
{
4032
    rb_io_t *fptr;
4033
    ssize_t n;
4034
    struct prdwr_args args;
4035

  
4036
    rb_secure(4);
4037
    string = rb_obj_as_string(string);
4038
    args.buf = RSTRING_PTR(string);
4039
    args.count = (size_t)RSTRING_LEN(string);
4040
    args.offset = NUM2OFFT(offset);
4041

  
4042
    io = GetWriteIO(io);
4043
    GetOpenFile(io, fptr);
4044
    rb_io_check_writable(fptr);
4045
    args.fd = fptr->fd;
4046

  
4047
    n = (ssize_t)rb_thread_io_blocking_region(nogvl_pwrite, &args, fptr->fd);
4048

  
4049
    if (n == -1) rb_sys_fail_path(fptr->pathv);
4050

  
4051
    return SSIZET2NUM(n);
4052
}
4053
#endif /* HAVE_PWRITE */
4054

  
3928 4055
/*
3929 4056
 *  call-seq:
3930 4057
 *     ios.sysread(maxlen[, outbuf])    -> string
......
10409 10536
    rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
10410 10537
    rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
10411 10538
    rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
10539

  
10540
#ifdef HAVE_PREAD
10541
    rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
10542
#endif
10543
#ifdef HAVE_PWRITE
10544
    rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
10545
#endif
10412 10546
    rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
10413 10547
    rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
10414 10548
    rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
test/ruby/test_io.rb
1809 1809
      Process.waitpid2(pid)
1810 1810
    end
1811 1811
  end
1812

  
1813
  def test_pread
1814
    t = make_tempfile
1815

  
1816
    open(t.path) do |f|
1817
      assert_equal "bar", f.pread(3, 4)
1818
      buf = "asdf"
1819
      assert_equal "bar", f.pread(3, 4, buf)
1820
      assert_equal "bar", buf
1821
      assert_raises(EOFError) { f.pread(1, f.size) }
1822
    end
1823
  end if IO.method_defined?(:pread)
1824

  
1825
  def test_pwrite
1826
    t = make_tempfile
1827

  
1828
    open(t.path, IO::RDWR) do |f|
1829
      assert_equal 3, f.pwrite(4, "ooo")
1830
      assert_equal "ooo", f.pread(3, 4)
1831
    end
1832
  end if IO.method_defined?(:pwrite) && IO.method_defined?(:pread)
1812 1833
end
1813
-