Project

General

Profile

Feature #4038 ยป IO-advise-7-kosaki.patch

kosaki (Motohiro KOSAKI), 12/16/2010 04:55 AM

View differences:

configure.in
1290 1290
fi
1291 1291
AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eaccess\
1292 1292
	      truncate ftruncate chsize times utimes utimensat fcntl lockf lstat\
1293
	      link symlink readlink readdir_r fsync fdatasync fchown\
1293
	      link symlink readlink readdir_r fsync fdatasync fchown posix_fadvise\
1294 1294
	      setitimer setruid seteuid setreuid setresuid setproctitle socketpair\
1295 1295
	      setrgid setegid setregid setresgid issetugid pause lchown lchmod\
1296 1296
	      getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
io.c
1

  
1 2
/**********************************************************************
2 3

  
3 4
  io.c -
......
7389 7390
}
7390 7391
#endif
7391 7392

  
7393
static VALUE sym_normal,   sym_sequential, sym_random,
7394
             sym_willneed, sym_dontneed, sym_noreuse;
7395

  
7396
#ifdef HAVE_POSIX_FADVISE
7397
struct io_advise_struct {
7398
    int fd;
7399
    off_t offset;
7400
    off_t len;
7401
    int advice;
7402
};
7403

  
7404
static VALUE
7405
io_advise_internal(void *arg)
7406
{
7407
    struct io_advise_struct *ptr = arg;
7408
    return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
7409
}
7410

  
7411
static VALUE io_advise_sym_to_const(VALUE sym)
7412
{
7413
#ifdef POSIX_FADV_NORMAL
7414
  if (sym == sym_normal)
7415
      return INT2NUM(POSIX_FADV_NORMAL);
7416
#endif
7417

  
7418
#ifdef POSIX_FADV_RANDOM
7419
  if (sym == sym_random)
7420
      return INT2NUM(POSIX_FADV_RANDOM);
7421
#endif
7422

  
7423
#ifdef POSIX_FADV_SEQUENTIAL
7424
  if (sym == sym_sequential)
7425
      return INT2NUM(POSIX_FADV_SEQUENTIAL);
7426
#endif
7427

  
7428
#ifdef POSIX_FADV_WILLNEED
7429
  if (sym == sym_willneed)
7430
      return INT2NUM(POSIX_FADV_WILLNEED);
7431
#endif
7432

  
7433
#ifdef POSIX_FADV_DONTNEED
7434
  if (sym == sym_dontneed)
7435
      return INT2NUM(POSIX_FADV_DONTNEED);
7436
#endif
7437

  
7438
#ifdef POSIX_FADV_NOREUSE
7439
  if (sym == sym_noreuse)
7440
      return INT2NUM(POSIX_FADV_NOREUSE);
7441
#endif
7442

  
7443
      return Qnil;
7444
}
7445

  
7446
static VALUE
7447
do_io_advise(VALUE io, VALUE advice, VALUE offset, VALUE len)
7448
{
7449
  int rv;
7450
  rb_io_t *fptr;
7451
  struct io_advise_struct ias;
7452
  VALUE num_adv;
7453

  
7454
  num_adv = io_advise_sym_to_const(advice);
7455

  
7456
  /*
7457
   * The platform doesn't support this hint. We don't raise exception, instead
7458
   * silently ignore it. Because IO::advise is only hint.
7459
   */
7460
  if (num_adv == Qnil)
7461
      return Qnil;
7462

  
7463
  io = GetWriteIO(io);
7464
  GetOpenFile(io, fptr);
7465

  
7466
  ias.fd     = fptr->fd;
7467
  ias.advice = NUM2INT(num_adv);
7468
  ias.offset = NIL_P(offset) ? 0 : NUM2OFFT(offset);
7469
  ias.len    = NIL_P(len)    ? 0 : NUM2OFFT(len);
7470

  
7471
  if (rv = (int)rb_thread_blocking_region(io_advise_internal, &ias, RUBY_UBF_IO, 0))
7472
      /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
7473
	 it returns the error code. */
7474
      rb_syserr_fail(rv, RSTRING_PTR(fptr->pathv));
7475

  
7476
  return Qnil;
