ruby-changes:6758
From: nobu <ko1@a...>
Date: Thu, 31 Jul 2008 01:07:41 +0900 (JST)
Subject: [ruby-changes:6758] Ruby:r18274 (mvm): * merged from trunk r18206:18273.
nobu 2008-07-31 01:06:57 +0900 (Thu, 31 Jul 2008) New Revision: 18274 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18274 Log: * merged from trunk r18206:18273. Added files: branches/mvm/ext/win32ole/sample/ienavi2.rb branches/mvm/test/rss/dot.png branches/mvm/test/ruby/enc/test_koi8.rb branches/mvm/test/ruby/test_sleep.rb branches/mvm/test/win32ole/err_in_callback.rb branches/mvm/test/win32ole/test_err_in_callback.rb Removed files: branches/mvm/test/ruby/test_koi8.rb Modified files: branches/mvm/.merged-trunk-revision branches/mvm/ChangeLog branches/mvm/bootstraptest/test_method.rb branches/mvm/dir.c branches/mvm/dln.c branches/mvm/dln.h branches/mvm/ext/bigdecimal/bigdecimal.c branches/mvm/ext/win32ole/win32ole.c branches/mvm/file.c branches/mvm/gc.c branches/mvm/include/ruby/ruby.h branches/mvm/io.c branches/mvm/lib/rinda/tuplespace.rb branches/mvm/lib/webrick/httputils.rb branches/mvm/math.c branches/mvm/pack.c branches/mvm/parse.y branches/mvm/proc.c branches/mvm/regint.h branches/mvm/regparse.c branches/mvm/sample/exyacc.rb branches/mvm/string.c branches/mvm/test/etc/test_etc.rb branches/mvm/test/openssl/test_ssl.rb branches/mvm/test/rinda/test_rinda.rb branches/mvm/test/rss/rss-assertions.rb branches/mvm/test/rss/test_atom.rb branches/mvm/test/ruby/test_io.rb branches/mvm/test/ruby/test_io_m17n.rb branches/mvm/test/ruby/test_math.rb branches/mvm/test/ruby/test_require.rb branches/mvm/test/win32ole/test_win32ole_event.rb branches/mvm/thread.c branches/mvm/version.h branches/mvm/vm.c branches/mvm/vm_core.h branches/mvm/win32/win32.c Index: mvm/regparse.c =================================================================== --- mvm/regparse.c (revision 18273) +++ mvm/regparse.c (revision 18274) @@ -729,7 +729,10 @@ CHECK_NULL_RETURN_MEMERR(e); e->name = strdup_with_null(reg->enc, name, name_end); - if (IS_NULL(e->name)) return ONIGERR_MEMORY; + if (IS_NULL(e->name)) { + xfree(e); + return ONIGERR_MEMORY; + } onig_st_insert_strend(t, e->name, (e->name + (name_end - name)), (HashDataType )e); @@ -5392,6 +5395,9 @@ if (r == 0) { *targetp = qn; } + else if (r == 1) { + onig_node_free(qn); + } else if (r == 2) { /* split case: /abc+/ */ Node *tmp; Index: mvm/math.c =================================================================== --- mvm/math.c (revision 18273) +++ mvm/math.c (revision 18274) @@ -51,6 +51,24 @@ } } +static void +infinity_check(VALUE arg, double res, const char *msg) +{ + while(1) { + if (errno) { + rb_sys_fail(msg); + } + if (isinf(res) && !isinf(RFLOAT_VALUE(arg))) { +#if defined(EDOM) + errno = EDOM; +#elif defined(ERANGE) + errno = ERANGE; +#endif + continue; + } + break; + } +} /* * call-seq: @@ -286,6 +304,7 @@ errno = 0; d = atanh(RFLOAT_VALUE(x)); domain_check(d, "atanh"); + infinity_check(x, d, "atanh"); return DOUBLE2NUM(d); } @@ -337,6 +356,7 @@ d /= log(RFLOAT_VALUE(base)); } domain_check(d, "log"); + infinity_check(x, d, "log"); return DOUBLE2NUM(d); } @@ -367,9 +387,8 @@ Need_Float(x); errno = 0; d = log2(RFLOAT_VALUE(x)); - if (errno) { - rb_sys_fail("log2"); - } + domain_check(d, "log2"); + infinity_check(x, d, "log2"); return DOUBLE2NUM(d); } @@ -389,6 +408,7 @@ errno = 0; d = log10(RFLOAT_VALUE(x)); domain_check(d, "log10"); + infinity_check(x, d, "log10"); return DOUBLE2NUM(d); } Index: mvm/include/ruby/ruby.h =================================================================== --- mvm/include/ruby/ruby.h (revision 18273) +++ mvm/include/ruby/ruby.h (revision 18274) @@ -302,6 +302,7 @@ RUBY_T_UNDEF = 0x1b, RUBY_T_NODE = 0x1c, RUBY_T_ICLASS = 0x1d, + RUBY_T_DEFERRED = 0x1e, RUBY_T_MASK = 0x1f }; @@ -330,6 +331,7 @@ #define T_COMPLEX RUBY_T_COMPLEX #define T_UNDEF RUBY_T_UNDEF #define T_NODE RUBY_T_NODE +#define T_DEFERRED RUBY_T_DEFERRED #define T_MASK RUBY_T_MASK #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) Index: mvm/ChangeLog =================================================================== --- mvm/ChangeLog (revision 18273) +++ mvm/ChangeLog (revision 18274) @@ -1,3 +1,246 @@ +Thu Jul 31 00:58:33 2008 Nobuyoshi Nakada <nobu@r...> + + * pack.c (pack_unpack): reduced static variables. + +Thu Jul 31 00:10:20 2008 Yusuke Endoh <mame@t...> + + * proc.c (rb_proc_call_with_block): prevent null reference. + +Wed Jul 30 22:19:13 2008 Yusuke Endoh <mame@t...> + + * parse.y (vtable_free): remove meaningless null check. + +Wed Jul 30 22:08:25 2008 Tanaka Akira <akr@f...> + + * dir.c (struct dir_data): change path field char * to VALUE. + (mark_dir): new function for mark path field. + (free_dir): follow the path field change. + (dir_s_alloc): ditto. + (dir_initialize): ditto. + (dir_s_open): ditto. + (dir_inspect): ditto. + (dir_path): return (duplicate of) the path field to preserve + encoding. [ruby-dev:35685] + +Wed Jul 30 22:06:56 2008 Yusuke Endoh <mame@t...> + + * string.c (sym_inspect): remove dead code. + +Wed Jul 30 21:32:52 2008 Yusuke Endoh <mame@t...> + + * ChangeLog: fix wrong method name and add reference. + +Wed Jul 30 21:30:08 2008 Yusuke Endoh <mame@t...> + + * regparse.c (name_add): fix memory leak. + +Wed Jul 30 21:08:06 2008 Yusuke Endoh <mame@t...> + + * regparse.c (parse_exp): fix memory leak at Regexp.new("x{1,1}"). + +Wed Jul 30 17:48:15 2008 Nobuyoshi Nakada <nobu@r...> + + * win32/win32.c (rb_w32_select): recalc the rest of timeout for each + iterations. [ruby-core:18015] + +Tue Jul 29 23:37:37 2008 Yusuke Endoh <mame@t...> + + * io.c (io_ungetc): raise NotImplementedError when ungetc is called + against dummy encoding IO. [ruby-dev:35686] + + * io.c (rb_io_getline_1): ditto when gets with delimiter is called. + + * io.c (io_getc): ditto when getc is called. + + * test/ruby/test_io_m17n.rb (test_terminator_stateful_conversion, + test_getc_stateful_conversion, test_ungetc_stateful_conversion): + these tests should raise NotImplementedError. + +Tue Jul 29 22:55:34 2008 Yusuke Endoh <mame@t...> + + * test/ruby/test_io.rb (pipe): run reader thread and writer thread. + +Tue Jul 29 21:38:08 2008 Yusuke Endoh <mame@t...> + + * ext/bigdecimal/bigdecimal.c (Init_bigdecimal): fix typo. + +Tue Jul 29 21:35:59 2008 Yusuke Endoh <mame@t...> + + * test/etc/test_etc.rb (test_passwd): age field may be string under + some environments. + +Tue Jul 29 17:54:35 2008 NARUSE, Yui <naruse@r...> + + * dir.c (char_casecmp): fix: return 0 if either of characters is NUL. + +Tue Jul 29 13:17:03 2008 NARUSE, Yui <naruse@r...> + + * test/etc/test_etc.rb (test_getpwuid): fix for users whose uid is + shared. + +Tue Jul 29 05:37:53 2008 Nobuyoshi Nakada <nobu@r...> + + * file.c (rb_find_file_ext, rb_find_file): explicit relative path + which starts with "./" or "../" should be searched from cwd + instead of load path. [ruby-dev:35673] + +Tue Jul 29 02:39:46 2008 NARUSE, Yui <naruse@r...> + + * math.c (math_atanh): raise EDOM on FreeBSD when atanh(1). + + * math.c (math_log): ditto. + + * math.c (math_log2): ditto. + + * math.c (math_log10): ditto. + + * test/ruby/test_math.rb: test for above. + +Tue Jul 29 01:41:15 2008 Tanaka Akira <akr@f...> + + * dir.c (struct dir_data): intenc field removed. + (dir_s_alloc): intenc initialization removed. + (dir_initialize): :internal_encoding option removed. dirname code + conversion removed. + (dir_enc_str): code conversion removed. + [ruby-dev:35661] + +Mon Jul 28 21:32:17 2008 Kouhei Sutou <kou@c...> + + * test/rss/: use PNG instead of zlib as binary data. + +Mon Jul 28 21:24:33 2008 NAKAMURA Usaku <usa@r...> + + * thread_win32.[ch] (cond_every_entry, rb_thread_cond_struct): reverted + r18239 because r18245 made the changes unnecessary. + + * thread.c (rb_mutex_struct): define after including thread_{pthread, + win32}.c. + +Mon Jul 28 21:00:10 2008 Yusuke Endoh <mame@t...> + + * test/ruby/test_require.rb (test_require_too_long_filename): + Kernel#require does not use dln_find_file_r (at r18242). + +Mon Jul 28 20:17:03 2008 Yusuke Endoh <mame@t...> + + * vm_core.h: move the definition of struct rb_mutex_struct. + + * thread.c: ditto. + +Mon Jul 28 18:58:46 2008 Yusuke Endoh <mame@t...> + + * thread.c (mutex_unlock): fix typo. + +Mon Jul 28 18:15:45 2008 Nobuyoshi Nakada <nobu@r...> + + * file.c (rb_find_file_ext, rb_find_file): not to split load path with + path separator. [ruby-Bugs-21356] + +Mon Jul 28 18:14:03 2008 Nobuyoshi Nakada <nobu@r...> + + * win32/win32.c (overlapped_socket_io, fcntl, rb_w32_close): must not + pass a pointer to int which is smaller than st_data_t on mswin64. + +Mon Jul 28 16:49:47 2008 Nobuyoshi Nakada <nobu@r...> + + * win32/win32.c (CreateChild, overlapped_socket_io): suppress + warnings. + +Mon Jul 28 16:06:36 2008 NAKAMURA Usaku <usa@r...> + + * win32/win32.c (MAXPATHLEN): define before use. + +Mon Jul 28 16:01:12 2008 NAKAMURA Usaku <usa@r...> + + * thread_win32.[ch] (cond_every_entry, rb_thread_cond_struct): moved + the definitions from .c to .h because rb_thread_cond_struct is used + in vm_core.h. + +Mon Jul 28 14:29:54 2008 Nobuyoshi Nakada <nobu@r...> + + * dln.c (load_lib): use dln_find_file_r instead of dln_find_file. + +Mon Jul 28 00:18:47 2008 Yusuke Endoh <mame@t...> + + * vm_core.h, thread.c: It is now prohibited to use Data_Get_Struct in + *_free against an object that is going to be free'ed. So, change type + of thread_t#keeping_mutexes from VALUE to mutex_t. + + * vm.c: remove mark to keeping_mutexes. + +Sun Jul 27 23:32:42 2008 Yusuke Endoh <mame@t...> + + * test/openssl/test_ssl.rb (server_loop): rescue Errno::EINVAL and + Errno::ECONNABORTED. + +Sun Jul 27 22:11:57 2008 NARUSE, Yui <naruse@r...> + + * bootstraptests/method.rb: increase RLIMIT_STACK size to 4M+8Kbytes + because FreeBSD fails this less than that. + +Sun Jul 27 21:45:59 2008 Koichi Sasada <ko1@a...> + + * gc.c (gc_mark_children, obj_free): T_DEFERRED should not be appear. + + * gc.c (gc_sweep, finalize_list): fix to decrement heap_slot#limit + after executing finalizer. + +Sun Jul 27 14:48:37 2008 Koichi Sasada <ko1@a...> + + * include/ruby/ruby.h: add a type T_DEFERRED. + + * gc.c: fix deferred finalizer system. finalize processes of + T_DATA and T_FILE are executed after gc process. + And fix to use BUILTIN_TYPE() instead of seeing flag. + + * thread.c, vm_core.h: add RUBY_VM_SET_FINALIZER_INTERRUPT() + and check intterupt_flag at rb_thread_execute_interrupts(). + + * thread.c (mutex_mark): fix to mark next_mutex. + + * vm.c (rb_thread_mark): fix to mark keeping_mutexes. + +Sun Jul 27 09:15:28 2008 Nobuyoshi Nakada <nobu@r...> + + * dln.h (dln_find_exe, dln_find_file): deprecated, use reentrant + versions instead. + +Sun Jul 27 09:02:32 2008 Masatoshi SEKI <m_seki@m...> + + * lib/rinda/tuplespace.rb: merged from 1.8. + + * test/rinda/test_rinda.rb: merged from 1.8. + +Sat Jul 26 22:45:18 2008 Yuki Sonoda (Yugui) <yugui@y...> + + * sample/exyacc.rb: fixed NoMethodError(Kernel#sub!). + replaced use of special variables with explicit IO + operations. + +Sat Jul 26 21:17:18 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (Init_win32ole): add + WIN32OLE_EVENT#handler=, WIN32OLE_EVENT#handler + + * test/win32ole/test_win32ole_event.rb: ditto. + +Sat Jul 26 07:44:14 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (add_event_call_back): remove unused + variable. + +Fri Jul 25 23:48:10 2008 Nobuyoshi Nakada <nobu@r...> + + * gc.c (gc_sweep, obj_free, run_final): defer finalizers of IO and + Data. [ruby-dev:35578] + +Fri Jul 25 23:35:18 2008 Nobuyoshi Nakada <nobu@r...> + + * lib/webrick/httputils.rb (WEBrick::HTTPUtils#split_header_value): + reduce backtrack. based on a fix by Christian Neukirchen + <chneukirchen AT gmail.com>. + Fri Jul 25 23:24:07 2008 Nobuyoshi Nakada <nobu@r...> * thread_pthread.c (get_stack): subtract guard size. @@ -12,6 +255,35 @@ * signal.c (sigsegv): use ruby_stack_overflowed_p. +Fri Jul 25 21:55:38 2008 Yusuke Endoh <mame@t...> + + * test/ruby/enc/test_koi8.rb: move from test/ruby/test_koi8.rb. + +Fri Jul 25 21:09:32 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (ole_invoke, add_event_callback, + rescue_callback): refactoring. + +Fri Jul 25 20:52:44 2008 Masaki Suketa <masaki.suketa@n...> + + * test/win32ole/err_in_callback.rb : add test of raising + exception in WIN32OLE_EVENT callback. + + * test/win32ole/test_err_in_callback.rb : ditto. + +Fri Jul 25 20:43:57 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c (Init_win32ole): add + WIN32OLE_EVENT#off_event. + + * test/win32ole/test_win32ole_event.rb: ditto. + + * test/win32ole/test_win32ole_event.rb: some refactoring. + +Fri Jul 25 19:50:49 2008 Nobuyoshi Nakada <nobu@r...> + + * regint.c (xmalloc, xrealloc, xfree): not to use ruby managed memory. + Fri Jul 25 16:21:14 2008 Nobuyoshi Nakada <nobu@r...> * include/ruby/io.h (ruby_absolute_path_p): published. @@ -22,6 +294,11 @@ * util.c (ruby_sys_getcwd): renamed and reverted. +Fri Jul 25 15:52:40 2008 Koichi Sasada <ko1@a...> + + * vm.c (vm_invoke_proc): skip setting safe_level if + it from bmethod. This change makes test/ruby/test_proc.rb pass. + Fri Jul 25 10:00:00 2008 Martin Duerst <duerst@i...> * test/ruby/test_transcode.rb: refactoring/cleanup of @@ -1852,8 +2129,8 @@ Fri Jun 20 03:19:39 2008 Yusuke Endoh <mame@t...> - * test/testunit/collector/test_dir.rb: r15825 made it unnecessary to change - String to Symbol. + * test/testunit/collector/test_dir.rb: r15825 made it unnecessary to + change String to Symbol. * test/testunit/collector/test_objectspace.rb: ditto. Index: mvm/bootstraptest/test_method.rb =================================================================== --- mvm/bootstraptest/test_method.rb (revision 18273) +++ mvm/bootstraptest/test_method.rb (revision 18274) @@ -997,12 +997,13 @@ assert_normal_exit %q{ begin - Process.setrlimit(Process::RLIMIT_STACK, 1024*1024) + Process.setrlimit(Process::RLIMIT_STACK, 4_202_496) + # FreeBSD fails this less than 4M + 8K bytes. rescue Exception exit end class C - attr "a" * (2*1024*1024) + attr "a" * (10*1024*1024) end }, '[ruby-dev:31818]' Index: mvm/vm_core.h =================================================================== --- mvm/vm_core.h (revision 18273) +++ mvm/vm_core.h (revision 18274) @@ -419,6 +419,8 @@ void *arg; }; +struct rb_mutex_struct; + struct rb_thread_struct { VALUE self; @@ -466,7 +468,7 @@ rb_thread_lock_t interrupt_lock; struct rb_unblock_callback unblock; VALUE locking_mutex; - VALUE keeping_mutexes; + struct rb_mutex_struct *keeping_mutexes; int transition_for_lock; struct rb_vm_tag *tag; @@ -726,12 +728,13 @@ #define RUBY_VM_SET_INTERRUPT(th) ((th)->interrupt_flag |= 0x02) #define RUBY_VM_SET_TIMER_INTERRUPT(th) ((th)->interrupt_flag |= 0x01) +#define RUBY_VM_SET_FINALIZER_INTERRUPT(th) ((th)->interrupt_flag |= 0x04) #define RUBY_VM_INTERRUPTED(th) ((th)->interrupt_flag & 0x02) void rb_thread_execute_interrupts(rb_thread_t *); #define RUBY_VM_CHECK_INTS_TH(th) do { \ - if(th->interrupt_flag){ \ + if (th->interrupt_flag) { \ /* TODO: trap something event */ \ rb_thread_execute_interrupts(th); \ } \ Index: mvm/sample/exyacc.rb =================================================================== --- mvm/sample/exyacc.rb (revision 18273) +++ mvm/sample/exyacc.rb (revision 18274) @@ -2,21 +2,19 @@ # usage: exyacc.rb [yaccfiles] # this is coverted from exyacc.pl in the camel book -$/ = nil - -while gets() - sbeg = $_.index("\n%%") + 1 - send = $_.rindex("\n%%") + 1 - $_ = $_[sbeg, send-sbeg] - sub!(/.*\n/, "") - gsub!(/'\{'/, "'\001'") - gsub!(/'\}'/, "'\002'") - gsub!(%r{\*/}, "\003\003") - gsub!(%r{/\*[^\003]*\003\003}, '') - while gsub!(/\{[^{}]*\}/, ''); end - gsub!(/'\001'/, "'{'") - gsub!(/'\002'/, "'}'") - while gsub!(/^[ \t]*\n(\s)/, '\1'); end - gsub!(/([:|])[ \t\n]+(\w)/, '\1 \2') - print $_ +ARGF.each(nil) do |source| + sbeg = source.index("\n%%") + 1 + send = source.rindex("\n%%") + 1 + grammer = source[sbeg, send-sbeg] + grammer.sub!(/.*\n/, "") + grammer.gsub!(/'\{'/, "'\001'") + grammer.gsub!(/'\}'/, "'\002'") + grammer.gsub!(%r{\*/}, "\003\003") + grammer.gsub!(%r{/\*[^\003]*\003\003}, '') + while grammer.gsub!(/\{[^{}]*\}/, ''); end + grammer.gsub!(/'\001'/, "'{'") + grammer.gsub!(/'\002'/, "'}'") + while grammer.gsub!(/^[ \t]*\n(\s)/, '\1'); end + grammer.gsub!(/([:|])[ \t\n]+(\w)/, '\1 \2') + print grammer end Index: mvm/string.c =================================================================== --- mvm/string.c (revision 18273) +++ mvm/string.c (revision 18274) @@ -6352,7 +6352,7 @@ static VALUE sym_inspect(VALUE sym) { - VALUE str, klass = Qundef; + VALUE str; ID id = SYM2ID(sym); rb_encoding *enc; @@ -6366,10 +6366,6 @@ str = rb_str_inspect(str); strncpy(RSTRING_PTR(str), ":\"", 2); } - if (klass != Qundef) { - rb_str_cat2(str, "/"); - rb_str_append(str, rb_inspect(klass)); - } return str; } Index: mvm/io.c =================================================================== --- mvm/io.c (revision 18273) +++ mvm/io.c (revision 18274) @@ -321,11 +321,17 @@ return; } +static rb_encoding *io_input_encoding(rb_io_t *fptr); + static void io_ungetc(VALUE str, rb_io_t *fptr) { int len = RSTRING_LEN(str); + if (rb_enc_dummy_p(io_input_encoding(fptr))) { + rb_raise(rb_eNotImpError, "ungetc against dummy encoding is not currently supported"); + } + if (fptr->rbuf == NULL) { fptr->rbuf_off = 0; fptr->rbuf_len = 0; @@ -1948,6 +1954,9 @@ GetOpenFile(io, fptr); rb_io_check_readable(fptr); + if (rb_enc_dummy_p(io_input_encoding(fptr)) && rs != rb_default_rs) { + rb_raise(rb_eNotImpError, "gets with delimiter against dummy encoding is not currently supported"); + } if (NIL_P(rs)) { str = read_all(fptr, 0, Qnil); if (RSTRING_LEN(str) == 0) return Qnil; @@ -2263,6 +2272,10 @@ int r, n, cr = 0; VALUE str; + if (rb_enc_dummy_p(enc)) { + rb_raise(rb_eNotImpError, "getc against dummy encoding is not currently supported"); + } + if (io_fillbuf(fptr) < 0) { return Qnil; } Index: mvm/pack.c =================================================================== --- mvm/pack.c (revision 18273) +++ mvm/pack.c (revision 18274) @@ -1787,33 +1787,31 @@ VALUE buf = infected_str_new(0, (send - s)*3/4, str); char *ptr = RSTRING_PTR(buf); int a = -1,b = -1,c = 0,d; - static int first = 1; - static int b64_xtable[256]; + static signed char b64_xtable[256]; - if (first) { + if (b64_xtable['/'] <= 0) { int i; - first = 0; for (i = 0; i < 256; i++) { b64_xtable[i] = -1; } for (i = 0; i < 64; i++) { - b64_xtable[(int)b64_table[i]] = i; + b64_xtable[(unsigned char)b64_table[i]] = i; } } while (s < send) { a = b = c = d = -1; - while((a = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { s++; } - if( s >= send ) break; + while ((a = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;} + if (s >= send) break; s++; - while((b = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { s++; } - if( s >= send ) break; + while ((b = b64_xtable[(unsigned char)*s]) == -1 && s < send) {s++;} + if (s >= send) break; s++; - while((c = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { if( *s == '=' ) break; s++; } - if( *s == '=' || s >= send ) break; + while ((c = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;} + if (*s == '=' || s >= send) break; s++; - while((d = b64_xtable[(int)(*(unsigned char*)s)]) == -1 && s < send) { if( *s == '=' ) break; s++; } - if( *s == '=' || s >= send ) break; + while ((d = b64_xtable[(unsigned char)*s]) == -1 && s < send) {if (*s == '=') break; s++;} + if (*s == '=' || s >= send) break; s++; *ptr++ = a << 2 | b >> 4; *ptr++ = b << 4 | c >> 2; Index: mvm/lib/webrick/httputils.rb =================================================================== --- mvm/lib/webrick/httputils.rb (revision 18273) +++ mvm/lib/webrick/httputils.rb (revision 18274) @@ -23,16 +23,8 @@ ret = path.dup ret.gsub!(%r{/+}o, '/') # // => / - while ret.sub!(%r{/\.(/|\Z)}o, '/'); end # /. => / - begin # /foo/.. => /foo - match = ret.sub!(%r{/([^/]+)/\.\.(/|\Z)}o){ - if $1 == ".." - raise "abnormal path `#{path}'" - else - "/" - end - } - end while match + while ret.sub!(%r'/\.(?:/|\Z)', '/'); end # /. => / + while ret.sub!(%r'/(?!\.\./)[^/]+/\.\.(?:/|\Z)', '/'); end # /foo/.. => /foo raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret ret @@ -155,8 +147,8 @@ module_function :parse_header def split_header_value(str) - str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+) - (?:,\s*|\Z)/xn).collect{|v| v[0] } + str.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+) + (?:,\s*|\Z)'xn).flatten end module_function :split_header_value Index: mvm/lib/rinda/tuplespace.rb =================================================================== --- mvm/lib/rinda/tuplespace.rb (revision 18273) +++ mvm/lib/rinda/tuplespace.rb (revision 18274) @@ -2,6 +2,8 @@ require 'thread' require 'drb/drb' require 'rinda/rinda' +require 'enumerator' +require 'forwardable' module Rinda @@ -286,45 +288,70 @@ # of Tuplespace. class TupleBag + class TupleBin + extend Forwardable + def_delegators '@bin', :find_all, :delete_if, :each, :empty? + def initialize + @bin = [] + end + + def add(tuple) + @bin.push(tuple) + end + + def delete(tuple) + idx = @bin.rindex(tuple) + @bin.delete_at(idx) if idx + end + + def find(&blk) + @bin.reverse_each do |x| + return x if yield(x) + end + nil + end + end + def initialize # :nodoc: @hash = {} + @enum = Enumerable::Enumerator.new(self, :each_entry) end ## # +true+ if the TupleBag to see if it has any expired entries. def has_expires? - @hash.each do |k, v| - v.each do |tuple| - return true if tuple.expires - end + @enum.find do |tuple| + tuple.expires end - false end ## - # Add +ary+ to the TupleBag. + # Add +tuple+ to the TupleBag. - def push(ary) - size = ary.size - @hash[size] ||= [] - @hash[size].push(ary) + def push(tuple) + key = bin_key(tuple) + @hash[key] ||= TupleBin.new + @hash[key].add(tuple) end ## - # Removes +ary+ from the TupleBag. + # Removes +tuple+ from the TupleBag. - def delete(ary) - size = ary.size - @hash.fetch(size, []).delete(ary) + def delete(tuple) + key = bin_key(tuple) + bin = @hash[key] + return nil unless bin + bin.delete(tuple) + @hash.delete(key) if bin.empty? + tuple end ## # Finds all live tuples that match +template+. - def find_all(template) - @hash.fetch(template.size, []).find_all do |tuple| + bin_for_find(template).find_all do |tuple| tuple.alive? && template.match(tuple) end end @@ -333,7 +360,7 @@ # Finds a live tuple that matches +template+. def find(template) - @hash.fetch(template.size, []).find do |tuple| + bin_for_find(template).find do |tuple| tuple.alive? && template.match(tuple) end end @@ -343,7 +370,7 @@ # +tuple+ and are alive. def find_all_template(tuple) - @hash.fetch(tuple.size, []).find_all do |template| + @enum.find_all do |template| template.alive? && template.match(tuple) end end @@ -354,20 +381,39 @@ def delete_unless_alive deleted = [] - @hash.keys.each do |size| - ary = [] - @hash[size].each do |tuple| + @hash.each do |key, bin| + bin.delete_if do |tuple| if tuple.alive? - ary.push(tuple) + false else deleted.push(tuple) + true end end - @hash[size] = ary end deleted end + private + def each_entry(&blk) + @hash.each do |k, v| + v.each(&blk) + end + end + + def bin_key(tuple) + head = tuple[0] + if head.class == Symbol + return head + else + false + end + end + + def bin_for_find(template) + key = bin_key(template) + key ? @hash.fetch(key, []) : @enum + end end ## @@ -403,8 +449,7 @@ # Adds +tuple+ def write(tuple, sec=nil) - entry = TupleEntry.new(tuple, sec) - start_keeper + entry = create_entry(tuple, sec) synchronize do if entry.expired? @read_waiter.find_all_template(entry).each do |template| @@ -414,6 +459,7 @@ notify_event('delete', entry.value) else @bag.push(entry) + start_keeper if entry.expires @read_waiter.find_all_template(entry).each do |template| template.read(tuple) end @@ -439,7 +485,6 @@ def move(port, tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? - start_keeper synchronize do entry = @bag.find(template) if entry @@ -452,6 +497,7 @@ begin @take_waiter.push(template) + start_keeper if template.expires while true raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? @@ -476,7 +522,6 @@ def read(tuple, sec=nil) template = WaitTemplateEntry.new(self, tuple, sec) yield(template) if block_given? - start_keeper synchronize do entry = @bag.find(template) return entry.value if entry @@ -484,6 +529,7 @@ begin @read_waiter.push(template) + start_keeper if template.expires template.wait raise RequestCanceledError if template.canceled? raise RequestExpiredError if template.expired? @@ -529,6 +575,10 @@ private + def create_entry(tuple, sec) + TupleEntry.new(tuple, sec) + end + ## # Removes dead tuples. @@ -566,9 +616,12 @@ def start_keeper return if @keeper && @keeper.alive? @keeper = Thread.new do - while need_keeper? - keep_clean + while true sleep(@period) + synchronize do + break unless need_keeper? + keep_clean + end end end end Index: mvm/proc.c =================================================================== --- mvm/proc.c (revision 18273) +++ mvm/proc.c (revision 18274) @@ -531,7 +531,7 @@ } return vm_invoke_proc(GET_THREAD(), proc, proc->block.self, - argc, argv, &pass_proc->block); + argc, argv, (pass_proc ? &pass_proc->block : 0)); } /* Index: mvm/thread.c =================================================================== --- mvm/thread.c (revision 18273) +++ mvm/thread.c (revision 18274) @@ -59,7 +59,6 @@ struct timeval rb_time_interval(VALUE); static int rb_thread_dead(rb_thread_t *th); -static void rb_mutex_unlock_all(VALUE); static void rb_check_deadlock(rb_vm_t *vm); void rb_signal_exec(rb_thread_t *th, int sig); @@ -272,6 +271,17 @@ return ST_CONTINUE; } +typedef struct rb_mutex_struct +{ + rb_thread_lock_t lock; + rb_thread_cond_t cond; + struct rb_thread_struct volatile *th; + volatile int cond_waiting, cond_notified; + struct rb_mutex_struct *next_mutex; +} mutex_t; + +static void rb_mutex_unlock_all(mutex_t *mutex); + void rb_thread_terminate_all(void) { @@ -413,7 +423,7 @@ /* unlock all locking mutexes */ if (th->keeping_mutexes) { rb_mutex_unlock_all(th->keeping_mutexes); - th->keeping_mutexes = Qfalse; + th->keeping_mutexes = NULL; } /* delete self from living_threads */ @@ -950,8 +960,12 @@ rb_thread_execute_interrupts(rb_thread_t *th) { if (th->raised_flag) return; + while (th->interrupt_flag) { enum rb_thread_status status = th->status; + int timer_interrupt = th->interrupt_flag & 0x01; + int finalizer_interrupt = th->interrupt_flag & 0x04; + th->status = THREAD_RUNNABLE; th->interrupt_flag = 0; @@ -981,10 +995,15 @@ } th->status = status; - /* thread pass */ - rb_thread_schedule(); + if (finalizer_interrupt) { + rb_gc_finalize_deferred(); + } + + if (timer_interrupt) { + EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0); + rb_thread_schedule(); + } } - EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0); } @@ -1956,7 +1975,7 @@ } static int -subst(struct timeval *rest, const struct timeval *wait) +subtract_tv(struct timeval *rest, const struct timeval *wait) { while (rest->tv_usec < wait->tv_usec) { if (rest->tv_sec <= wait->tv_sec) { @@ -1981,10 +2000,18 @@ #ifndef linux double limit = 0; struct timeval wait_rest; +# if defined(__CYGWIN__) || defined(_WIN32) + struct timeval start_time; +# endif if (timeout) { - limit = timeofday() + - (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6; +# if defined(__CYGWIN__) || defined(_WIN32) + gettimeofday(&start_time, NULL); + limit = (double)start_time.tv_sec + (double)start_time.tv_usec*1e-6; +# else + limit = timeofday(); +# endif + limit += (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6; wait_rest = *timeout; timeout = &wait_rest; } @@ -1999,6 +2026,7 @@ #if defined(__CYGWIN__) || defined(_WIN32) { + int finish = 0; /* polling duration: 100ms */ struct timeval wait_100ms, *wait; wait_100ms.tv_sec = 0; @@ -2016,9 +2044,19 @@ if (write) *write = orig_write; if (except) *except = orig_except; wait = &wait_100ms; - } while (__th->interrupt_flag == 0 && (timeout == 0 || subst(timeout, &wait_100ms))); + if (timeout) { + struct timeval elapsed; + gettimeofday(&elapsed, NULL); + subtract_tv(&elapsed, &start_time); + if (!subtract_tv(timeout, &elapsed)) { + finish = 1; + break; + } + if (cmp_tv(&wait_100ms, timeout) < 0) wait = timeout; + } + } while (__th->interrupt_flag == 0); }, 0, 0); - } while (result == 0 && (timeout == 0 || subst(timeout, &wait_100ms))); + } while (result == 0 && !finish); } #else BLOCKING_REGION({ @@ -2493,31 +2531,12 @@ * */ -typedef struct mutex_struct { - rb_thread_lock_t lock; - rb_thread_cond_t cond; - rb_thread_t volatile *th; - volatile int cond_waiting, cond_notified; - VALUE next_mutex; -} mutex_t; - #define GetMutexPtr(obj, tobj) \ Data_Get_Struct(obj, mutex_t, tobj) static const char *mutex_unlock(mutex_t *mutex); static void -mutex_mark(void *ptr) -{ - if (ptr) { - mutex_t *mutex = ptr; - if (mutex->th) { - rb_gc_mark(mutex->th->self); - } - } -} - -static void mutex_free(void *ptr) { if (ptr) { @@ -2542,7 +2561,7 @@ VALUE volatile obj; mutex_t *mutex; - obj = Data_Make_Struct(klass, mutex_t, mutex_mark, mutex_free, mutex); + obj = Data_Make_Struct(klass, mutex_t, NULL, mutex_free, mutex); native_mutex_initialize(&mutex->lock); native_cond_initialize(&mutex->cond); return obj; @@ -2583,12 +2602,13 @@ static void mutex_locked(rb_thread_t *th, VALUE self) { + mutex_t *mutex; + GetMutexPtr(self, mutex); + if (th->keeping_mutexes) { - mutex_t *mutex; - GetMutexPtr(self, mutex); mutex->next_mutex = th->keeping_mutexes; } - th->keeping_mutexes = self; + th->keeping_mutexes = mutex; } /* @@ -2754,14 +2774,14 @@ native_mutex_unlock(&mutex->lock); if (!err) { - GetMutexPtr(th->keeping_mutexes, th_mutex); + th_mutex = th->keeping_mutexes; if (th_mutex == mutex) { th->keeping_mutexes = mutex->next_mutex; } else { while (1) { mutex_t *tmp_mutex; - GetMutexPtr(th_mutex->next_mutex, tmp_mutex); + tmp_mutex = th_mutex->next_mutex; if (tmp_mutex == mutex) { th_mutex->next_mutex = tmp_mutex->next_mutex; break; @@ -2769,7 +2789,7 @@ th_mutex = tmp_mutex; } } - mutex->next_mutex = Qfalse; + mutex->next_mutex = NULL; } return err; @@ -2796,13 +2816,13 @@ } static void -rb_mutex_unlock_all(VALUE mutexes) +rb_mutex_unlock_all(mutex_t *mutexes) { const char *err; mutex_t *mutex; while (mutexes) { - GetMutexPtr(mutexes, mutex); + mutex = mutexes; rb_warn("mutex #<%s:%p> remains to be locked by terminated thread", rb_obj_classname(mutexes), (void*)mutexes); mutexes = mutex->next_mutex; Index: mvm/dir.c =================================================================== --- mvm/dir.c (revision 18273) +++ mvm/dir.c (revision 18274) @@ -96,8 +96,7 @@ const char *p1end, *p2end; int c1, c2; - if (!*p1) return *p1; - if (!*p2) return -*p2; + if (!*p1 || !*p2) return !!*p1 - !!*p2; p1end = p1 + strlen(p1); p2end = p2 + strlen(p2); c1 = rb_enc_codepoint(p1, p1end, enc); @@ -295,17 +294,21 @@ struct dir_data { DIR *dir; - char *path; - rb_encoding *intenc; + VALUE path; rb_encoding *extenc; }; static void +mark_dir(struct dir_data *dir) +{ + rb_gc_mark(dir->path); +} + +static void free_dir(struct dir_data *dir) { if (dir) { if (dir->dir) closedir(dir->dir); - if (dir->path) xfree(dir->path); } xfree(dir); } @@ -316,11 +319,10 @@ dir_s_alloc(VALUE klass) { struct dir_data *dirp; - VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp); + VALUE obj = Data_Make_Struct(klass, struct dir_data, mark_dir, free_dir, dirp); dirp->dir = NULL; - dirp->path = NULL; - dirp->intenc = NULL; + dirp->path = Qnil; dirp->extenc = NULL; return obj; @@ -337,66 +339,36 @@ { struct dir_data *dp; static rb_encoding *fs_encoding; - rb_encoding *intencoding, *extencoding; + rb_encoding *extencoding; VALUE dirname, opt; - static VALUE sym_intenc, sym_extenc; + static VALUE sym_extenc; - if (!sym_intenc) { - sym_intenc = ID2SYM(rb_intern("internal_encoding")); + if (!sym_extenc) { sym_extenc = ID2SYM(rb_intern("external_encoding")); fs_encoding = rb_filesystem_encoding(); } - intencoding = NULL; extencoding = fs_encoding; rb_scan_args(argc, argv, "11", &dirname, &opt); if (!NIL_P(opt)) { - VALUE v, extenc=Qnil, intenc=Qnil; + VALUE v, extenc=Qnil; opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash"); - v = rb_hash_aref(opt, sym_intenc); - if (!NIL_P(v)) intenc = v; v = rb_hash_aref(opt, sym_extenc); if (!NIL_P(v)) extenc = v; if (!NIL_P(extenc)) { extencoding = rb_to_encoding(extenc); - if (!NIL_P(intenc)) { - intencoding = rb_to_encoding(intenc); - if (extencoding == intencoding) { - rb_warn("Ignoring internal encoding '%s': it is identical to external encoding '%s'", - RSTRING_PTR(rb_inspect(intenc)), - RSTRING_PTR(rb_inspect(extenc))); - intencoding = NULL; - } - } } - else if (!NIL_P(intenc)) { - rb_raise(rb_eArgError, "External encoding must be specified when internal encoding is given"); - } } FilePathValue(dirname); - { - rb_encoding *dirname_encoding = rb_enc_get(dirname); - if (rb_usascii_encoding() != dirname_encoding - && rb_ascii8bit_encoding() != dirname_encoding -#if defined __APPLE__ - && rb_utf8_encoding() != dirname_encoding -#endif - && extencoding != dirname_encoding) { - if (!intencoding) intencoding = dirname_encoding; - dirname = rb_str_transcode(dirname, rb_enc_from_encoding(extencoding)); - } - } Data_Get_Struct(dir, struct dir_data, dp); if (dp->dir) closedir(dp->dir); - if (dp->path) xfree(dp->path); dp->dir = NULL; - dp->path = NULL; - dp->intenc = intencoding; + dp->path = Qnil; dp->extenc = extencoding; dp->dir = opendir(RSTRING_PTR(dirname)); if (dp->dir == NULL) { @@ -408,7 +380,7 @@ rb_sys_fail(RSTRING_PTR(dirname)); } } - dp->path = strdup(RSTRING_PTR(dirname)); + dp->path = rb_str_dup_frozen(dirname); return dir; } @@ -428,7 +400,7 @@ dir_s_open(int argc, VALUE *argv, VALUE klass) { struct dir_data *dp; - VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp); + VALUE dir = Data_Make_Struct(klass, struct dir_data, mark_dir, free_dir, dp); dir_initialize(argc, argv, dir); if (rb_block_given_p()) { @@ -462,9 +434,6 @@ dir_enc_str(VALUE str, struct dir_data *dirp) { rb_enc_associate(str, dirp->extenc); - if (dirp->intenc) { - str = rb_str_transcode(str, rb_enc_from_encoding(dirp->intenc)); - } return str; } @@ -480,9 +449,9 @@ struct dir_data *dirp; Data_Get_Struct(dir, struct dir_data, dirp); - if (dirp->path) { + if (!NIL_P(dirp->path)) { const char *c = rb_obj_classname(dir); - return rb_sprintf("#<%s:%s>", c, dirp->path); + return rb_sprintf("#<%s:%s>", c, RSTRING_PTR(dirp->path)); } return rb_funcall(dir, rb_intern("to_s"), 0, 0); } @@ -502,8 +471,8 @@ struct dir_data *dirp; Data_Get_Struct(dir, struct dir_data, dirp); - if (!dirp->path) return Qnil; - return dir_enc_str(rb_str_new2(dirp->path), dirp); + if (NIL_P(dirp->path)) return Qnil; + return rb_str_dup(dirp->path); } /* Index: mvm/win32/win32.c =================================================================== --- mvm/win32/win32.c (revision 18273) +++ mvm/win32/win32.c (revision 18274) @@ -916,6 +916,12 @@ return rb_w32_spawn(mode, rb_w32_join_argv(cmd, argv), prog); } +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#else +# define MAXPATHLEN 512 +#endif + static struct ChildRecord * CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput, HANDLE hError) @@ -928,6 +934,7 @@ const char *shell; struct ChildRecord *child; char *p = NULL; + char fbuf[MAXPATHLEN]; if (!cmd && !prog) { errno = EFAULT; @@ -975,7 +982,7 @@ dwCreationFlags = (NORMAL_PRIORITY_CLASS); if (prog) { - if (!(p = dln_find_exe(prog, NULL))) { + if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) { shell = prog; } } @@ -1014,7 +1021,7 @@ prog = cmd; for (;;) { if (!*prog) { - p = dln_find_exe(cmd, NULL); + p = dln_find_exe_r(cmd, NULL, fbuf, sizeof(fbuf)); break; } if (strchr(".:*?\"/\\", *prog)) { @@ -1031,7 +1038,7 @@ p = ALLOCA_N(char, len + 1); memcpy(p, cmd, len); p[len] = 0; - p = dln_find_exe(p, NULL); + p = dln_find_exe_r(p, NULL, fbuf, sizeof(fbuf)); break; } prog++; @@ -1106,13 +1113,7 @@ return 0; } -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#else -# define MAXPATHLEN 512 -#endif - static NtCmdLineElement ** cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail) { @@ -2142,7 +2143,7 @@ } static inline int -subst(struct timeval *rest, const struct timeval *wait) +subtract(struct timeval *rest, const struct timeval *wait) { while (rest->tv_usec < wait->tv_usec) { if (rest->tv_sec <= wait->tv_sec) { @@ -2173,7 +2174,7 @@ #undef Sleep int WSAAPI rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, - struct timeval *timeout) + struct timeval *timeout) { int r; fd_set pipe_rd; @@ -2182,11 +2183,29 @@ fd_set else_wr; fd_set except; int nonsock = 0; + struct timeval limit; if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) { errno = EINVAL; return -1; } + + if (timeout) { + if (timeout->tv_sec < 0 || + timeout->tv_usec < 0 || + timeout->tv_usec >= 1000000) { + errno = EINVAL; + return -1; + } + gettimeofday(&limit, NULL); + limit.tv_sec += timeout->tv_sec; + limit.tv_usec += timeout->tv_usec; + if (limit.tv_usec >= 1000000) { + limit.tv_usec -= 1000000; + limit.tv_sec++; + } + } + if (!NtSocketsInitialized) { StartSockets(); } @@ -2222,10 +2241,9 @@ struct timeval rest; struct timeval wait; struct timeval zero; - if (timeout) rest = *timeout; wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms zero.tv_sec = 0; zero.tv_usec = 0; // 0ms - do { + for (;;) { if (nonsock) { // modifying {else,pipe,cons}_rd is safe because // if they are modified, function returns immediately. @@ -2241,8 +2259,7 @@ break; } else { - struct timeval *dowait = - compare(&rest, &wait) < 0 ? &rest : &wait; + struct timeval *dowait = &wait; fd_set orig_rd; fd_set orig_wr; @@ -2256,10 +2273,16 @@ if (wr) *wr = orig_wr; if (ex) *ex = orig_ex; - // XXX: should check the time select spent + if (timeout) { + struct timeval now; + gettimeofday(&now, NULL); + rest = limit; + if (!subtract(&rest, &now)) break; + if (compare(&rest, &wait) < 0) dowait = &rest; + } Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000); } - } while (!timeout || subst(&rest, &wait)); + } } return r; @@ -2431,7 +2454,8 @@ int r; int ret; int mode; - int flg; + st_data_t data; + DWORD flg; WSAOVERLAPPED wol; WSABUF wbuf; int err; @@ -2441,7 +2465,8 @@ StartSockets(); s = TO_SOCKET(fd); - st_lookup(socklist, (st_data_t)s, (st_data_t *)&mode); + st_lookup(socklist, (st_data_t)s, &data); + mode = (int)data; if (!cancel_io || (mode & O_NONBLOCK)) { RUBY_CRITICAL({ if (input) { @@ -2919,6 +2944,7 @@ int arg; int ret; int flag = 0; + st_data_t data; u_long ioctlArg; if (!is_socket(sock)) { @@ -2933,7 +2959,8 @@ va_start(va, cmd); arg = va_arg(va, int); va_end(va); - st_lookup(socklist, (st_data_t)sock, (st_data_t*)&flag); + st_lookup(socklist, (st_data_t)sock, &data); + flag = (int)data; if (arg & O_NONBLOCK) { flag |= O_NONBLOCK; ioctlArg = 1; @@ -3583,7 +3610,7 @@ HANDLE h; int ret; if (IsWin95()) { - int fd = open(path, O_WRONLY), e; + int fd = open(path, O_WRONLY), e = 0; if (fd == -1) return -1; ret = chsize(fd, (unsigned long)length); if (ret == -1) e = errno; @@ -3985,13 +4012,16 @@ { SOCKET sock = TO_SOCKET(fd); int save_errno = errno; + st_data_t key; if (!is_socket(sock)) { UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); return _close(fd); } _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); - st_delete(socklist, (st_data_t *)&sock, NULL); + key = (st_data_t)sock; + st_delete(socklist, &key, NULL); + sock = (SOCKET)key; _close(fd); errno = save_errno; if (closesocket(sock) == SOCKET_ERROR) { Index: mvm/gc.c =================================================================== --- mvm/gc.c (revision 18273) +++ mvm/gc.c (revision 18274) @@ -574,7 +574,6 @@ objs--; } } - lo = 0; hi = heaps_used; @@ -1078,7 +1077,7 @@ rb_mark_generic_ivar(ptr); } - switch (obj->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: rb_bug("rb_gc_mark() called for broken object"); @@ -1221,7 +1220,7 @@ } gc_mark(objspace, obj->as.basic.klass, lev); - switch (obj->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_ICLASS: case T_CLASS: case T_MODULE: @@ -1315,13 +1314,22 @@ default: rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s", - obj->as.basic.flags & T_MASK, obj, + BUILTIN_TYPE(obj), obj, is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object"); } } -static void obj_free(rb_objspace_t *, VALUE); +static int obj_free(rb_objspace_t *, VALUE); +static inline void +add_freelist(rb_objspace_t *objspace, RVALUE *p) +{ + VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +} + static void finalize_list(rb_objspace_t *objspace, RVALUE *p) { @@ -1329,11 +1337,12 @@ RVALUE *tmp = p->as.free.next; run_final(objspace, (VALUE)p); if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(objspace, p); } + else { + struct heaps_slot *slot = (struct heaps_slot *)RDATA(p)->dmark; + slot->limit--; + } p = tmp; } } @@ -1382,6 +1391,7 @@ do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65; free_min = (heaps_used * HEAP_OBJ_LIMIT) * 0.2; + if (free_min < FREE_MIN) { do_heap_free = heaps_used * HEAP_OBJ_LIMIT; free_min = FREE_MIN; @@ -1394,27 +1404,28 @@ int n = 0; RVALUE *free = freelist; RVALUE *final = final_list; + int deferred; p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags) { - obj_free(objspace, (VALUE)p); - } - if (need_call_final && FL_TEST(p, FL_FINALIZE)) { - p->as.free.flags = FL_MARK; /* remain marked */ + if (p->as.basic.flags && + ((deferred = obj_free(objspace, (VALUE)p)) || + ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) { + if (!deferred) { + p->as.free.flags = T_DEFERRED; + RDATA(p)->dfree = 0; + } + p->as.free.flags |= FL_MARK; p->as.free.next = final_list; final_list = p; } else { - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(objspace, p); } n++; } - else if (RBASIC(p)->flags == FL_MARK) { + else if (BUILTIN_TYPE(p) == T_DEFERRED) { /* objects to be finalized */ /* do nothing remain marked */ } @@ -1426,11 +1437,15 @@ } if (n == heaps[i].limit && freed > do_heap_free) { RVALUE *pp; + int f_count = 0; - heaps[i].limit = 0; for (pp = final_list; pp != final; pp = pp->as.free.next) { - p->as.free.flags |= FL_SINGLETON; /* freeing page mark */ + f_count++; + RDATA(pp)->dmark = (void *)&heaps[i]; + pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */ } + heaps[i].limit = f_count; + freelist = free; /* cancel this page from freelist */ } else { @@ -1451,25 +1466,24 @@ /* clear finalization list */ if (final_list) { deferred_final_list = final_list; - return; + RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD()); } - free_unused_heaps(objspace); + else{ + free_unused_heaps(objspace); + } } void rb_gc_force_recycle(VALUE p) { rb_objspace_t *objspace = &rb_objspace; - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - RANY(p)->as.free.flags = 0; - RANY(p)->as.free.next = freelist; - freelist = RANY(p); + add_freelist(objspace, (RVALUE *)p); } -static void +static int obj_free(rb_objspace_t *objspace, VALUE obj) { - switch (RANY(obj)->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: @@ -1482,7 +1496,7 @@ rb_free_generic_ivar((VALUE)obj); } - switch (RANY(obj)->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) && RANY(obj)->as.object.as.heap.ivptr) { @@ -1523,7 +1537,14 @@ xfree(DATA_PTR(obj)); } else if (RANY(obj)->as.data.dfree) { - (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + if (1) { + RANY(obj)->as.basic.flags &= ~T_MASK; + RANY(obj)->as.basic.flags |= T_DEFERRED; + return 1; + } + else { + (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + } } } break; @@ -1538,7 +1559,17 @@ break; case T_FILE: if (RANY(obj)->as.file.fptr) { - rb_io_fptr_finalize(RANY(obj)->as.file.fptr); + rb_io_t *fptr = RANY(obj)->as.file.fptr; + if (1) { + RANY(obj)->as.basic.flags &= ~T_MASK; + RANY(obj)->as.basic.flags |= T_DEFERRED; + RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize; + RDATA(obj)->data = fptr; + return 1; + } + else { + rb_io_fptr_finalize(fptr); + } } break; case T_RATIONAL: @@ -1567,7 +1598,7 @@ xfree(RANY(obj)->as.node.u1.node); break; } - return; /* no need to free iv_tbl */ + break; /* no need to free iv_tbl */ case T_STRUCT: if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && @@ -1578,8 +1609,10 @@ default: rb_bug("gc_sweep(): unknown data type 0x%lx(%p)", - RANY(obj)->as.basic.flags & T_MASK, (void*)obj); + BUILTIN_TYPE(obj), (void*)obj); } + + return 0; } #ifdef __GNUC__ @@ -1848,6 +1881,7 @@ case T_NONE: case T_ICLASS: case T_NODE: + case T_DEFERRED: continue; case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; @@ -1998,14 +2032,19 @@ run_final(rb_objspace_t *objspace, VALUE obj) { long i; - int status, critical_save = rb_thread_critical; + int status; VALUE args[3], table, objid; objid = rb_obj_id(obj); /* make obj into id */ - rb_thread_critical = Qtrue; - args[1] = 0; - args[2] = (VALUE)rb_safe_level(); - if (finalizer_table && st_delete(finalizer_table, (st_data_t*)&obj, &table)) { + + if (RDATA(obj)->dfree) { + (*RDATA(obj)->dfree)(DATA_PTR(obj)); + } + + if (finalizer_table && + st_delete(finalizer_table, (st_data_t*)&obj, &table)) { + args[1] = 0; + args[2] = (VALUE)rb_safe_level(); if (!args[1] && RARRAY_LEN(table) > 0) { args[1] = rb_obj_freeze(rb_ary_new3(1, objid)); } @@ -2016,15 +2055,14 @@ rb_protect(run_single_final, (VALUE)args, &status); } } - rb_thread_critical = critical_save; } static void gc_finalize_deferred(rb_objspace_t *objspace) { RVALUE *p = deferred_final_list; + deferred_final_list = 0; - deferred_final_list = 0; if (p) { finalize_list(objspace, p); } @@ -2042,7 +2080,10 @@ { RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg; if (p->as.basic.flags & FL_FINALIZE) { - p->as.free.flags = FL_MARK; /* remain marked */ + if (BUILTIN_TYPE(p) != T_DEFERRED) { + p->as.free.flags = FL_MARK | T_DEFERRED; /* remain marked */ + RDATA(p)->dfree = 0; + } p->as.free.next = *final_list; *final_list = p; } @@ -2322,6 +2363,7 @@ COUNT_TYPE(T_UNDEF); COUNT_TYPE(T_NODE); COUNT_TYPE(T_ICLASS); + COUNT_TYPE(T_DEFERRED); #undef COUNT_TYPE default: type = INT2NUM(i); break; } Index: mvm/regint.h =================================================================== --- mvm/regint.h (revision 18273) +++ mvm/regint.h (revision 18274) @@ -85,6 +85,10 @@ /* escape other system UChar definition */ #ifndef RUBY_DEFINES_H #include "ruby/ruby.h" +#undef xmalloc +#undef xrealloc +#undef xcalloc +#undef xfree #endif #ifdef ONIG_ESCAPE_UCHAR_COLLISION #undef ONIG_ESCAPE_UCHAR_COLLISION Index: mvm/parse.y =================================================================== --- mvm/parse.y (revision 18273) +++ mvm/parse.y (revision 18274) @@ -155,9 +155,7 @@ if (tbl->tbl) { xfree(tbl->tbl); } - if (tbl) { - xfree(tbl); - } + xfree(tbl); } } Index: mvm/dln.c =================================================================== --- mvm/dln.c (revision 18273) +++ mvm/dln.c (revision 18274) @@ -348,14 +348,14 @@ static int dln_init(const char *prog) { - char *file; + char *file, fbuf[MAXPATHLEN]; int fd; struct exec hdr; struct nlist *syms; if (dln_init_p == 1) return 0; - file = dln_find_exe(prog, NULL); + file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)); if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { dln_errno = errno; return -1; @@ -911,7 +911,7 @@ static int load_lib(const char *lib) { - char *path, *file; + char *path, *file, fbuf[MAXPATHLEN]; char armagic[SARMAG]; int fd, size; struct ar_hdr ahdr; @@ -942,7 +942,7 @@ path = getenv("DLN_LIBRARY_PATH"); if (path == NULL) path = dln_librrb_ary_path; - file = dln_find_file(lib, path); + file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf)); fd = open(file, O_RDONLY); if (fd == -1) goto syserr; size = read(fd, armagic, SARMAG); Index: mvm/ext/bigdecimal/bigdecimal.c =================================================================== --- mvm/ext/bigdecimal/bigdecimal.c (revision 18273) +++ mvm/ext/bigdecimal/bigdecimal.c (revision 18274) @@ -1844,7 +1844,7 @@ /* * 0x01: Determines what happens when the result of a computation is an - * underflow (a result too large to be represented). See BigDecimal.mode. + * overflow (a result too large to be represented). See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW)); Index: mvm/ext/win32ole/sample/ienavi2.rb =================================================================== --- mvm/ext/win32ole/sample/ienavi2.rb (revision 0) +++ mvm/ext/win32ole/sample/ienavi2.rb (revision 18274) @@ -0,0 +1,40 @@ +require 'win32ole' + +class IEHandler + attr_reader :loop + def initialize + @urls = [] + @loop = true + end + def method_missing(event, *args) + case event + when "BeforeNavigate2" + puts "Now Navigate #{args[1]}..." + end + end + def onNavigateComplete2(pdisp, url) + @urls << url + end + def onOnQuit + puts "Now Stop IE..." + @loop = false + end + def put_urls + puts "You Navigated the URLs ..." + @urls.each_with_index do |url, i| + puts "(#{i+1}) #{url}" + end + end +end + +ie = WIN32OLE.new('InternetExplorer.Application') +ie.visible = true +ie.gohome + +ev = WIN32OLE_EVENT.new(ie) +ev.handler = IEHandler.new + +while (ev.handler.loop) + WIN32OLE_EVENT.message_loop +end +ev.handler.put_urls Property changes on: mvm/ext/win32ole/sample/ienavi2.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/ext/win32ole/win32ole.c =================================================================== --- mvm/ext/win32ole/win32ole.c (revision 18273) +++ mvm/ext/win32ole/win32ole.c (revision 18274) @@ -118,7 +118,7 @@ #define WC2VSTR(x) ole_wc2vstr((x), TRUE) -#define WIN32OLE_VERSION "1.2.7" +#define WIN32OLE_VERSION "1.3.0" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -499,6 +499,8 @@ static VALUE foleparam_inspect(VALUE self); static long ole_search_event_at(VALUE ary, VALUE ev); static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL *is_default); +static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler); +static void ole_delete_event(VALUE ary, VALUE ev); static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams); static VALUE hash2result(VALUE hash); static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams); @@ -517,7 +519,10 @@ static VALUE ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg); static VALUE fev_on_event(int argc, VALUE *argv, VALUE self); static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self); +static VALUE fev_off_event(int argc, VALUE *argv, VALUE self); static VALUE fev_unadvise(VALUE self); +static VALUE fev_set_handler(VALUE self, VALUE val); +static VALUE fev_get_handler(VALUE self); static VALUE evs_push(VALUE ev); static VALUE evs_delete(long i); static VALUE evs_entry(long i); @@ -3227,7 +3232,7 @@ if (is_bracket) { DispID = DISPID_VALUE; argc += 1; - rb_funcall(paramS, rb_intern("unshift"), 1, cmd); + rb_ary_unshift(paramS, cmd); } else { wcmdname = ole_vstr2wc(cmd); hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, @@ -7432,7 +7437,34 @@ } return def_event; } +static VALUE +ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler) +{ + VALUE mid; + *is_default_handler = FALSE; + mid = rb_to_id(rb_sprintf("on%s", StringValuePtr(ev))); + if (rb_respond_to(handler, mid)) { + return mid; + } + mid = rb_intern("method_missing"); + if (rb_respond_to(handler, mid)) { + *is_default_handler = TRUE; + return mid; + } + return Qnil; +} + +static void +ole_delete_event(VALUE ary, VALUE ev) +{ + long at = -1; + at = ole_search_event_at(ary, ev); + if (at >= 0) { + rb_ary_delete_at(ary, at); + } +} + static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams) { @@ -7490,8 +7522,9 @@ { VALUE *parg = (VALUE *)arg; VALUE handler = parg[0]; - VALUE args = parg[1]; - return rb_apply(handler, rb_intern("call"), args); + VALUE mid = parg[1]; + VALUE args = parg[2]; + return rb_apply(handler, mid, args); } static VALUE @@ -7499,12 +7532,10 @@ { VALUE e = rb_errinfo(); - VALUE c = rb_funcall(e, rb_intern("class"), 0); VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0); VALUE msg = rb_funcall(e, rb_intern("message"), 0); - c = rb_funcall(c, rb_intern("to_s"), 0); bt = rb_ary_entry(bt, 0); - fprintf(stdout, "%s: %s (%s)\n", StringValuePtr(bt), StringValuePtr(msg), StringValuePtr(c)); + fprintf(stdout, "%s: %s (%s)\n", StringValuePtr(bt), StringValuePtr(msg), rb_obj_classname(e)); rb_backtrace(); ruby_finalize(); exit(-1); @@ -7530,9 +7561,11 @@ unsigned int i; ITypeInfo *pTypeInfo; VARIANT *pvar; - VALUE ary, obj, event, handler, args, outargv, ev, result; - VALUE arg[2]; - VALUE is_outarg; + VALUE ary, obj, event, args, outargv, ev, result; + VALUE handler = Qnil; + VALUE arg[3]; + VALUE mid; + VALUE is_outarg = Qfalse; BOOL is_default_handler = FALSE; int state; @@ -7554,9 +7587,21 @@ } ev = WC2VSTR(bstr); event = ole_search_event(ary, ev, &is_default_handler); - if (NIL_P(event)) { - return NOERROR; + if (TYPE(event) == T_ARRAY) { + handler = rb_ary_entry(event, 0); + mid = rb_intern("call"); + is_outarg = rb_ary_entry(event, 3); + } else { + handler = rb_ivar_get(obj, rb_intern("handler")); + if (handler == Qnil) { + return NOERROR; + } + mid = ole_search_handler_method(handler, ev, &is_default_handler); } + if (handler == Qnil || mid == Qnil) { + return NOERROR; + } + args = rb_ary_new(); if (is_default_handler) { rb_ary_push(args, ev); @@ -7567,8 +7612,6 @@ pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1]; rb_ary_push(args, ole_variant2val(pvar)); } - handler = rb_ary_entry(event, 0); - is_outarg = rb_ary_entry(event, 3); outargv = Qnil; if (is_outarg == Qtrue) { outargv = rb_ary_new(); @@ -7583,7 +7626,8 @@ * and exit ruby process by Win32OLE itself. */ arg[0] = handler; - arg[1] = args; + arg[1] = mid; + arg[2] = args; result = rb_protect(exec_callback, (VALUE)arg, &state); if (state != 0) { rescue_callback(Qnil); @@ -8079,16 +8123,12 @@ static void add_event_call_back(VALUE obj, VALUE event, VALUE data) { - long at = -1; VALUE events = rb_ivar_get(obj, id_events); if (NIL_P(events) || TYPE(events) != T_ARRAY) { events = rb_ary_new(); rb_ivar_set(obj, id_events, events); } - at = ole_search_event_at(events, event); - if (at >= 0) { - rb_ary_delete_at(events, at); - } + ole_delete_event(events, event); rb_ary_push(events, data); } @@ -8167,6 +8207,40 @@ /* * call-seq: + * WIN32OLE_EVENT#off_event([event]) + * + * removes the callback of event. + * + * ie = WIN32OLE.new('InternetExplorer.Application') + * ev = WIN32OLE_EVENT.new(ie) + * ev.on_event('BeforeNavigate2') {|*args| + * args.last[6] = true + * } + * ... + * ev.off_event('BeforeNavigate2') + * ... + */ +static VALUE +fev_off_event(int argc, VALUE *argv, VALUE self) +{ + VALUE event = Qnil; + VALUE events; + + rb_secure(4); + rb_scan_args(argc, argv, "01", &event); + if(!NIL_P(event)) { + Check_SafeStr(event); + } + events = rb_ivar_get(self, id_events); + if (NIL_P(events)) { + return Qnil; + } + ole_delete_event(events, event); + return Qnil; +} + +/* + * call-seq: * WIN32OLE_EVENT#unadvise -> nil * * disconnects OLE server. If this method called, then the WIN32OLE_EVENT object @@ -8220,6 +8294,64 @@ return rb_funcall(ary_ole_event, rb_intern("length"), 0); } +/* + * call-seq: + * WIN32OLE_EVENT#handler= + * + * sets event handler object. If handler object has onXXX + * method according to XXX event, then onXXX method is called + * when XXX event occurs. + * + * If handler object has method_missing and there is no + * method according to the event, then method_missing + * called and 1-st argument is event name. + * + * If handler object has onXXX method and there is block + * defined by WIN32OLE_EVENT#on_event('XXX'){}, + * then block is executed but handler object method is not called + * when XXX event occurs. + * + * class Handler + * def onStatusTextChange(text) + * puts "StatusTextChanged" + * end + * def onPropertyChange(prop) + * puts "PropertyChanged" + * end + * def method_missing(ev, *arg) + * puts "other event #{ev}" + * end + * end + * + * handler = Handler.new + * ie = WIN32OLE.new('InternetExplorer.Application') + * ev = WIN32OLE_EVENT.new(ie) + * ev.on_event("StatusTextChange") {|*args| + * puts "this block executed." + * puts "handler.onStatusTextChange method is not called." + * } + * ev.handler = handler + * + */ +static VALUE +fev_set_handler(VALUE self, VALUE val) +{ + return rb_ivar_set(self, rb_intern("handler"), val); +} + +/* + * call-seq: + * WIN32OLE_EVENT#handler + * + * returns handler object. + * + */ +static VALUE +fev_get_handler(VALUE self) +{ + return rb_ivar_get(self, rb_intern("handler")); +} + static void olevariant_free(struct olevariantdata *pvar) { @@ -8854,7 +8986,10 @@ rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1); rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1); rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1); + rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1); rb_define_method(cWIN32OLE_EVENT, "unadvise", fev_unadvise, 0); + rb_define_method(cWIN32OLE_EVENT, "handler=", fev_set_handler, 1); + rb_define_method(cWIN32OLE_EVENT, "handler", fev_get_handler, 0); cWIN32OLE_VARIANT = rb_define_class("WIN32OLE_VARIANT", rb_cObject); rb_define_alloc_func(cWIN32OLE_VARIANT, folevariant_s_allocate); Index: mvm/dln.h =================================================================== --- mvm/dln.h (revision 18273) +++ mvm/dln.h (revision 18274) @@ -28,8 +28,8 @@ # define _(args) () #endif -char *dln_find_exe(const char*,const char*); -char *dln_find_file(const char*,const char*); +DEPRECATED(char *dln_find_exe(const char*,const char*)); +DEPRECATED(char *dln_find_file(const char*,const char*)); char *dln_find_exe_r(const char*,const char*,char*,int); char *dln_find_file_r(const char*,const char*,char*,int); Index: mvm/.merged-trunk-revision =================================================================== --- mvm/.merged-trunk-revision (revision 18273) +++ mvm/.merged-trunk-revision (revision 18274) @@ -1 +1 @@ -18206 +18273 Index: mvm/vm.c =================================================================== --- mvm/vm.c (revision 18273) +++ mvm/vm.c (revision 18274) @@ -508,7 +508,9 @@ TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { - th->safe_level = proc->safe_level; + if (!proc->is_from_method) { + th->safe_level = proc->safe_level; + } val = invoke_block_from_c(th, &proc->block, self, argc, argv, blockptr, 0); } TH_POP_TAG(); @@ -1474,7 +1476,7 @@ if (th->locking_mutex != Qfalse) { rb_bug("thread_free: locking_mutex must be NULL (%p:%ld)", th, th->locking_mutex); } - if (th->keeping_mutexes != Qfalse) { + if (th->keeping_mutexes != NULL) { rb_bug("thread_free: keeping_mutexes must be NULL (%p:%ld)", th, th->locking_mutex); } Index: mvm/version.h =================================================================== --- mvm/version.h (revision 18273) +++ mvm/version.h (revision 18274) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2008-07-25" +#define RUBY_RELEASE_DATE "2008-07-31" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20080725 +#define RUBY_RELEASE_CODE 20080731 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2008 #define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 25 +#define RUBY_RELEASE_DAY 31 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: mvm/test/ruby/test_koi8.rb =================================================================== --- mvm/test/ruby/test_koi8.rb (revision 18273) +++ mvm/test/ruby/test_koi8.rb (revision 18274) @@ -1,22 +0,0 @@ -require "test/unit" - -class TestKOI8 < Test::Unit::TestCase - ASSERTS = %q( - (0xc0..0xdf).each do |c| - c1 = c.chr("ENCODING") - c2 = (c + 0x20).chr("ENCODING") - assert_match(/^(#{ c1 })\1$/i, c2 + c1) - assert_match(/^(#{ c2 })\1$/i, c1 + c2) - assert_match(/^[#{ c1 }]+$/i, c2 + c1) - assert_match(/^[#{ c2 }]+$/i, c1 + c2) - end - ) - - def test_koi8_r - eval("# encoding: koi8-r\n" + ASSERTS.gsub("ENCODING", "koi8-r")) - end - - def test_koi8_u - eval("# encoding: koi8-u\n" + ASSERTS.gsub("ENCODING", "koi8-u")) - end -end Index: mvm/test/ruby/test_io_m17n.rb =================================================================== --- mvm/test/ruby/test_io_m17n.rb (revision 18273) +++ mvm/test/ruby/test_io_m17n.rb (revision 18274) @@ -161,11 +161,13 @@ with_tmpdir { src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp") generate_file('tmp', src) - s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| - f.gets("0".force_encoding("euc-jp")) - } - assert_equal(Encoding.find("euc-jp"), s.encoding) - assert_str_equal(src.encode("euc-jp"), s) + assert_raise(NotImplementedError) do + s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| + f.gets("0".force_encoding("euc-jp")) + } + assert_equal(Encoding.find("euc-jp"), s.encoding) + assert_str_equal(src.encode("euc-jp"), s) + end } end @@ -218,13 +220,30 @@ with_tmpdir { src = "\e$B\x23\x30\x23\x31\e(B".force_encoding("iso-2022-jp") generate_file('tmp', src) - open("tmp", "r:iso-2022-jp:euc-jp") {|f| - assert_equal("\xa3\xb0".force_encoding("euc-jp"), f.getc) - assert_equal("\xa3\xb1".force_encoding("euc-jp"), f.getc) - } + assert_raise(NotImplementedError) do + open("tmp", "r:iso-2022-jp:euc-jp") {|f| + assert_equal("\xa3\xb0".force_encoding("euc-jp"), f.getc) + assert_equal("\xa3\xb1".force_encoding("euc-jp"), f.getc) + } + end } end + def test_ungetc_stateful_conversion + with_tmpdir { + src = "before \e$B\x23\x30\x23\x31\e(B after".force_encoding("iso-2022-jp") + generate_file('tmp', src) + assert_raise(NotImplementedError) do + s = open("tmp", "r:iso-2022-jp:euc-jp") {|f| + f.ungetc("0".force_encoding("euc-jp")) + f.read + } + assert_equal(Encoding.find("euc-jp"), s.encoding) + assert_str_equal(("0" + src).encode("euc-jp"), s) + end + } + end + def test_open_ascii with_tmpdir { src = "abc\n" Index: mvm/test/ruby/test_require.rb =================================================================== --- mvm/test/ruby/test_require.rb (revision 18273) +++ mvm/test/ruby/test_require.rb (revision 18274) @@ -19,13 +19,20 @@ end def test_require_too_long_filename - assert_in_out_err([], <<-INPUT, %w(:ok), /^.+$/) + assert_in_out_err([], <<-INPUT, %w(:ok), []) begin require '#{ "foo/" * 10000 }foo' rescue LoadError p :ok end INPUT + + assert_in_out_err(["-S", "foo/" * 10000 + "foo"], "") do |r, e| + assert_equal([], r) + assert_operator(2, :<=, e.size) + assert_equal("openpath: pathname too long (ignored)", e.first) + assert_match(/\(LoadError\)/, e.last) + end end def test_require_path_home Index: mvm/test/ruby/test_math.rb =================================================================== --- mvm/test/ruby/test_math.rb (revision 18273) +++ mvm/test/ruby/test_math.rb (revision 18274) @@ -110,6 +110,7 @@ check(0, Math.log(1, 10)) check(1, Math.log(10, 10)) check(2, Math.log(100, 10)) + assert_equal(1.0/0, Math.log(1.0/0)) assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log(0) } assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log(-1) } end @@ -118,6 +119,7 @@ check(0, Math.log2(1)) check(1, Math.log2(2)) check(2, Math.log2(4)) + assert_equal(1.0/0, Math.log2(1.0/0)) assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log2(0) } assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log2(-1) } end @@ -126,6 +128,7 @@ check(0, Math.log10(1)) check(1, Math.log10(10)) check(2, Math.log10(100)) + assert_equal(1.0/0, Math.log10(1.0/0)) assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log10(0) } assert_raise(Errno::EDOM, Errno::ERANGE) { Math.log10(-1) } end @@ -134,6 +137,7 @@ check(0, Math.sqrt(0)) check(1, Math.sqrt(1)) check(2, Math.sqrt(4)) + assert_equal(1.0/0, Math.sqrt(1.0/0)) assert_raise(Errno::EDOM, Errno::ERANGE) { Math.sqrt(-1) } end Index: mvm/test/ruby/enc/test_koi8.rb =================================================================== --- mvm/test/ruby/enc/test_koi8.rb (revision 0) +++ mvm/test/ruby/enc/test_koi8.rb (revision 18274) @@ -0,0 +1,22 @@ +require "test/unit" + +class TestKOI8 < Test::Unit::TestCase + ASSERTS = %q( + (0xc0..0xdf).each do |c| + c1 = c.chr("ENCODING") + c2 = (c + 0x20).chr("ENCODING") + assert_match(/^(#{ c1 })\1$/i, c2 + c1) + assert_match(/^(#{ c2 })\1$/i, c1 + c2) + assert_match(/^[#{ c1 }]+$/i, c2 + c1) + assert_match(/^[#{ c2 }]+$/i, c1 + c2) + end + ) + + def test_koi8_r + eval("# encoding: koi8-r\n" + ASSERTS.gsub("ENCODING", "koi8-r")) + end + + def test_koi8_u + eval("# encoding: koi8-u\n" + ASSERTS.gsub("ENCODING", "koi8-u")) + end +end Property changes on: mvm/test/ruby/enc/test_koi8.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/test/ruby/test_io.rb =================================================================== --- mvm/test/ruby/test_io.rb (revision 18273) +++ mvm/test/ruby/test_io.rb (revision 18274) @@ -557,14 +557,16 @@ end.join end - def pipe + def pipe(wp, rp) r, w = IO.pipe - Timeout.timeout(10) do - yield(r, w) - end + rt = Thread.new { rp.call(r) } + wt = Thread.new { wp.call(w) } + flunk("timeout") unless rt.join(10) && wt.join(10) ensure r.close unless !r || r.closed? w.close unless !w || w.closed? + (rt.kill; rt.join) if rt + (wt.kill; wt.join) if wt end def pipe2(&b) @@ -594,16 +596,20 @@ end def test_ungetc2 - pipe do |r, w| - r.ungetc("0" * 10000) + f = false + pipe(proc do |w| + 0 until f w.write("1" * 10000) w.close + end, proc do |r| + r.ungetc("0" * 10000) + f = true assert_equal("0" * 10000 + "1" * 10000, r.read) - end + end) end def test_write_non_writable - pipe do |r, w| + with_pipe do |r, w| assert_raise(IOError) do r.write "foobarbaz" end @@ -629,7 +635,7 @@ end def test_inspect - pipe do |r, w| + with_pipe do |r, w| assert(r.inspect =~ /^#<IO:0x[0-9a-f]+>$/) assert_raise(SecurityError) do safe_4 { r.inspect } @@ -638,18 +644,19 @@ end def test_readpartial - pipe do |r, w| + pipe(proc do |w| w.write "foobarbaz" w.close + end, proc do |r| assert_raise(ArgumentError) { r.readpartial(-1) } assert_equal("fooba", r.readpartial(5)) r.readpartial(5, s = "") assert_equal("rbaz", s) - end + end) end def test_readpartial_error - pipe do |r, w| + with_pipe do |r, w| s = "" t = Thread.new { r.readpartial(5, s) } 0 until s.size == 5 @@ -661,18 +668,19 @@ end def test_read - pipe do |r, w| + pipe(proc do |w| w.write "foobarbaz" w.close + end, proc do |r| assert_raise(ArgumentError) { r.read(-1) } assert_equal("fooba", r.read(5)) r.read(nil, s = "") assert_equal("rbaz", s) - end + end) end def test_read_error - pipe do |r, w| + with_pipe do |r, w| s = "" t = Thread.new { r.read(5, s) } 0 until s.size == 5 @@ -684,20 +692,22 @@ end def test_write_nonblock - pipe do |r, w| + pipe(proc do |w| w.write_nonblock(1) w.close + end, proc do |r| assert_equal("1", r.read) - end + end) end def test_gets - pipe do |r, w| + pipe(proc do |w| w.write "foobarbaz" w.close + end, proc do |r| assert_equal("", r.gets(0)) - assert_equal("foobarbaz", r.gets(9)) - end + assert_equal("foobarbaz", s = r.gets(9)) + end) end def test_close_read @@ -709,14 +719,14 @@ end def test_close_read_pipe - pipe do |r, w| + with_pipe do |r, w| r.close_read assert_raise(Errno::EPIPE) { w.write "foobarbaz" } end end def test_close_read_security_error - pipe do |r, w| + with_pipe do |r, w| assert_raise(SecurityError) do safe_4 { r.close_read } end @@ -724,7 +734,7 @@ end def test_close_read_non_readable - pipe do |r, w| + with_pipe do |r, w| assert_raise(IOError) do w.close_read end @@ -740,7 +750,7 @@ end def test_close_write_security_error - pipe do |r, w| + with_pipe do |r, w| assert_raise(SecurityError) do safe_4 { r.close_write } end @@ -748,7 +758,7 @@ end def test_close_write_non_readable - pipe do |r, w| + with_pipe do |r, w| assert_raise(IOError) do r.close_write end @@ -802,111 +812,119 @@ assert_equal("nil,1,2,2,1001,1001,1001,1,2,3,3", f.read.chomp.gsub("\n", ",")) end - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| r.gets; assert_equal(1, $.) r.gets; assert_equal(2, $.) r.lineno = 1000; assert_equal(2, $.) r.gets; assert_equal(1001, $.) r.gets; assert_equal(1001, $.) - end + end) end def test_readline - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| r.readline; assert_equal(1, $.) r.readline; assert_equal(2, $.) r.lineno = 1000; assert_equal(2, $.) r.readline; assert_equal(1001, $.) assert_raise(EOFError) { r.readline } - end + end) end def test_each_char - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| a = [] r.each_char {|c| a << c } assert_equal(%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"], a) - end + end) end def test_lines - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| e = r.lines assert_equal("foo\n", e.next) assert_equal("bar\n", e.next) assert_equal("baz\n", e.next) assert_raise(StopIteration) { e.next } - end + end) end def test_bytes - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| e = r.bytes (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| assert_equal(c.ord, e.next) end assert_raise(StopIteration) { e.next } - end + end) end def test_chars - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| e = r.chars (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| assert_equal(c, e.next) end assert_raise(StopIteration) { e.next } - end + end) end def test_readbyte - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| assert_equal(c.ord, r.readbyte) end assert_raise(EOFError) { r.readbyte } - end + end) end def test_readchar - pipe do |r, w| + pipe(proc do |w| w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c| assert_equal(c, r.readchar) end assert_raise(EOFError) { r.readchar } - end + end) end def test_close_on_exec @@ -919,7 +937,7 @@ assert_equal(false, f.close_on_exec?) end - pipe do |r, w| + with_pipe do |r, w| assert_equal(false, r.close_on_exec?) r.close_on_exec = true assert_equal(true, r.close_on_exec?) @@ -935,7 +953,7 @@ end def test_close_security_error - pipe do |r, w| + with_pipe do |r, w| assert_raise(SecurityError) do safe_4 { r.close } end @@ -1034,7 +1052,7 @@ def test_reopen t = make_tempfile - pipe do |r, w| + with_pipe do |r, w| assert_raise(SecurityError) do safe_4 { r.reopen(t.path) } end @@ -1070,11 +1088,12 @@ end def test_printf - pipe do |r, w| + pipe(proc do |w| printf(w, "foo %s baz\n", "bar") w.close_write + end, proc do |r| assert_equal("foo bar baz\n", r.read) - end + end) end def test_print @@ -1084,13 +1103,14 @@ end def test_putc - pipe do |r, w| + pipe(proc do |w| w.putc "A" w.putc "BC" w.putc 68 w.close_write + end, proc do |r| assert_equal("ABD", r.read) - end + end) assert_in_out_err([], "putc 65", %w(A), []) end @@ -1098,19 +1118,21 @@ def test_puts_recursive_array a = ["foo"] a << a - pipe do |r, w| + pipe(proc do |w| w.puts a w.close + end, proc do |r| assert_equal("foo\n[...]\n", r.read) - end + end) end def test_display - pipe do |r, w| + pipe(proc do |w| "foo".display(w) w.close + end, proc do |r| assert_equal("foo", r.read) - end + end) assert_in_out_err([], "'foo'.display", %w(foo), []) end @@ -1132,7 +1154,7 @@ assert_equal("foo\nbar\nbaz\n", File.read(t.path)) - pipe do |r, w| + with_pipe do |r, w| assert_raise(RuntimeError) do o = Object.new class << o; self; end.instance_eval do @@ -1142,16 +1164,18 @@ end end - pipe do |r, w| - r, w = IO.new(r), IO.new(w) + pipe(proc do |w| + w = IO.new(w) w.puts "foo" w.puts "bar" w.puts "baz" w.close + end, proc do |r| + r = IO.new(r) assert_equal("foo\nbar\nbaz\n", r.read) - end + end) - pipe do |r, w| + with_pipe do |r, w| assert_raise(ArgumentError) { IO.new(r, "r+") } end Index: mvm/test/ruby/test_sleep.rb =================================================================== --- mvm/test/ruby/test_sleep.rb (revision 0) +++ mvm/test/ruby/test_sleep.rb (revision 18274) @@ -0,0 +1,10 @@ +require 'test/unit' + +class TestSleep < Test::Unit::TestCase + def test_sleep_5sec + start = Time.now + sleep 5 + slept = Time.now-start + assert_in_delta(5.0, slept, 0.1, "[ruby-core:18015]: longer than expected") + end +end Property changes on: mvm/test/ruby/test_sleep.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/test/win32ole/test_err_in_callback.rb =================================================================== --- mvm/test/win32ole/test_err_in_callback.rb (revision 0) +++ mvm/test/win32ole/test_err_in_callback.rb (revision 18274) @@ -0,0 +1,73 @@ +# +# test Win32OLE avoids cfp consistency error when the exception raised +# in WIN32OLE_EVENT handler block. [ruby-dev:35450] +# + +begin + require 'win32ole' +rescue LoadError +end +require 'rbconfig' +require 'mkmf' +require 'test/unit' +if defined?(WIN32OLE) + class TestErrInCallBack < Test::Unit::TestCase + def setup + @ruby = nil + if File.exist?("./" + CONFIG["RUBY_INSTALL_NAME"] + CONFIG["EXEEXT"]) + @ruby = "./" + CONFIG["RUBY_INSTALL_NAME"] + @iopt = $:.map {|e| + " -I " + e + }.join("") + @script = File.dirname(__FILE__) + "/err_in_callback.rb" + @param = create_temp_html + @param = "file:///" + @param.gsub(/\\/, '/') + end + end + + def create_temp_html + fso = WIN32OLE.new('Scripting.FileSystemObject') + dummy_file = fso.GetTempName + ".html" + cfolder = fso.getFolder(".") + @str = "This is test HTML file for Win32OLE (#{Time.now})" + f = cfolder.CreateTextFile(dummy_file) + f.writeLine("<html><body><div id='str'>#{@str}</div></body></html>") + f.close + dummy_path = cfolder.path + "\\" + dummy_file + dummy_path + end + + def test_err_in_callback + if @ruby + r = `#{@ruby} #{@iopt} #{@script} #{@param}` + assert_match(/NameError/, r) + end + end + + def ie_quit + sh = WIN32OLE.new('Shell.Application') + sh.windows.each do |w| + if w.ole_type.name == 'IWebBrowser2' + 20.times do |i| + if w.locationURL != "" && w.document + break + end + WIN32OLE_EVENT.message_loop + sleep 1 + end + e = w.document.getElementById("str") + if e && e.innerHTML == @str + w.quit + WIN32OLE_EVENT.message_loop + sleep 0.2 + end + end + end + end + + def teardown + WIN32OLE_EVENT.message_loop + ie_quit + end + end +end Property changes on: mvm/test/win32ole/test_err_in_callback.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/test/win32ole/err_in_callback.rb =================================================================== --- mvm/test/win32ole/err_in_callback.rb (revision 0) +++ mvm/test/win32ole/err_in_callback.rb (revision 18274) @@ -0,0 +1,11 @@ +require 'win32ole' +ie = WIN32OLE.new('InternetExplorer.Application') +ie.visible = true +WIN32OLE_EVENT.message_loop +sleep 0.2 +ev = WIN32OLE_EVENT.new(ie) + +ev.on_event('BeforeNavigate2') {|*args| + foo +} +ie.navigate(ARGV.shift) Property changes on: mvm/test/win32ole/err_in_callback.rb ___________________________________________________________________ Name: svn:eol-style + LF Index: mvm/test/win32ole/test_win32ole_event.rb =================================================================== --- mvm/test/win32ole/test_win32ole_event.rb (revision 18273) +++ mvm/test/win32ole/test_win32ole_event.rb (revision 18274) @@ -6,6 +6,8 @@ if defined?(WIN32OLE_EVENT) class TestWIN32OLE_EVENT < Test::Unit::TestCase + module IE + end def create_temp_html fso = WIN32OLE.new('Scripting.FileSystemObject') dummy_file = fso.GetTempName + ".html" @@ -17,9 +19,25 @@ dummy_path end + def message_loop + WIN32OLE_EVENT.message_loop + sleep 0.1 + end + + def wait_ie + while @ie.readyState != IE::READYSTATE_COMPLETE + message_loop + end + end + def setup + WIN32OLE_EVENT.message_loop @ie = WIN32OLE.new("InternetExplorer.Application") + if !defined?(IE::READYSTATE_COMPLETE) + WIN32OLE.const_load(@ie, IE) + end @ie.visible = true + message_loop @event = "" @event2 = "" @event3 = "" @@ -43,8 +61,7 @@ while @ie.busy WIN32OLE_EVENT.new(@ie) GC.start - WIN32OLE_EVENT.message_loop - sleep 0.1 + message_loop end assert_match(/BeforeNavigate/, @event) assert_match(/NavigateComplete/, @event) @@ -54,11 +71,7 @@ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents') ev.on_event {|*args| default_handler(*args)} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents') - GC.start - sleep 0.1 - end + wait_ie assert_match(/BeforeNavigate/, @event) assert_match(/NavigateComplete/, @event) end @@ -68,10 +81,7 @@ ev.on_event('BeforeNavigate') {|*args| handler1} ev.on_event('BeforeNavigate') {|*args| handler2} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert_equal("handler2", @event2) end @@ -80,10 +90,7 @@ ev.on_event {|*args| handler1} ev.on_event {|*args| handler2} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert_equal("handler2", @event2) end @@ -93,10 +100,7 @@ ev.on_event{|*args| handler2} ev.on_event('NavigateComplete'){|*args| handler3(*args)} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert(@event3!="") assert("handler2", @event2) end @@ -106,10 +110,7 @@ ev.on_event {|*args| default_handler(*args)} ev.on_event('NavigateComplete'){|*args| handler3(*args)} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert_match(/BeforeNavigate/, @event) assert(/NavigateComplete/ !~ @event) assert(@event!="") @@ -119,18 +120,12 @@ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents') ev.on_event {|*args| default_handler(*args)} @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert_match(/BeforeNavigate/, @event) ev.unadvise @event = "" @ie.navigate("file:///#{@f}") - while @ie.busy - WIN32OLE_EVENT.message_loop - sleep 0.1 - end + wait_ie assert_equal("", @event); assert_raise(WIN32OLERuntimeError) { ev.on_event {|*args| default_handler(*args)} @@ -157,10 +152,7 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end @@ -171,10 +163,7 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end @@ -185,10 +174,7 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end @@ -199,10 +185,7 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end @@ -213,10 +196,7 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end @@ -227,13 +207,28 @@ } bl = @ie.locationURL @ie.navigate("file:///#{@f}") - while @ie.busy - sleep 0.1 - WIN32OLE_EVENT.message_loop - end + wait_ie assert_equal(bl, @ie.locationURL) end + def test_off_event + ev = WIN32OLE_EVENT.new(@ie) + ev.on_event{handler1} + ev.off_event + @ie.navigate("file:///#{@f}") + wait_ie + assert_equal("", @event2) + end + + def test_off_event_arg + ev = WIN32OLE_EVENT.new(@ie) + ev.on_event('BeforeNavigate2'){handler1} + ev.off_event('BeforeNavigate2') + @ie.navigate("file:///#{@f}") + wait_ie + assert_equal("", @event2) + end + def handler1 @event2 = "handler1" end @@ -248,21 +243,72 @@ def teardown @ie.quit - WIN32OLE_EVENT.message_loop + message_loop @ie = nil - WIN32OLE_EVENT.message_loop - sleep 0.1 + i = 0 begin - File.unlink(@f) + i += 1 + File.unlink(@f) if i < 10 rescue Errno::EACCES - WIN32OLE_EVENT.message_loop - sleep 0.1 - File.unlink(@f) + message_loop + retry end - + message_loop GC.start - WIN32OLE_EVENT.message_loop - sleep 0.1 + message_loop end + + class Handler1 + attr_reader :val1, :val2, :val3, :val4 + def initialize + @val1 = nil + @val2 = nil + @val3 = nil + @val4 = nil + end + def onStatusTextChange(t) + @val1 = t + end + def onProgressChange(p, pmax) + @val2 = p + @val3 = pmax + end + def onPropertyChange(p) + @val4 = p + end + end + + class Handler2 + attr_reader :ev + def initialize + @ev = "" + end + def method_missing(ev, *arg) + @ev += ev + end + end + + def test_handler1 + ev = WIN32OLE_EVENT.new(@ie) + h1 = Handler1.new + ev.handler = h1 + @ie.navigate("file:///#{@f}") + wait_ie + assert(h1.val1) + assert_equal(h1.val1, ev.handler.val1) + assert(h1.val2) + assert(h1.val3) + assert(h1.val4) + end + + def test_handler2 + ev = WIN32OLE_EVENT.new(@ie) + h2 = Handler2.new + ev.handler = h2 + @ie.navigate("file:///#{@f}") + wait_ie + assert(h2.ev != "") + end + end end Index: mvm/test/openssl/test_ssl.rb =================================================================== --- mvm/test/openssl/test_ssl.rb (revision 18273) +++ mvm/test/openssl/test_ssl.rb (revision 18274) @@ -86,7 +86,7 @@ server_proc.call(ctx, ssl) end end - rescue Errno::EBADF, IOError + rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED end def start_server(port0, verify_mode, start_immediately, args = {}, &block) @@ -128,8 +128,8 @@ block.call(server, port.to_i) ensure - tcps.shutdown if (tcps) begin + tcps.shutdown if (tcps) if (server) server.join(5) if server.alive? @@ -138,7 +138,6 @@ flunk("TCPServer was closed and SSLServer is still alive") unless $! end end - rescue Errno::EINVAL, Errno::EBADF ensure tcps.close if (tcps) end Index: mvm/test/rinda/test_rinda.rb =================================================================== --- mvm/test/rinda/test_rinda.rb (revision 18273) +++ mvm/test/rinda/test_rinda.rb (revision 18274) @@ -12,14 +12,14 @@ include Singleton class MyTS < Rinda::TupleSpace - def keeper + def keeper_thread nil end end def initialize @now = 2 - @reso = 0.1 + @reso = 1 @ts = MyTS.new @ts.write([2, :now]) @inf = 2**31 - 1 @@ -33,17 +33,18 @@ n end - def _forward(n=@reso) + def _forward(n=nil) now ,= @ts.take([nil, :now]) @now = now + n n = @reso if n.nil? @ts.write([@now, :now]) end - def forward(n=@reso) + def forward(n) while n > 0 _forward(@reso) n -= @reso + Thread.pass end end @@ -55,21 +56,11 @@ @ts.write([2, :now]) end - def sleep(n=@reso) - while will_deadlock? - n -= @reso - forward - return 0 if n <= 0 - end + def sleep(n=nil) now ,= @ts.read([nil, :now]) @ts.read([(now + n)..@inf, :now]) 0 end - - def will_deadlock? - sz = Thread.current.group.list.find_all {|x| x.status != 'sleep'}.size - sz <= 1 - end end module Time @@ -115,6 +106,14 @@ Time.sleep(n) end end + + def thread_join(th) + while th.alive? + Kernel.sleep(0.1) + sleep(1) + end + th.value + end def test_00_tuple tuple = Rinda::TupleEntry.new([1,2,3]) @@ -240,6 +239,28 @@ end end + def test_ruby_talk_264062 + th = Thread.new { @ts.take([:empty], 1) } + sleep(10) + assert_raises(Rinda::RequestExpiredError) do + thread_join(th) + end + + th = Thread.new { @ts.read([:empty], 1) } + sleep(10) + assert_raises(Rinda::RequestExpiredError) do + thread_join(th) + end + end + + def test_symbol_tuple + @ts.write([:symbol, :symbol]) + @ts.write(['string', :string]) + assert_equal([[:symbol, :symbol]], @ts.read_all([:symbol, nil])) + assert_equal([[:symbol, :symbol]], @ts.read_all([Symbol, nil])) + assert_equal([], @ts.read_all([:nil, nil])) + end + def test_core_01 5.times do |n| @ts.write([:req, 2]) @@ -252,7 +273,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 0.5) + tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError @@ -263,10 +284,9 @@ s end - sleep(20) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) end def test_core_02 @@ -274,7 +294,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 1.0) + tuple = @ts.take([:req, Integer], 1) assert_equal(2, tuple[1]) s += tuple[1] rescue Rinda::RequestExpiredError @@ -289,10 +309,9 @@ @ts.write([:req, 2]) end - sleep(20) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) assert_equal([], @ts.read_all([nil, nil])) end @@ -349,7 +368,7 @@ s = 0 while true begin - tuple = @ts.take([:req, Integer], 1.0) + tuple = @ts.take([:req, Integer], 1) s += tuple[1] rescue Rinda::RequestExpiredError break @@ -359,26 +378,23 @@ s end - writer = Thread.new do - 5.times do |n| - @ts.write([:req, 2]) - sleep 0.1 - end + 5.times do |n| + @ts.write([:req, 2]) end @ts.take({"message"=>"first", "name"=>"3"}) sleep(4) + assert_equal(10, thread_join(taker)) tuple = @ts.take([:ans, nil]) assert_equal(10, tuple[1]) - assert_equal(10, taker.value) assert_equal([], @ts.read_all([nil, nil])) notify1.cancel sleep(3) # notify2 expired - assert_equal([0, 11], listener1.value) - assert_equal([0, 3], listener2.value) + assert_equal([0, 11], thread_join(listener1)) + assert_equal([0, 3], thread_join(listener2)) ary = [] ary.push(["write", {"message"=>"first", "name"=>"3"}]) @@ -403,23 +419,24 @@ template = nil taker = Thread.new do - @ts.take([:take, nil], 10) do |template| + @ts.take([:take, nil], 10) do |t| + template = t Thread.new do - sleep 0.2 template.cancel end end end - sleep(1) + sleep(2) + + assert_raises(Rinda::RequestCanceledError) do + assert_nil(thread_join(taker)) + end + assert(template.canceled?) @ts.write([:take, 1]) - assert_raises(Rinda::RequestCanceledError) do - assert_nil(taker.value) - end - assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end @@ -431,23 +448,24 @@ template = nil reader = Thread.new do - @ts.read([:take, nil], 10) do |template| + @ts.read([:take, nil], 10) do |t| + template = t Thread.new do - sleep 0.2 template.cancel end end end - sleep(1) + sleep(2) + + assert_raises(Rinda::RequestCanceledError) do + assert_nil(thread_join(reader)) + end + assert(template.canceled?) @ts.write([:take, 1]) - assert_raises(Rinda::RequestCanceledError) do - assert_nil(reader.value) - end - assert_equal([[:take, 1]], @ts.read_all([nil, nil])) end @@ -478,30 +496,22 @@ assert(tuple.expired?) assert(!tuple.alive?) - tuple = Rinda::TupleEntry.new([1,2,3], SimpleRenewer.new(1,2)) + @renewer = SimpleRenewer.new(1,2) + tuple = Rinda::TupleEntry.new([1,2,3], @renewer) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) - sleep(1.5) + sleep(1) assert(!tuple.canceled?) assert(!tuple.expired?) assert(tuple.alive?) - sleep(1.5) + sleep(2) assert(tuple.expired?) assert(!tuple.alive?) end end class TupleSpaceTest < Test::Unit::TestCase - def test_message - flunk("YARV doesn't support Rinda") - end -end - -end -__END__ - -class TupleSpaceTest < Test::Unit::TestCase include TupleSpaceTestModule def setup @@ -520,13 +530,9 @@ end def test_remote_array_and_hash - ary = [1, 2, 3] - @ts.write(DRbObject.new(ary)) - GC.start + @ts.write(DRbObject.new([1, 2, 3])) assert_equal([1, 2, 3], @ts.take([1, 2, 3], 0)) - hash = {'head' => 1, 'tail' => 2} - @ts.write(DRbObject.new(hash)) - GC.start + @ts.write(DRbObject.new({'head' => 1, 'tail' => 2})) assert_equal({'head' => 1, 'tail' => 2}, @ts.take({'head' => 1, 'tail' => 2}, 0)) end Index: mvm/test/rss/rss-assertions.rb =================================================================== --- mvm/test/rss/rss-assertions.rb (revision 18273) +++ mvm/test/rss/rss-assertions.rb (revision 18274) @@ -557,20 +557,16 @@ def assert_atom_content_inline_other_text(generator) _wrap_assertion do - require "zlib" - - type = "application/zip" + type = "image/png" assert_parse(generator.call(<<-EOA), :nothing_raised) <content type="#{type}"/> EOA - text = "" - char = "a" - 100.times do |i| - text << char - char.succ! + png_file = File.join(File.dirname(__FILE__), "dot.png") + png = File.open(png_file, "rb") do |file| + file.read.force_encoding("binary") end - base64_content = [Zlib::Deflate.deflate(text)].pack("m").delete("\n") + base64_content = [png].pack("m").delete("\n") [false, true].each do |with_space| xml_content = base64_content @@ -591,7 +587,7 @@ assert(content.inline_other_base64?) assert(!content.out_of_line?) assert(!content.have_xml_content?) - assert_equal(text, Zlib::Inflate.inflate(content.content)) + assert_equal(png, content.content) xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => type}, base64_content, xml) Index: mvm/test/rss/dot.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Property changes on: mvm/test/rss/dot.png ___________________________________________________________________ Name: svn:mime-type + image/png Index: mvm/test/rss/test_atom.rb =================================================================== --- mvm/test/rss/test_atom.rb (revision 18273) +++ mvm/test/rss/test_atom.rb (revision 18274) @@ -641,24 +641,19 @@ def assert_atom_content_inline_other_base64_to_s(target_class) _wrap_assertion do - require "zlib" - - text = "" - char = "a" - 100.times do |i| - text << char - char.succ! + type = "image/png" + png_file = File.join(File.dirname(__FILE__), "dot.png") + original_content = File.open(png_file, "rb") do |file| + file.read.force_encoding("binary") end - type = "application/zip" - original_content = Zlib::Deflate.deflate(text) - content = target_class.new content.type = type content.content = original_content xml = REXML::Document.new(content.to_s).root assert_rexml_element([], {"type" => type}, - [original_content].pack("m").delete("\n"), xml) + [original_content].pack("m").delete("\n"), + xml) end end Index: mvm/test/etc/test_etc.rb =================================================================== --- mvm/test/etc/test_etc.rb (revision 18273) +++ mvm/test/etc/test_etc.rb (revision 18274) @@ -18,7 +18,7 @@ assert_instance_of(String, s.shell) assert_kind_of(Integer, s.change) if s.respond_to?(:change) assert_kind_of(Integer, s.quota) if s.respond_to?(:quota) - assert_kind_of(Integer, s.age) if s.respond_to?(:age) + assert(s.age.is_a?(Integer) || s.age.is_a?(String)) if s.respond_to?(:age) assert_instance_of(String, s.uclass) if s.respond_to?(:uclass) assert_instance_of(String, s.comment) if s.respond_to?(:comment) assert_kind_of(Integer, s.expire) if s.respond_to?(:expire) @@ -28,9 +28,9 @@ end def test_getpwuid - passwd = [] - Etc.passwd {|s| passwd << s } - passwd.each do |s| + passwd = {} + Etc.passwd {|s| passwd[s.uid] = s unless passwd[s.uid] } + passwd.values.each do |s| assert_equal(s, Etc.getpwuid(s.uid)) assert_equal(s, Etc.getpwuid) if Etc.getlogin == s.name end Index: mvm/file.c =================================================================== --- mvm/file.c (revision 18273) +++ mvm/file.c (revision 18274) @@ -4479,35 +4479,25 @@ return eaccess(path, R_OK) == 0; } -#ifdef __CYGWIN__ -static void -intern_cygwin_path(volatile VALUE *path) +static int +is_explicit_relative(const char *path) { - char rubylib[MAXPATHLEN]; - VALUE str = *path; - const char *p = RSTRING_PTR(str); - - if (*p == '\\' || has_drive_letter(p)) { - if (cygwin_conv_to_posix_path(p, rubylib) == 0) { - *path = rb_str_new2(rubylib); - } - } + if (*path++ != '.') return 0; + if (*path == '.') path++; + return isdirsep(*path); } -#define intern_path(str) intern_cygwin_path(&(str)) -#else -#define intern_path(str) (void)(str) -#endif VALUE rb_get_load_path(void); int rb_find_file_ext(VALUE *filep, const char *const *ext) { - const char *path, *found; const char *f = RSTRING_PTR(*filep); - VALUE fname, load_path; - long i, j; + VALUE fname, load_path, tmp; + long i, j, fnlen; + if (!ext[0]) return 0; + if (f[0] == '~') { fname = rb_file_expand_path(*filep, Qnil); if (rb_safe_level() >= 2 && OBJ_TAINTED(fname)) { @@ -4518,15 +4508,18 @@ *filep = fname; } - if (is_absolute_path(f)) { + if (is_absolute_path(f) || is_explicit_relative(f)) { + fname = rb_str_dup(*filep); + fnlen = RSTRING_LEN(fname); for (i=0; ext[i]; i++) { - fname = rb_str_dup(*filep); rb_str_cat2(fname, ext[i]); - OBJ_FREEZE(fname); if (file_load_ok(StringValueCStr(fname))) { + if (!is_absolute_path(f)) fname = rb_file_expand_path(fname, Qnil); + OBJ_FREEZE(fname); *filep = fname; return i+1; } + rb_str_set_len(fname, fnlen); } return 0; } @@ -4534,24 +4527,26 @@ load_path = rb_get_load_path(); if (!load_path) return 0; + fname = rb_str_dup(*filep); + RBASIC(fname)->klass = 0; + fnlen = RSTRING_LEN(fname); + tmp = rb_str_tmp_new(MAXPATHLEN + 2); for (j=0; ext[j]; j++) { - fname = rb_str_dup(*filep); rb_str_cat2(fname, ext[j]); - OBJ_FREEZE(fname); for (i = 0; i < RARRAY_LEN(load_path); i++) { VALUE str = RARRAY_PTR(load_path)[i]; - char fbuf[MAXPATHLEN]; FilePathValue(str); if (RSTRING_LEN(str) == 0) continue; - intern_path(str); - path = RSTRING_PTR(str); - found = dln_find_file_r(StringValueCStr(fname), path, fbuf, sizeof(fbuf)); - if (found && file_load_ok(found)) { - *filep = rb_str_new2(found); + file_expand_path(fname, str, tmp); + if (file_load_ok(RSTRING_PTR(tmp))) { + RBASIC(tmp)->klass = RBASIC(*filep)->klass; + OBJ_FREEZE(tmp); + *filep = tmp; return j+1; } } + rb_str_set_len(fname, fnlen); } RB_GC_GUARD(load_path); return 0; @@ -4562,8 +4557,6 @@ { VALUE tmp, load_path; const char *f = StringValueCStr(path); - const char *lpath; - char fbuf[MAXPATHLEN]; if (f[0] == '~') { path = rb_file_expand_path(path, Qnil); @@ -4580,14 +4573,17 @@ rb_raise(rb_eSecurityError, "loading from unsafe file %s", f); } if (file_load_ok(f)) return path; + return 0; } #endif - if (is_absolute_path(f)) { + if (is_absolute_path(f) || is_explicit_relative(f)) { if (rb_safe_level() >= 1 && !fpath_check(f)) { rb_raise(rb_eSecurityError, "loading from unsafe file %s", f); } - if (file_load_ok(f)) return path; + if (!file_load_ok(f)) return 0; + if (!is_absolute_path(f)) path = rb_file_expand_path(path, Qnil); + return path; } if (rb_safe_level() >= 4) { @@ -4598,42 +4594,30 @@ if (load_path) { long i; - tmp = rb_ary_new(); + tmp = rb_str_tmp_new(MAXPATHLEN + 2); for (i = 0; i < RARRAY_LEN(load_path); i++) { VALUE str = RARRAY_PTR(load_path)[i]; FilePathValue(str); if (RSTRING_LEN(str) > 0) { - intern_path(str); - rb_ary_push(tmp, str); + file_expand_path(path, str, tmp); + f = RSTRING_PTR(tmp); + if (file_load_ok(f)) goto found; } } - tmp = rb_ary_join(tmp, rb_str_new2(PATH_SEP)); - if (RSTRING_LEN(tmp) == 0) { - lpath = 0; - } - else { - lpath = RSTRING_PTR(tmp); - } + return 0; + found: + RBASIC(tmp)->klass = RBASIC(path)->klass; + OBJ_FREEZE(tmp); } else { - lpath = 0; - } - - if (!lpath) { return 0; /* no path, no load */ } - if (!(f = dln_find_file_r(f, lpath, fbuf, sizeof(fbuf)))) { - return 0; - } + if (rb_safe_level() >= 1 && !fpath_check(f)) { rb_raise(rb_eSecurityError, "loading from unsafe file %s", f); } - if (file_load_ok(f)) { - tmp = rb_str_new2(f); - OBJ_FREEZE(tmp); - return tmp; - } - return 0; + + return tmp; } static void -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/