Project

General

Profile

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

avsej (Sergey Avseyev), 01/27/2017 08:52 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
#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
4827
struct prdwr_internal_arg {
4828
    int fd;
4829
    void *buf;
4830
    size_t count;
4831
    off_t offset;
4832
    ssize_t len;
4833
};
4834
#endif /* HAVE_PREAD || HAVE_PWRITE */
4835

  
4836
#if defined(HAVE_PREAD)
4837
static VALUE
4838
internal_pread_func(void *arg)
4839
{
4840
    struct prdwr_internal_arg *p = arg;
4841
    return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
4842
}
4843

  
4844
static VALUE
4845
pread_internal_call(VALUE arg)
4846
{
4847
    struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
4848
    p->len = (ssize_t)rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
4849
    return Qundef;
4850
}
4851
#endif /* HAVE_PREAD */
4852

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

  
4883
    rb_scan_args(argc, argv, "21", &len, &offset, &str);
4884
    arg.count = NUM2SIZET(len);
4885
    arg.offset = NUM2OFFT(offset);
4886

  
4887
    io_setstrbuf(&str, (long)arg.count);
4888
    if (arg.count == 0) return str;
4889
    arg.buf = RSTRING_PTR(str);
4890

  
4891
    GetOpenFile(io, fptr);
4892
    rb_io_check_byte_readable(fptr);
4893

  
4894
    arg.fd = fptr->fd;
4895
    rb_io_check_closed(fptr);
4896

  
4897
    rb_str_locktmp(str);
4898
    rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
4899
    n = arg.len;
4900

  
4901
    if (n == -1) {
4902
	rb_sys_fail_path(fptr->pathv);
4903
    }
4904
    io_set_read_length(str, n);
4905
    if (n == 0 && arg.count > 0) {
4906
	rb_eof_error();
4907
    }
4908
    OBJ_TAINT(str);
4909

  
4910
    return str;
4911
#else
4912
    rb_raise(rb_eNotImpError, "pread() function is unimplemented on this machine");
4913
    return Qnil;
4914
#endif /* HAVE_PREAD */
4915
}
4916

  
4917
#if defined(HAVE_PWRITE)
4918
static VALUE
4919
internal_pwrite_func(void *ptr)
4920
{
4921
    struct prdwr_internal_arg *arg = ptr;
4922

  
4923
    return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
4924
}
4925
#endif /* HAVE_PWRITE */
4926

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

  
4953
    if (!RB_TYPE_P(str, T_STRING))
4954
	str = rb_obj_as_string(str);
4955

  
4956
    arg.buf = RSTRING_PTR(str);
4957
    arg.count = (size_t)RSTRING_LEN(str);
4958
    arg.offset = NUM2OFFT(offset);
4959

  
4960
    io = GetWriteIO(io);
4961
    GetOpenFile(io, fptr);
4962
    rb_io_check_writable(fptr);
4963
    arg.fd = fptr->fd;
4964

  
4965
    n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
4966
    RB_GC_GUARD(str);
4967

  
4968
    if (n == -1) rb_sys_fail_path(fptr->pathv);
4969

  
4970
    return LONG2FIX(n);
4971
#else
4972
    rb_raise(rb_eNotImpError, "pwrite() function is unimplemented on this machine");
4973
    return Qnil;
4974
#endif /* HAVE_PWRITE */
4975
}
4976

  
4826 4977
VALUE
4827 4978
rb_io_binmode(VALUE io)
4828 4979
{
......
12423 12574
    rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
12424 12575
    rb_define_method(rb_cIO, "sysread",  rb_io_sysread, -1);
12425 12576

  
12577
    rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
12578
    rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
12579

  
12426 12580
    rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
12427 12581
    rb_define_alias(rb_cIO, "to_i", "fileno");
12428 12582
    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 implemented."
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 implemented."
3531
    end
3507 3532
  end
3508 3533
end
3509
-