[#33640] [Ruby 1.9-Bug#4136][Open] Enumerable#reject should not inherit the receiver's instance variables — Hiro Asari <redmine@...>

Bug #4136: Enumerable#reject should not inherit the receiver's instance variables

10 messages 2010/12/08

[#33667] [Ruby 1.9-Bug#4149][Open] Documentation submission: syslog standard library — mathew murphy <redmine@...>

Bug #4149: Documentation submission: syslog standard library

11 messages 2010/12/10

[#33683] [feature:trunk] Enumerable#categorize — Tanaka Akira <akr@...>

Hi.

14 messages 2010/12/12
[#33684] Re: [feature:trunk] Enumerable#categorize — "Martin J. Dst" <duerst@...> 2010/12/12

[#33687] Towards a standardized AST for Ruby code — Magnus Holm <judofyr@...>

Hey folks,

23 messages 2010/12/12
[#33688] Re: Towards a standardized AST for Ruby code — Charles Oliver Nutter <headius@...> 2010/12/12

On Sun, Dec 12, 2010 at 9:55 AM, Magnus Holm <judofyr@gmail.com> wrote:

[#33689] Re: Towards a standardized AST for Ruby code — "Haase, Konstantin" <Konstantin.Haase@...> 2010/12/12

On Dec 12, 2010, at 17:46 , Charles Oliver Nutter wrote:

[#33763] [Ruby 1.9-Bug#4168][Open] WeakRef is unsafe to use in Ruby 1.9 — Brian Durand <redmine@...>

Bug #4168: WeakRef is unsafe to use in Ruby 1.9

43 messages 2010/12/17

[#33815] trunk warnflags build issue with curb 0.7.9? — Jon <jon.forums@...>

As this may turn out to be a 3rd party issue rather than a bug, I'd like some feedback.

11 messages 2010/12/22

[#33833] Ruby 1.9.2 is going to be released — "Yuki Sonoda (Yugui)" <yugui@...>

-----BEGIN PGP SIGNED MESSAGE-----

15 messages 2010/12/23

[#33846] [Ruby 1.9-Feature#4197][Open] Improvement of the benchmark library — Benoit Daloze <redmine@...>

Feature #4197: Improvement of the benchmark library

15 messages 2010/12/23

[#33910] [Ruby 1.9-Feature#4211][Open] Converting the Ruby and C API documentation to YARD syntax — Loren Segal <redmine@...>

Feature #4211: Converting the Ruby and C API documentation to YARD syntax

10 messages 2010/12/26

[#33923] [Ruby 1.9-Bug#4214][Open] Fiddle::WINDOWS == false on Windows — Jon Forums <redmine@...>

Bug #4214: Fiddle::WINDOWS == false on Windows

15 messages 2010/12/27

[ruby-core:33734] [Ruby 1.9-Feature#4038] IO#advise

From: Motohiro KOSAKI <redmine@...>
Date: 2010-12-15 18:45:48 UTC
List: ruby-core #33734
Issue #4038 has been updated by Motohiro KOSAKI.

File IO-advise-6-kosaki.patch added

I've modified the patch slightly. Now IO#advise makes noop instead undefined behavior if the platform doesn't support the advise.

My point is, If the method can make undefined behavior, many developer strongly want to avoid it and they want to know which
advise is implemented. I'd like to remove such unnecessary fear.

Thanks.

- kosaki

----------------------------------------
http://redmine.ruby-lang.org/issues/show/4038

----------------------------------------
http://redmine.ruby-lang.org

Attachments (1)

IO-advise-6-kosaki.patch (7.66 KB, text/x-diff)
---
 configure.in         |    2 +-
 io.c                 |  146 ++++++++++++++++++++++++++++++++++++++++++++++++++
 test/ruby/test_io.rb |   34 ++++++++++++
 3 files changed, 181 insertions(+), 1 deletions(-)

diff --git a/configure.in b/configure.in
index 26ab974..c25fd16 100644
--- a/configure.in
+++ b/configure.in
@@ -1290,7 +1290,7 @@ else
 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\
diff --git a/io.c b/io.c
index d5d1220..f69973e 100644
--- a/io.c
+++ b/io.c
@@ -1,3 +1,4 @@
+
 /**********************************************************************
 
   io.c -
@@ -7389,6 +7390,144 @@ select_end(VALUE arg)
 }
 #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
@@ -10142,6 +10281,7 @@ Init_IO(void)
     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);
@@ -10318,4 +10458,10 @@ Init_IO(void)
     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"));
 }
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index 73a16de..c7dbb6d 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -1722,4 +1722,38 @@ End
       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
-- 
1.7.0.1

In This Thread