Project

General

Profile

Feature #4532 ยป 0001-Add-IO-pread-and-IO-pwrite-methods.patch

Updated patch, for current trunk (57443) - avsej (Sergey Avseyev), 01/27/2017 08:29 PM

View differences:

configure.in
2396 2396
AC_CHECK_FUNCS(posix_memalign)
2397 2397
AC_CHECK_FUNCS(ppoll)
2398 2398
AC_CHECK_FUNCS(pread)
2399
AC_CHECK_FUNCS(pwrite)
2399 2400
AC_CHECK_FUNCS(qsort_r)
2400 2401
AC_CHECK_FUNCS(qsort_s)
2401 2402
AC_CHECK_FUNCS(readlink)
io.c
4823 4823
    return str;
4824 4824
}
4825 4825

  
4826
struct prdwr_internal_arg {
4827
    int fd;
4828
    void *buf;
4829
    size_t count;
4830
    off_t offset;
4831
    ssize_t len;
4832
};
4833

  
4834
static VALUE
4835
internal_pread_func(void *arg)
4836
{
4837
    struct prdwr_internal_arg *p = arg;
4838
    return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
4839
}
4840

  
4841
static VALUE
4842
pread_internal_call(VALUE arg)
4843
{
4844
    struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
4845
    p->len = (ssize_t)rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
4846
    return Qundef;
4847
}
4848

  
4849
/*
4850
 *  call-seq:
4851
 *     ios.pread(maxlen, offset[, outbuf])    -> string
4852
 *
4853
 *  Reads <i>maxlen</i> bytes from <em>ios</em> using the pread system call
4854
 *  and returns them as a string without modifying the underlying
4855
 *  descriptor offset.  This is advantageous compared to combining IO#seek
4856
 *  and IO#read in that it is atomic, allowing multiple threads/process to
4857
 *  share the same IO object for reading the file at various locations.
4858
 *  This bypasses any userspace buffering of the IO layer.
4859
 *  If the optional <i>outbuf</i> argument is present, it must
4860
 *  reference a String, which will receive the data.
4861
 *  Raises <code>SystemCallError</code> on error, <code>EOFError</code>
4862
 *  at end of file and <code>NotImplementedError</code> if platform does not
4863
 *  implement the system call.
4864
 *
4865
 *     f = File.new("testfile")
4866
 *     f.read           #=> "This is line one\nThis is line two\n"
4867
 *     f.pread(12, 0)   #=> "This is line"
4868
 *     f.pread(9, 8)    #=> "line one\n"
4869
 */
4870
static VALUE
4871
rb_io_pread(int argc, VALUE *argv, VALUE io)
4872
{
4873
    VALUE len, offset, str;
4874
    rb_io_t *fptr;
4875
    ssize_t n;
4876
    struct prdwr_internal_arg arg;
4877

  
4878
#if defined(HAVE_PREAD)
4879
    rb_scan_args(argc, argv, "21", &len, &offset, &str);
4880
    arg.count = NUM2SIZET(len);
4881
    arg.offset = NUM2OFFT(offset);
4882

  
4883
    io_setstrbuf(&str, (long)arg.count);
4884
    if (arg.count == 0) return str;
4885
    arg.buf = RSTRING_PTR(str);
4886

  
4887
    GetOpenFile(io, fptr);
4888
    rb_io_check_byte_readable(fptr);
4889

  
4890
    arg.fd = fptr->fd;
4891
    rb_io_check_closed(fptr);
4892

  
4893
    rb_str_locktmp(str);
4894
    rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
4895
    n = arg.len;
4896

  
4897
    if (n == -1) {
4898
	rb_sys_fail_path(fptr->pathv);
4899
    }
4900
    io_set_read_length(str, n);
4901
    if (n == 0 && arg.count > 0) {
4902
	rb_eof_error();
4903
    }
4904
    OBJ_TAINT(str);
4905

  
4906
    return str;
4907
#else
4908
    rb_raise(rb_eNotImpError, "pread() function is unimplemented on this machine");
4909
    return Qnil;
4910
#endif /* HAVE_PREAD */
4911
}
4912

  
4913
static VALUE
4914
internal_pwrite_func(void *ptr)
4915
{
4916
    struct prdwr_internal_arg *arg = ptr;
4917

  
4918
    return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
4919
}
4920

  
4921
/*
4922
 *  call-seq:
4923
 *     ios.pwrite(string, offset)    -> integer
4924
 *
4925
 *  Writes the given string to <em>ios</em> at <i>offset</i> using pwrite()
4926
 *  system call.  This is advantageous to combining IO#seek and IO#write
4927
 *  in that it is atomic, allowing multiple threads/process to share the
4928
 *  same IO object for reading the file at various locations.
4929
 *  This bypasses any userspace buffering of the IO layer.
4930
 *  Returns the number of bytes written.
4931
 *  Raises <code>SystemCallError</code> on error and <code>NotImplementedError</code>
4932
 *  if platform does not implement the system call.
4933
 *
4934
 *     f = File.new("out", "w")
4935
 *     f.pwrite("ABCDEF", 3)   #=> 6
4936
 *
4937
 *     File.read("out")        #=> "\u0000\u0000\u0000ABCDEF"
4938
 */
