diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-03-10 04:35:06 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-03-10 04:35:06 +0000 |
commit | 3721229d20880694f3c5a3a7a3fa401b19c5870b (patch) | |
tree | fd22b9e7c5b536c67efbd8a3ce74f583e5f29e58 | |
parent | 5905791c3373cf9cd1fce4da28acf9b16f721c3a (diff) | |
download | sleepy_penguin-3721229d20880694f3c5a3a7a3fa401b19c5870b.tar.gz |
close(2) on inotify descriptors takes forever and a day.
-rw-r--r-- | ext/sleepy_penguin/inotify.c | 40 | ||||
-rw-r--r-- | test/test_inotify.rb | 23 |
2 files changed, 62 insertions, 1 deletions
diff --git a/ext/sleepy_penguin/inotify.c b/ext/sleepy_penguin/inotify.c index a08bf15..6c126b4 100644 --- a/ext/sleepy_penguin/inotify.c +++ b/ext/sleepy_penguin/inotify.c @@ -3,6 +3,11 @@ #include <sys/inotify.h> #include <sys/ioctl.h> #include "missing_inotify.h" +#if defined(RFILE) && defined(HAVE_ST_FD) && \ + defined(HAVE_RB_THREAD_BLOCKING_REGION) +# define NOGVL_CLOSE +#endif + static ID id_for_fd, id_inotify_buf, id_inotify_tmp, id_mask; static VALUE cEvent, checks; @@ -265,7 +270,7 @@ static VALUE init_copy(VALUE dest, VALUE orig) /* * call-seq: - * ino.each { |event| ... } -> ino + * ino.each { |event| ... } -> ino * * Yields each Inotify::Event received in a blocking fashion. */ @@ -279,6 +284,36 @@ static VALUE each(VALUE self) return self; } +#if defined(NOGVL_CLOSE) +static VALUE fptr_close(void *ptr) +{ + rb_io_t *fptr = ptr; + return (VALUE)close(fptr->fd); +} + +/* + * call-seq: + * ino.close -> nil + * + * Closes the underlying file descriptor and releases resources used by the + * kernel. Unlike other file descriptors, Inotify descriptors can take + * a long time to close(2). Calling this explicitly releases the GVL under + * Ruby 1.9 + */ +static VALUE nogvl_close(VALUE self) +{ + rb_io_t *fptr; + + GetOpenFile(self, fptr); + + if ((int)rb_sp_io_region(fptr_close, fptr) < 0) + rb_sys_fail("close(inotify)"); + fptr->fd = -1; + + return Qnil; +} +#endif /* NOGVL_CLOSE */ + void sleepy_penguin_init_inotify(void) { VALUE mSleepyPenguin, cInotify; @@ -311,6 +346,9 @@ void sleepy_penguin_init_inotify(void) rb_define_method(cInotify, "initialize_copy", init_copy, 1); rb_define_method(cInotify, "take", take, -1); rb_define_method(cInotify, "each", each, 0); +#ifdef NOGVL_CLOSE + rb_define_method(cInotify, "close", nogvl_close, 0); +#endif /* * Document-class: SleepyPenguin::Inotify::Event diff --git a/test/test_inotify.rb b/test/test_inotify.rb index a003baf..1a5d5d1 100644 --- a/test/test_inotify.rb +++ b/test/test_inotify.rb @@ -115,4 +115,27 @@ class TestInotify < Test::Unit::TestCase end assert_equal 0, nr end + + def test_close_threadable + ino = Inotify.new + tmp = [] + thr = Thread.new do + until ino.closed? + tmp << Time.now + Thread.pass + end + end + t0 = Time.now + ino.close + t1 = Time.now + between = [] + thr.join + tmp.each do |t| + if t > t0 && t < t1 + between << t + end + end + assert tmp.size > 0, "tmp.size=#{tmp.size}" + assert between.size > 0, "between.size=#{between.size}" + end if RUBY_VERSION.to_f >= 1.9 end |