Project

General

Profile

Feature #4532 » 0001-add-IO-pread-and-IO-pwrite-methods.patch

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

View differences:

configure.in
setsid telldir seekdir fchmod cosh sinh tanh log2 round\
setuid setgid daemon select_large_fdset setenv unsetenv\
mktime timegm gmtime_r clock_gettime gettimeofday\
pread sendfile shutdown sigaltstack dl_iterate_phdr)
pread pwrite sendfile shutdown sigaltstack dl_iterate_phdr)
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
[AC_TRY_COMPILE([
io.c
return LONG2FIX(n);
}
#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
struct prdwr_args {
int fd;
void *buf;
size_t count;
off_t offset;
};
#endif
#if defined(HAVE_PREAD)
static VALUE
nogvl_pread(void *ptr)
{
struct prdwr_args *args = ptr;
return (VALUE)pread(args->fd, args->buf, args->count, args->offset);
}
/*
* call-seq:
* ios.pread(maxlen, offset[, outbuf]) -> string
*
* Reads <i>maxlen</i> bytes from <em>ios</em> using the pread system call
* and returns them as a string without modifying the underlying
* descriptor offset. This is advantageous compared to combining IO#seek
* and IO#read in that it is atomic, allowing multiple threads/process to
* share the same IO object for reading the file at various locations.
* This bypasses any userspace buffering of the IO layer.
* If the optional <i>outbuf</i> argument is present, it must
* reference a String, which will receive the data.
* Raises <code>SystemCallError</code> on error and <code>EOFError</code>
* at end of file.
* Not implemented on all platforms.
*
* f = File.new("testfile")
* f.pread(16, 0) #=> "This is line one"
*/
static VALUE
rb_io_pread(int argc, VALUE *argv, VALUE io)
{
VALUE len, offset, str;
rb_io_t *fptr;
ssize_t n;
struct prdwr_args args;
rb_scan_args(argc, argv, "21", &len, &offset, &str);
args.count = NUM2SIZET(len);
args.offset = NUM2OFFT(offset);
io_setstrbuf(&str, (long)args.count);
if (args.count == 0) return str;
args.buf = RSTRING_PTR(str);
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
args.fd = fptr->fd;
rb_io_check_closed(fptr);
rb_str_locktmp(str);
n = (ssize_t)rb_thread_io_blocking_region(nogvl_pread, &args, fptr->fd);
rb_str_unlocktmp(str);
if (n == -1) {
rb_sys_fail_path(fptr->pathv);
}
rb_str_set_len(str, n);
if (n == 0 && args.count > 0) {
rb_eof_error();
}
rb_str_resize(str, n);
OBJ_TAINT(str);
return str;
}
#endif /* HAVE_PREAD */
#if defined(HAVE_PWRITE)
static VALUE
nogvl_pwrite(void *ptr)
{
struct prdwr_args *args = ptr;
return (VALUE)pwrite(args->fd, args->buf, args->count, args->offset);
}
/*
* call-seq:
* ios.pwrite(offset, string) -> integer
*
* Writes the given string to <em>ios</em> at <i>offset</i> using pwrite()
* system call. This is advantageous to combining IO#seek and IO#write
* in that it is atomic, allowing multiple threads/process to share the
* same IO object for reading the file at various locations.
* This bypasses any userspace buffering of the IO layer.
* Returns the number of bytes written.
* Raises <code>SystemCallError</code> on error.
*
* f = File.new("out", "w")
* f.pwrite(3, "ABCDEF") #=> 6
*/
static VALUE
rb_io_pwrite(VALUE io, VALUE offset, VALUE string)
{
rb_io_t *fptr;
ssize_t n;
struct prdwr_args args;
rb_secure(4);
string = rb_obj_as_string(string);
args.buf = RSTRING_PTR(string);
args.count = (size_t)RSTRING_LEN(string);
args.offset = NUM2OFFT(offset);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
args.fd = fptr->fd;
n = (ssize_t)rb_thread_io_blocking_region(nogvl_pwrite, &args, fptr->fd);
if (n == -1) rb_sys_fail_path(fptr->pathv);
return SSIZET2NUM(n);
}
#endif /* HAVE_PWRITE */
/*
* call-seq:
* ios.sysread(maxlen[, outbuf]) -> string
......
rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
#ifdef HAVE_PREAD
rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
#endif
#ifdef HAVE_PWRITE
rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
#endif
rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
test/ruby/test_io.rb
Process.waitpid2(pid)
end
end
def test_pread
t = make_tempfile
open(t.path) do |f|
assert_equal "bar", f.pread(3, 4)
buf = "asdf"
assert_equal "bar", f.pread(3, 4, buf)
assert_equal "bar", buf
assert_raises(EOFError) { f.pread(1, f.size) }
end
end if IO.method_defined?(:pread)
def test_pwrite
t = make_tempfile
open(t.path, IO::RDWR) do |f|
assert_equal 3, f.pwrite(4, "ooo")
assert_equal "ooo", f.pread(3, 4)
end
end if IO.method_defined?(:pwrite) && IO.method_defined?(:pread)
end
(1-1/3)