なかだです。

At Wed, 10 Dec 2003 03:04:00 +0900,
Yukihiro Matsumoto wrote:
> |そこで、IO を引数に取って内部に保存しておく IO::for_io (と
> |TCPServer#bind)があると次のようなことができて嬉しいのですが、
> |どうでしょう。
> 
> 個人的にはfdごとにreference countを持つことで元のIOがGCされ
> てもcountが0になるまでcloseを遅延するのはどうだろうかと考え
> ていました。面倒なので手つかずだったのですが。

こんなとこでどうでしょうか。socketのほうは手つかずですが。

* gc.c (obj_free), io.c (rb_io_fptr_finalize), rubyio.h (OpenFile):
  sharing OpenFile.

* io.c (rb_io_s_for_io): new method IO.for_io.  [ruby-dev:22195]


Index: gc.c =================================================================== RCS file: /cvs/ruby/src/ruby/gc.c,v retrieving revision 1.164 diff -u -2 -p -d -r1.164 gc.c --- gc.c 28 Nov 2003 14:23:31 -0000 1.164 +++ gc.c 10 Dec 2003 07:33:11 -0000 @@ -1145,5 +1145,4 @@ obj_free(obj) if (RANY(obj)->as.file.fptr) { rb_io_fptr_finalize(RANY(obj)->as.file.fptr); - RUBY_CRITICAL(free(RANY(obj)->as.file.fptr)); } break; Index: io.c =================================================================== RCS file: /cvs/ruby/src/ruby/io.c,v retrieving revision 1.240 diff -u -2 -p -d -r1.240 io.c --- io.c 9 Dec 2003 05:12:52 -0000 1.240 +++ io.c 10 Dec 2003 08:00:36 -0000 @@ -1389,4 +1389,5 @@ rb_io_fptr_finalize(fptr) { if (!fptr) return; + if (fptr->refcnt <= 0 || --fptr->refcnt) return; if (fptr->path) { free(fptr->path); @@ -1396,4 +1397,5 @@ rb_io_fptr_finalize(fptr) rb_io_fptr_cleanup(fptr, Qtrue); + free(fptr); } @@ -2944,4 +2946,25 @@ rb_io_s_for_fd(argc, argv, klass) } +static VALUE +rb_io_s_for_io(klass, io) + VALUE klass; + VALUE io; +{ + OpenFile *fptr; + VALUE obj; + + GetOpenFile(rb_io_get_io(io), fptr); + if (fptr->refcnt == LONG_MAX) { + VALUE s = rb_inspect(io); + rb_raise(rb_eIOError, "too many shared IO for %s", StringValuePtr(s)); + } + + obj = rb_obj_alloc(klass); + fptr->refcnt++; + RFILE(obj)->fptr = fptr; + + return obj; +} + static int binmode = 0; @@ -4058,4 +4081,5 @@ Init_IO() rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1); rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1); + rb_define_singleton_method(rb_cIO, "for_io", rb_io_s_for_io, 1); rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1); rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1); Index: rubyio.h =================================================================== RCS file: /cvs/ruby/src/ruby/rubyio.h,v retrieving revision 1.23 diff -u -2 -p -d -r1.23 rubyio.h --- rubyio.h 14 Apr 2003 09:04:43 -0000 1.23 +++ rubyio.h 10 Dec 2003 07:45:40 -0000 @@ -25,4 +25,5 @@ typedef struct OpenFile { char *path; /* pathname for file */ void (*finalize) _((struct OpenFile*,int)); /* finalize proc */ + long refcnt; } OpenFile; @@ -51,4 +52,5 @@ typedef struct OpenFile { fp->path = NULL;\ fp->finalize = 0;\ + fp->refcnt = 1;\ } while (0)
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