7477
}
7478

  
7479
#endif /* HAVE_POSIX_FADVISE */
7480

  
7481
/*
7482
 *  call-seq:
7483
 *     ios.advise(advice, offset=0, len=0) -> nil
7484
 *
7485
 *  Announce an intention to access data from the current file in a
7486
 *  specific pattern. On platforms that do not support the
7487
 *  <em>posix_fadvise(2)</em> system call, this method is a no-op.
7488
 *
7489
 * _advice_ is one of the following symbols:
7490
 *
7491
 *  * :normal - No advice to give; the default assumption for an open file.
7492
 *  * :sequential - The data will be accessed sequentially:
7493
 *     with lower offsets read before higher ones.
7494
 *  * :random - The data will be accessed in random order.
7495
 *  * :willneed - The data will be accessed in the near future.
7496
 *  * :dontneed - The data will not be accessed in the near future.
7497
 *  * :noreuse - The data will only be accessed once.
7498
 *
7499
 * The semantics of a piece of advice are platform-dependent. See
7500
 * <em>man 2 posix_fadvise</em> for details.
7501
 *
7502
 *  "data" means the region of the current file that begins at
7503
 *  _offset_ and extends for _len_ bytes. If _len_ is 0, the region
7504
 *  ends at the last byte of the file. By default, both _offset_ and
7505
 *  _len_ are 0, meaning that the advice applies to the entire file.
7506
 *
7507
 *  If an error occurs, one of the following exceptions will be raised:
7508
 *
7509
 *  * <code>IOError</code> - The <code>IO</code> stream is closed.
7510
 *  * <code>Errno::EBADF</code> - The file descriptor of the current file is
7511
      invalid.
7512
 *  * <code>Errno::EINVAL</code> - An invalid value for _advice_ was given.
7513
 *  * <code>Errno::ESPIPE</code> - The file descriptor of the current
7514
 *  * file refers to a FIFO or pipe. (Linux raises <code>Errno::EINVAL</code>
7515
 *  * in this case).
7516
 *  * <code>TypeError</code> - Either _advice_ was not a Symbol, or one of the
7517
      other arguments was not an <code>Integer</code>.
7518
 *  * <code>RangeError</code> - One of the arguments given was too big/small.
7519
 *
7520
 * This list is not exhaustive; other Errno:: exceptions are also possible.
7521
 */
7522
static VALUE
7523
rb_io_advise(int argc, VALUE *argv, VALUE io)
7524
{
7525
  int rv;
7526
  VALUE advice, offset, len;
7527

  
7528
  rb_scan_args(argc, argv, "12", &advice, &offset, &len);
7529
  if (TYPE(advice) != T_SYMBOL)
7530
      rb_raise(rb_eTypeError, "advice must be a Symbol");
7531

  
7532
#ifdef HAVE_POSIX_FADVISE
7533
  return do_io_advise(io, advice, offset, len);
7534
#else
7535

  
7536
  /* for argument check. */
7537
  NUM2OFFT(offset);
7538
  NUM2OFFT(len);
7539

  
7540
  /* Ignore all hint */
7541
  return Qnil;
7542
#endif
7543
}
7544

  
7392 7545
/*
7393 7546
 *  call-seq:
7394 7547
 *     IO.select(read_array
......
10142 10295
    rb_define_method(rb_cIO, "binmode",  rb_io_binmode_m, 0);
10143 10296
    rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
10144 10297
    rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
10298
    rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
10145 10299

  
10146 10300
    rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
10147 10301
    rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
......
10318 10472
    sym_textmode = ID2SYM(rb_intern("textmode"));
10319 10473
    sym_binmode = ID2SYM(rb_intern("binmode"));
10320 10474
    sym_autoclose = ID2SYM(rb_intern("autoclose"));
10475
    sym_normal = ID2SYM(rb_intern("normal"));
10476
    sym_sequential = ID2SYM(rb_intern("sequential"));
10477
    sym_random = ID2SYM(rb_intern("random"));
10478
    sym_willneed = ID2SYM(rb_intern("willneed"));
10479
    sym_dontneed = ID2SYM(rb_intern("dontneed"));
10480
    sym_noreuse = ID2SYM(rb_intern("noreuse"));
10321 10481
}
test/ruby/test_io.rb
1722 1722
      end
1723 1723
    end
1724 1724
  end
1725

  
1726
  def test_advise
1727
    t = make_tempfile
1728
    assert_raise(ArgumentError, "no arguments") { t.advise }
1729
    %w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv|
1730
      [[0,0], [0, 20], [400, 2]].each do |offset, len|
1731
        open(make_tempfile.path) do |t|
1732
          assert_equal(t.advise(adv, offset, len), nil)
1733
          assert_raise(ArgumentError, "superfluous arguments") do
1734
            t.advise(adv, offset, len, offset)
1735
          end
1736
          assert_raise(TypeError, "wrong type for first argument") do
1737
            t.advise(adv.to_s, offset, len)
1738
          end
1739
          assert_raise(TypeError, "wrong type for last argument") do
1740
            t.advise(adv, offset, Array(len))
1741
          end
1742
          assert_raise(RangeError, "last argument too big") do
1743
            t.advise(adv, offset, 9999e99)
1744
          end
1745
        end
1746
        assert_raise(IOError, "closed file") do
1747
          make_tempfile.advise(adv.to_sym, offset, len)
1748
        end
1749
      end
1750
    end
1751
    %w{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv|
1752
      [[0,0], [0, 20], [400, 2]].each do |offset, len|
1753
        open(make_tempfile.path) do |t|
1754
          assert_equal(t.advise(adv, offset, len), nil)
1755
        end
1756
      end
1757
    end
1758
  end
1725 1759
end