Feature #4038 » IO-advise-6-kosaki.patch
configure.in | ||
---|---|---|
fi
|
||
AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eaccess\
|
||
truncate ftruncate chsize times utimes utimensat fcntl lockf lstat\
|
||
link symlink readlink readdir_r fsync fdatasync fchown\
|
||
link symlink readlink readdir_r fsync fdatasync fchown posix_fadvise\
|
||
setitimer setruid seteuid setreuid setresuid setproctitle socketpair\
|
||
setrgid setegid setregid setresgid issetugid pause lchown lchmod\
|
||
getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
|
io.c | ||
---|---|---|
/**********************************************************************
|
||
io.c -
|
||
... | ... | |
}
|
||
#endif
|
||
struct io_advise_struct {
|
||
int fd;
|
||
off_t offset;
|
||
off_t len;
|
||
int advice;
|
||
};
|
||
static VALUE sym_normal, sym_sequential, sym_random,
|
||
sym_willneed, sym_dontneed, sym_noreuse;
|
||
static VALUE
|
||
io_advise_internal(void *arg)
|
||
{
|
||
struct io_advise_struct *ptr = arg;
|
||
return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
|
||
}
|
||
static VALUE io_advise_sym_to_const(VALUE sym)
|
||
{
|
||
#ifdef POSIX_FADV_NORMAL
|
||
if (sym == sym_normal)
|
||
return INT2NUM(POSIX_FADV_NORMAL);
|
||
#endif
|
||
#ifdef POSIX_FADV_RANDOM
|
||
if (sym == sym_random)
|
||
return INT2NUM(POSIX_FADV_RANDOM);
|
||
#endif
|
||
#ifdef POSIX_FADV_SEQUENTIAL
|
||
if (sym == sym_sequential)
|
||
return INT2NUM(POSIX_FADV_SEQUENTIAL);
|
||
#endif
|
||
#ifdef POSIX_FADV_WILLNEED
|
||
if (sym == sym_willneed)
|
||
return INT2NUM(POSIX_FADV_WILLNEED);
|
||
#endif
|
||
#ifdef POSIX_FADV_DONTNEED
|
||
if (sym == sym_dontneed)
|
||
return INT2NUM(POSIX_FADV_DONTNEED);
|
||
#endif
|
||
#ifdef POSIX_FADV_NOREUSE
|
||
if (sym == sym_noreuse)
|
||
return INT2NUM(POSIX_FADV_NOREUSE);
|
||
#endif
|
||
return Qnil;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* ios.advise(advice, offset=0, len=0) -> nil
|
||
*
|
||
* Announce an intention to access data from the current file in a
|
||
* specific pattern. On platforms that do not support the
|
||
* <em>posix_fadvise(2)</em> system call, this method is a no-op.
|
||
*
|
||
* _advice_ is one of the following symbols:
|
||
*
|
||
* * :normal - No advice to give; the default assumption for an open file.
|
||
* * :sequential - The data will be accessed sequentially:
|
||
* with lower offsets read before higher ones.
|
||
* * :random - The data will be accessed in random order.
|
||
* * :willneed - The data will be accessed in the near future.
|
||
* * :dontneed - The data will not be accessed in the near future.
|
||
* * :noreuse - The data will only be accessed once.
|
||
*
|
||
* The semantics of a piece of advice are platform-dependent. See
|
||
* <em>man 2 posix_fadvise</em> for details.
|
||
*
|
||
* "data" means the region of the current file that begins at
|
||
* _offset_ and extends for _len_ bytes. If _len_ is 0, the region
|
||
* ends at the last byte of the file. By default, both _offset_ and
|
||
* _len_ are 0, meaning that the advice applies to the entire file.
|
||
*
|
||
* If an error occurs, one of the following exceptions will be raised:
|
||
*
|
||
* * <code>IOError</code> - The <code>IO</code> stream is closed.
|
||
* * <code>Errno::EBADF</code> - The file descriptor of the current file is
|
||
invalid.
|
||
* * <code>Errno::EINVAL</code> - An invalid value for _advice_ was given.
|
||
* * <code>Errno::ESPIPE</code> - The file descriptor of the current
|
||
* * file refers to a FIFO or pipe. (Linux raises <code>Errno::EINVAL</code>
|
||
* * in this case).
|
||
* * <code>TypeError</code> - Either _advice_ was not a Symbol, or one of the
|
||
other arguments was not an <code>Integer</code>.
|
||
* * <code>RangeError</code> - One of the arguments given was too big/small.
|
||
*
|
||
* This list is not exhaustive; other Errno:: exceptions are also possible.
|
||
*/
|
||
static VALUE
|
||
rb_io_advise(int argc, VALUE *argv, VALUE io)
|
||
{
|
||
#ifdef HAVE_POSIX_FADVISE
|
||
int rv;
|
||
VALUE initadvice, initoffset, initlen;
|
||
rb_io_t *fptr;
|
||
struct io_advise_struct ias;
|
||
VALUE advice;
|
||
rb_scan_args(argc, argv, "12", &initadvice, &initoffset, &initlen);
|
||
if (TYPE(initadvice) != T_SYMBOL)
|
||
rb_raise(rb_eTypeError, "advice must be a Symbol");
|
||
advice = io_advise_sym_to_const(initadvice);
|
||
/*
|
||
* The platform doesn't support this hint. We don't raise exception, instead
|
||
* silently ignore it. Because IO::advise is only hint.
|
||
*/
|
||
if (advice == Qnil)
|
||
return Qnil;
|
||
io = GetWriteIO(io);
|
||
GetOpenFile(io, fptr);
|
||
ias.fd = fptr->fd;
|
||
ias.advice = NUM2INT(advice);
|
||
ias.offset = NIL_P(initoffset) ? 0 : NUM2OFFT(initoffset);
|
||
ias.len = NIL_P(initlen) ? 0 : NUM2OFFT(initlen);
|
||
if (rv = (int)rb_thread_blocking_region(io_advise_internal, &ias, RUBY_UBF_IO, 0))
|
||
/* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
|
||
it returns the error code. */
|
||
rb_syserr_fail(rv, RSTRING_PTR(fptr->pathv));
|
||
return Qnil;
|
||
#else /* HAVE_POSIX_FADVISE */
|
||
/* Ignore all hint */
|
||
return Qnil;
|
||
#endif
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* IO.select(read_array
|
||
... | ... | |
rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
|
||
rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
|
||
rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
|
||
rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
|
||
rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
|
||
rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
|
||
... | ... | |
sym_textmode = ID2SYM(rb_intern("textmode"));
|
||
sym_binmode = ID2SYM(rb_intern("binmode"));
|
||
sym_autoclose = ID2SYM(rb_intern("autoclose"));
|
||
sym_normal = ID2SYM(rb_intern("normal"));
|
||
sym_sequential = ID2SYM(rb_intern("sequential"));
|
||
sym_random = ID2SYM(rb_intern("random"));
|
||
sym_willneed = ID2SYM(rb_intern("willneed"));
|
||
sym_dontneed = ID2SYM(rb_intern("dontneed"));
|
||
sym_noreuse = ID2SYM(rb_intern("noreuse"));
|
||
}
|
test/ruby/test_io.rb | ||
---|---|---|
end
|
||
end
|
||
end
|
||
def test_advise
|
||
t = make_tempfile
|
||
assert_raise(ArgumentError, "no arguments") { t.advise }
|
||
%w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv|
|
||
[[0,0], [0, 20], [400, 2]].each do |offset, len|
|
||
open(make_tempfile.path) do |t|
|
||
assert_equal(t.advise(adv, offset, len), nil)
|
||
assert_raise(ArgumentError, "superfluous arguments") do
|
||
t.advise(adv, offset, len, offset)
|
||
end
|
||
assert_raise(TypeError, "wrong type for first argument") do
|
||
t.advise(adv.to_s, offset, len)
|
||
end
|
||
assert_raise(TypeError, "wrong type for last argument") do
|
||
t.advise(adv, offset, Array(len))
|
||
end
|
||
assert_raise(RangeError, "last argument too big") do
|
||
t.advise(adv, offset, 9999e99)
|
||
end
|
||
end
|
||
assert_raise(IOError, "closed file") do
|
||
make_tempfile.advise(adv.to_sym, offset, len)
|
||
end
|
||
end
|
||
end
|
||
%w{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv|
|
||
[[0,0], [0, 20], [400, 2]].each do |offset, len|
|
||
open(make_tempfile.path) do |t|
|
||
assert_equal(t.advise(adv, offset, len), nil)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|