4939
static VALUE
4940
rb_io_pwrite(VALUE io, VALUE offset, VALUE str)
4941
{
4942
    rb_io_t *fptr;
4943
    ssize_t n;
4944
    struct prdwr_internal_arg arg;
4945

  
4946
#if defined(HAVE_PWRITE)
4947
    if (!RB_TYPE_P(str, T_STRING))
4948
	str = rb_obj_as_string(str);
4949

  
4950
    arg.buf = RSTRING_PTR(str);
4951
    arg.count = (size_t)RSTRING_LEN(str);
4952
    arg.offset = NUM2OFFT(offset);
4953

  
4954
    io = GetWriteIO(io);
4955
    GetOpenFile(io, fptr);
4956
    rb_io_check_writable(fptr);
4957
    arg.fd = fptr->fd;
4958

  
4959
    n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
4960
    RB_GC_GUARD(str);
4961

  
4962
    if (n == -1) rb_sys_fail_path(fptr->pathv);
4963

  
4964
    return LONG2FIX(n);
4965
#else
4966
    rb_raise(rb_eNotImpError, "pwrite() function is unimplemented on this machine");
4967
    return Qnil;
4968
#endif /* HAVE_PWRITE */
4969
}
4970

  
4826 4971
VALUE
4827 4972
rb_io_binmode(VALUE io)
4828 4973
{
......
12423 12568
    rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
12424 12569
    rb_define_method(rb_cIO, "sysread",  rb_io_sysread, -1);
12425 12570

  
12571
    rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
12572
    rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
12573

  
12426 12574
    rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
12427 12575
    rb_define_alias(rb_cIO, "to_i", "fileno");
12428 12576
    rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
test/ruby/test_io.rb
3504 3504
        end
3505 3505
      end
3506 3506
    end
3507

  
3508
    def test_pread
3509
      make_tempfile { |t|
3510
        open(t.path) do |f|
3511
          assert_equal("bar", f.pread(3, 4))
3512
          buf = "asdf"
3513
          assert_equal("bar", f.pread(3, 4, buf))
3514
          assert_equal("bar", buf)
3515
          assert_raise(EOFError) { f.pread(1, f.size) }
3516
        end
3517
      }
3518
    rescue NotImplementedError
3519
      skip "pread(2) is not implemtented."
3520
    end
3521

  
3522
    def test_pwrite
3523
      make_tempfile { |t|
3524
        open(t.path, IO::RDWR) do |f|
3525
          assert_equal(3, f.pwrite(4, "ooo"))
3526
          assert_equal("ooo", f.pread(3, 4))
3527
        end
3528
      }
3529
    rescue NotImplementedError
3530
      skip "pwrite(2) and pread(2) are not implemtented."
3531
    end
3507 3532
  end
3508 3533
end
3509
-