| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59876 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
This is needed for passing to the hook function the measuring target
type (line/branch/method) and the site of coverage event fired.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59871 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* vm_core.h: move rb_thread_t::machine to rb_execution_context_t::machine.
* vm_core.h, gc.c (rb_gc_mark_machine_stack): accept ec instead of th.
it enables to call this func from rb_execution_context_mark() in vm.c.
* cont.c (fiber_setcontext): catch up this fix.
fiber_restore_thread() restores machine stack information too.
* gc.c: catch up structure layout changes.
* thread.c: ditto.
* thread_pthread.c: ditto.
* thread_win32.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59825 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
| |
To prepare new measuring targets: branch and method coverages.
So far, iseq->coverage was an array of counts executed for line coverage.
Now, it is a three-element array for each measuring target,
whose first element is an array for line coverage.
The second element is planned for branch coverage, and the third will be
for method coverage.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59738 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
| |
* thread_win32.c (native_set_another_thread_name): set thread name
by SetThreadDescription.
* win32/win32.c (rb_w32_set_thread_description): dynamically try
SetThreadDescription.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59660 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
| |
* vm_core.h: Ruby processes run with two stacks, a machine stack and a
VM stack. To make it clear, this fix renames
rb_execution_context_t::stack(_size) to vm_stack(_size).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59563 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
| |
* thread.c: "Thread#to_s" is not defined without any reason. So this fix
define "Thread#to_s" which returns a string with some thread information.
Also this fix makes alias "inspect" which refers "to_s". This manner is
same as other objects.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59560 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* cont.c: r55766 change the handling method of Fiber's VM stack.
Resumed Fiber points NULL as VM stack and running Thread has
responsibility to manage it (marking and releasing).
However, thread_start_func_2()@thread.c and thread_free()@vm.c
doesn't free the VM stack if corresponding root Fiber is exist.
This causes memory leak. [Bug #13772]
* cont.c (root_fiber_alloc): fib->cont.saved_thread.ec.stack should be NULL
because running thread has responsibility to manage this stack.
* vm.c (rb_thread_recycle_stack_release): assert given stack is not NULL
(callers should care it).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59462 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
| |
* vm_core.h (rb_thread.h): move errinfo and trace_arg to
rb_execution_context_t.
* cont.c (fiber_switch, rb_cont_call): do not restore "trace_arg" here.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59199 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
| |
* vm_core.h (rb_thread_t): move root_lep, root_svar and ensure_list
to rb_execution_context_t.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59195 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
| |
* vm_core.h (rb_thread_ptr): added to replace GetThreadPtr() macro.
* thread.c (in some functions: use "target_th" instead of "th" to make clear
that it is not a current thread.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59192 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* vm_core.h (rb_thread_t): move storages to rb_execution_context_t.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59190 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
| |
* vm_core.h (rb_thread_t): move several fields which are copied at cont.c
to rb_execution_context_t.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59177 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59157 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* thread.c (exec_recursive): rb_catch_protect() uses `int*` as
well as rb_protect.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Return value of EXEC_TAG() is saved by "int state".
Instead of "int", use "enum ruby_tag_type". First EXEC_TAG()
value should be 0, so that define TAG_NONE (= 0) and use it.
Some code used "status" instead of "state". To make them clear,
rename them to state.
We can change variable name from "state" to "tag_state", but this
ticket doesn't contain it.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59155 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
| |
* thread.c (rb_blocking_region_buffer): remove oldubf because ubf should be
NULL just before ubf setting.
* thread.c (set_unblock_function, reset_unblock_function): rename to
unblock_function_set() and unblock_function_clear() respectively.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* thread.c (rbuy_kill): removed. This function is used
with SIGSEGV, SIGBUS, SIGKILL, SIGILL, SIGFPE and SIGSTOP
and these signals are affect immediately. So that `kill(2)'
is enough for them.
* signal.c (rb_f_kill): ditto.
* vm_core.h (rb_thread_t::interrupt_cond): removed because
only `ruby_kill()' uses this field.
* test/ruby/test_signal.rb: Without this patch sending SIGSTOP to own
process wait another interrupt even if another process sends SIGCONT.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59066 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
| |
* thread.c: revert r59053.
* thread_pthread.c (rb_thread_create_timer_thread): needs more
stack space for valgrind.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59055 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
| |
Without this hack, pthread_join() in rb_thread_stop_timer_thread()
segfaults.
ProductName: Mac OS X
ProductVersion: 10.11.6
BuildVersion: 15G1510
valgrind-3.12.0
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59053 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We no longer use it this function, but extensions do, and
we need to ensure it continues to work for them.
* thread.c (rb_thread_fd_close): schedule other threads in loop
* ext/-test-/thread_fd_close/thread_fd_close.c: new file
* ext/-test-/thread_fd_close/depend: ditto
* ext/-test-/thread_fd_close/extconf.rb: ditto
* test/-ext-/thread_fd_close/test_thread_fd_close.rb: new test
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59030 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Enqueuing multiple errors for one event causes spurious errors
down the line, as reported by Nikolay Vashchenko in
https://bugs.ruby-lang.org/issues/13632
This should fix bad interactions with test_race_gets_and_close
in test/ruby/test_io.rb since we ensure rb_notify_fd_close
continues returning the busy flag after enqueuing the interrupt.
Backporting changes to 2.4 and earlier releases will be more
challenging...
* thread.c (rb_notify_fd_close): do not enqueue multiple interrupts
[ruby-core:81581] [Bug #13632]
* test/ruby/test_io.rb (test_single_exception_on_close):
new test based on script from Nikolay
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59028 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59025 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59024 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
| |
(http://ci.rvm.jp/). This revert is to check the reason of failures.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59023 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Enqueuing multiple errors for one event causes spurious errors
down the line, as reported by Nikolay Vashchenko in
https://bugs.ruby-lang.org/issues/13632
* thread.c (rb_notify_fd_close): do not enqueue multiple interrupts
[ruby-core:81581] [Bug #13632]
* test/ruby/test_io.rb (test_single_exception_on_close):
new test based on script from Nikolay
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59020 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
To convert the object implicitly, it has had two parts in convert_type() which are
1. lookink up the method's id
2. calling the method
Seems that strncmp() and strcmp() in convert_type() are slightly heavy to look up
the method's id for type conversion.
This patch will add and use internal APIs (rb_convert_type_with_id, rb_check_convert_type_with_id)
to call the method without looking up the method's id when convert the object.
Array#flatten -> 19 % up
Array#+ -> 3 % up
[ruby-dev:50024] [Bug #13341] [Fix GH-1537]
### Before
Array#flatten 104.119k (± 1.1%) i/s - 525.690k in 5.049517s
Array#+ 1.993M (± 1.8%) i/s - 10.010M in 5.024258s
### After
Array#flatten 124.005k (± 1.0%) i/s - 624.240k in 5.034477s
Array#+ 2.058M (± 4.8%) i/s - 10.302M in 5.019328s
### Test Code
require 'benchmark/ips'
class Foo
def to_ary
[1,2,3]
end
end
Benchmark.ips do |x|
ary = []
100.times { |i| ary << i }
array = [ary]
x.report "Array#flatten" do |i|
i.times { array.flatten }
end
x.report "Array#+" do |i|
obj = Foo.new
i.times { array + obj }
end
end
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58978 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Instead, match the poll() implementation used on Linux for now;
as the Linux poll(2) manpage describes using negative FD to
easily ignore an FD in a larger FD set while (sleeping the given
timeout). I'm not entirely sure if matching poll() behavior
is a good idea for a single FD, but it's better than segfaulting
or NoMemoryError.
* thread.c (init_set_fd): ignore negative FD
* test/-ext-/wait_for_single_fd/test_wait_for_single_fd.rb
(test_wait_for_invalid_fd): check values which may trigger
segfaults or OOM
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58925 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Today, it increases IO#close performance with many threads:
Execution time (sec)
name trunk after
vm_thread_close 4.276 3.018
Speedup ratio: compare with the result of `trunk' (greater is better)
name after
vm_thread_close 1.417
This speedup comes because rb_notify_fd_close only scans threads
inside rb_thread_io_blocking_region, not all threads in the VM.
In the future, this type data structure may allow us to notify
waiters of multiple FDs on a single thread (when using
Fibers).
* thread.c (struct waiting_fd): declare
(rb_thread_io_blocking_region): use on-stack list waiter
(rb_notify_fd_close): walk vm->waiting_fds instead
(call_without_gvl): remove old field setting
(th_init): ditto
* vm_core.h (typedef struct rb_vm_struct): add waiting_fds list
* (typedef struct rb_thread_struct): remove waiting_fd field
(rb_vm_living_threads_init): initialize waiting_fds list
I am now kicking myself for not thinking about this 3 years ago
when I introduced ccan/list in [Feature #9632] to optimize this
same function :<
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58812 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58699 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
| |
The goal is to reduce rb_context_t and rb_fiber_t size
by removing the need to store the entire rb_thread_t in
there.
[ruby-core:81045] Work-in-progress: soon, we will move more fields here.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58614 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Instead of relying on a native condition variable and mutex for
every Ruby Mutex object, use a doubly linked-list to implement a
waiter queue in the Mutex. The immediate benefit of this is
reducing the size of every Mutex object, as some projects have
many objects requiring synchronization.
In the future, this technique using a linked-list and on-stack
list node (struct mutex_waiter) should allow us to easily
transition to M:N threading model, as we can avoid the native
thread dependency to implement Mutex.
We already do something similar for autoload in variable.c,
and this was inspired by the Linux kernel wait queue (as
ccan/list is inspired by the Linux kernel linked-list).
Finaly, there are big performance improvements for Mutex
benchmarks, especially in contended cases:
measure target: real
name |trunk |built
----------------|------:|------:
loop_whileloop2 | 0.149| 0.148
vm2_mutex* | 0.893| 0.651
vm_thread_mutex1| 0.809| 0.624
vm_thread_mutex2| 2.608| 0.628
vm_thread_mutex3| 28.227| 0.881
Speedup ratio: compare with the result of `trunk' (greater is better)
name |built
----------------|------:
loop_whileloop2 | 1.002
vm2_mutex* | 1.372
vm_thread_mutex1| 1.297
vm_thread_mutex2| 4.149
vm_thread_mutex3| 32.044
Tested on AMD FX-8320 8-core at 3.5GHz
* thread_sync.c (struct mutex_waiter): new on-stack struct
(struct rb_mutex_struct): remove native lock/cond, use ccan/list
(rb_mutex_num_waiting): new function for debug_deadlock_check
(mutex_free): remove native_*_destroy
(mutex_alloc): initialize waitq, remove native_*_initialize
(rb_mutex_trylock): remove native_mutex_{lock,unlock}
(lock_func): remove
(lock_interrupt): remove
(rb_mutex_lock): rewrite waiting path to use native_sleep + ccan/list
(rb_mutex_unlock_th): rewrite to wake up from native_sleep
using rb_threadptr_interrupt
(rb_mutex_abandon_all): empty waitq
* thread.c (debug_deadlock_check): update for new struct
(rb_check_deadlock): ditto
[ruby-core:80913] [Feature #13517]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58604 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The current range based current values of:
TIME_QUANTUM_USEC=100000
RUBY_THREAD_PRIORITY_MAX=3
RUBY_THREAD_PRIORITY_MIN=-3
Gives a range of 12500..800000, plenty enough for a 32-bit
integer. Clamping this also reduces potential implementation
bugs between 32-bit and 64-bit platforms.
I may consider a further reduction to uint16_t in the future
for M:N threading, but some users may want slightly larger
time quantums.
* vm_core.h (rb_thread_t): use 32-bit running_time_us
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58591 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* thread.c (fill_thread_id_string): cast to void pointer to
suppress warnings when pthread_t is not pointer type.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58532 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58464 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* vm_dump.c (rb_vmdebug_stack_dump_all_threads): fix for
non-scalar thread_id platforms. c.f. [Bug #9884]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58424 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (setup_exception): consider if the exception is frozen,
but not one of special exception objects.
* gc.c (rb_memerror): copy minimum objects.
* thread.c (rb_threadptr_execute_interrupts): prepare special
exception queued by another thread to be raised.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58380 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* vm_insnhelper.c (rb_threadptr_stack_overflow): move from
thread.c and integrate with vm_stackoverflow.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58379 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
| |
* vm_backtrace.c (rb_threadptr_backtrace_object): rename and
extern.
* vm_backtrace.c (rb_threadptr_backtrace_str_ary): rename as
threadptr since the parameter is rb_thread_t*.
* vm_backtrace.c (rb_threadptr_backtrace_location_ary): ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58377 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
|
| |
* vm.c (hook_before_rewind): skip rewind hooks if err is SystemStackError
because rewind hooks can cause stack overflow again and again.
* thread.c (ruby_thread_stack_overflow): do not disable all hooks.
Additionally, clearing ruby_vm_event_flags is not suitable way
to disable hooks.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58349 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
| |
* thread.c (ruby_thread_stack_overflow): disable VM events when
stack overflow occurred; it causes another stack overflow again
in making backtrace object, and crashes.
[ruby-core:80662] [Bug #13425]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58334 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* thread.c (ruby_thread_stack_overflow): check if the given thread
is during GC.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58328 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
| |
* thread.c (Init_Thread): [EXPERIMENTAL] refine the "stream
closed" special exception message, by explicating that it is
caused by threading. [ruby-core:80583] [Bug #13405]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58286 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
| |
* vm_core.h (ruby_special_exceptions): renamed
ruby_error_closed_stream as ruby_error_stream_closed, like the
message.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58284 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
|
|
| |
I may experiment with M:N threading in coming months. Often I
find myself yearning for the old 1.8 days when spawning threads
was really cheap for network operations. But I also like to use
native blocking recv_io and accept calls for round-robin load
distribution and accessing files on systems with dozens of slow
rotational disks.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
|
| |
* thread.c (rb_vm_proc_local_ep): added.
* cont.c (rb_fiber_start): use rb_vm_proc_local_ep().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57970 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
|
| |
* thread.c (thread_do_start): fix segfault at start with Symbol.
proc created by Symbol#to_proc does not have environment unless
using refinements. [ruby-core:80147] [Bug #13313]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57969 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* thread.c (thread_do_start): extract from a macro in
thread_start_func_2 for debugger.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57968 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
|
|
|
| |
* thread.c (rb_thread_fd_close): remove deprecated. a couple of
external libraries used it. [ruby-core:80078] [Bug #13304]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57950 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
|
| |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|