Project

General

Profile

ActionsLike0

Feature #4347

closed

Tracing cannot be re-enabled after callcc [patch]

Added by quix (James M. Lawrence) almost 14 years ago. Updated over 12 years ago.

Status:
Closed
Target version:
[ruby-core:34998]

Description

=begin
% patch -p1 < test_continuation_tracing.patch
patching file test/ruby/test_continuation.rb
% ./ruby -v test/ruby/test_continuation.rb
ruby 1.9.3dev (2011-01-30 trunk 30735) [i386-darwin9.8.0]
Run options:

Running tests:

......FF

Finished tests in 0.080788s, 99.0246 tests/s, 148.5369 assertions/s.

  1. Failure:
    test_tracing_with_set_trace_func(TestContinuation) [test/ruby/test_continuation.rb:99]:
    <3> expected but was
    <1>.

  2. Failure:
    test_tracing_with_thread_set_trace_func(TestContinuation) [test/ruby/test_continuation.rb:121]:
    <3> expected but was
    <0>.

In thread.c (thread_suppress_tracing) the code after (*func)(arg, running)
is not executed, causing th->tracing to not be cleared.

This two-line patch works, though it may only address a symptom.
=end


Files

test_continuation_tracing.patch (1.22 KB) test_continuation_tracing.patch quix (James M. Lawrence), 01/31/2011 05:32 AM
continuation_tracing.patch (553 Bytes) continuation_tracing.patch quix (James M. Lawrence), 01/31/2011 05:32 AM
192_continuation_tracing.patch (514 Bytes) 192_continuation_tracing.patch patch for 1.9.2 r30696 quix (James M. Lawrence), 02/08/2011 04:30 AM

Updated by mame (Yusuke Endoh) over 13 years ago

  • Assignee changed from ko1 (Koichi Sasada) to mame (Yusuke Endoh)

Hello,

2011/1/31 James M. Lawrence :

In thread.c (thread_suppress_tracing) the code after (*func)(arg, running)
is not executed, causing th->tracing to not be cleared.

This two-line patch works, though it may only address a symptom.

Thank you for your reporting and providing patch.

The root cause of this issue is that Continuation#call ignores
ensure clause:

callcc do |c|
begin
c.call
ensure
p :foo
end
end #=> nothing output

When Continuation#call is executed in the proc of set_trace_func,
it skips the post-processing of set_trace_func, resulting in
corrupt state of rb_thread_t#tracing.

Your patch forces to reset the state when set_trace_func(nil). But
to address this issue fundamentally, Continuation#call must call
current ensure clauses. It needs very hard work, though.

As you know, your patch is not essintial fix, but it works actually
in your example, and looks benign. So I'll import it.

But note that there is still other issues, and that this issue may
have a relapse in future. If you want not to hit a land mine, do
not use callcc seriously. It is very fun, joke feature, I think.

Thanks,

--
Yusuke Endoh

Updated by judofyr (Magnus Holm) over 13 years ago

But note that there is still other issues, and that this issue may
have a relapse in future.  If you want not to hit a land mine, do
not use callcc seriously.  It is very fun, joke feature, I think.

Gotos are a joke feature too… Any chance we can get them in a separate
library like callcc too? :D

Like0Actions #8

Updated by mame (Yusuke Endoh) over 13 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r32597.
James, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • thread.c (set_trace_func, thread_set_trace_func_m): reset tracing
    state when set_trace_func hook is removed. This is workaround patch
    to force to reset tracing state that is broken by continuation call.
    a patch from James M. Lawrence. [Feature #4347] [ruby-core:34998]

  • test/ruby/test_continuation.rb (class TestContinuation): add a test
    for above. a patch from James M. Lawrence.

Updated by mame (Yusuke Endoh) over 13 years ago

  • Status changed from Closed to Assigned
  • Assignee changed from mame (Yusuke Endoh) to kosaki (Motohiro KOSAKI)

Hello,

@James
Sorry, I didn't make the deadline to import your patch.
Kosaki, who is the "virtual" release manager, changed this ticket to
1.9.x feature.
I've just imported it to trunk. It is up to a release manager to
decide whether this is imported to 1.9.3 or not.

@Magnus
If anyone write a patch. :-)

--
Yusuke Endoh

Updated by kosaki (Motohiro KOSAKI) over 13 years ago

  • Assignee changed from kosaki (Motohiro KOSAKI) to mame (Yusuke Endoh)

@James
Sorry, I didn't make the deadline to import your patch.
Kosaki, who is the "virtual" release manager, changed this ticket to
1.9.x feature.
I've just imported it to trunk. It is up to a release manager to
decide whether this is imported to 1.9.3 or not.

Of course, I'd respect your decision. Please commit it to ruby_1_9_3 branch. ;-)

Updated by mame (Yusuke Endoh) over 13 years ago

  • Status changed from Assigned to Closed

Done. Thank you very much!

--
Yusuke Endoh

Updated by ko1 (Koichi Sasada) over 12 years ago

  • Status changed from Closed to Assigned
  • Assignee changed from mame (Yusuke Endoh) to ko1 (Koichi Sasada)

I reopen this ticket. As you say, this is only workaround.

I solve this problem with restoring 'tracing state' (running trace func or not) at Continuation#call. I believe it is not a work around, but essential solution. I revert your proposal and set_trace_func(nil) does not clear tracing state any more.

With this change, your test code go to infinite loop:

example code

require 'continuation'

cont = nil

func = lambda{|*args|
p [1, args]
cont.call(nil)
}

3.times{
cont = callcc{|c| c}

-> (1) call trace func (c-return), (2) call cont.call(nil) and come here!

p cont

if cont
set_trace_func(func)
else
set_trace_func(nil)
end
}

With my patch, this example work fine:

require 'continuation'

cont = nil
func = lambda{|*args|
p [1, args]
cont, c = nil, cont
c.call(nil) if c
}

3.times{|i|
p i
cont = callcc{|c| c}
p cont

if cont
set_trace_func(func)
end
}

I quote mame-san's comment, again.

But note that there is still other issues, and that this issue may have a relapse in future. If you want not to hit a land mine, do not use callcc seriously. It is very fun, joke feature, I think.

Like0Actions #13

Updated by ko1 (Koichi Sasada) over 12 years ago

  • Status changed from Assigned to Closed

This issue was solved with changeset r36715.
James, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • vm_trace.c, vm_core.h: simplify tracing mechanism.
    (1) add rb_hook_list_t data structure which includes
    hooks, events (flag) and need_clean' flag. If the last flag is true, then clean the hooks list. In other words, deleted hooks are contained by hooks'.
    Cleanup process should run before traversing the list.
    (2) Change check mechanism
    See EXEC_EVENT_HOOK() in vm_core.h.
    (3) Add raw' hooks APIs Normal hooks are guarded from exception by rb_protect(). However, this protection is overhead for too simple functions which never cause exceptions. raw' hooks
    are executed without protection and faster.
    Now, we only provide registration APIs. All `raw'
    hooks are kicked under protection (same as normal hooks).
  • include/ruby/ruby.h: remove internal data definition and
    macros.
  • internal.h (ruby_suppress_tracing), vm_trace.c: rename
    ruby_suppress_tracing() to rb_suppress_tracing()
    and remove unused function parameter.
  • parse.y: fix to use renamed rb_suppress_tracing().
  • thread.c (thread_create_core): no need to set RUBY_VM_VM.
  • vm.c (mark_event_hooks): move definition to vm_trace.c.
  • vm.c (ruby_vm_event_flags): add a global variable.
    This global variable represents all of Threads and VM's
    event masks (T1#events | T2#events | ... | VM#events).
    You can check the possibility kick trace func or not
    with ruby_vm_event_flags.
    ruby_vm_event_flags is maintained by vm_trace.c.
  • cont.c (fiber_switch, rb_cont_call): restore tracing status.
    [Feature #4347]
  • test/ruby/test_continuation.rb: ditto.
ActionsLike0

Also available in: Atom PDF