In Files

  • cont.c

Parent

Methods

Continuation

Continuation objects are generated by Kernel#callcc. They hold a return address and execution context, allowing a nonlocal return to the end of the callcc block from anywhere within a program. Continuations are somewhat analogous to a structured version of C's setjmp/longjmp (although they contain more state, so you might consider them closer to threads).

For instance:

arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
callcc{|$cc|}
puts(message = arr.shift)
$cc.call unless message =~ /Max/

produces:

Freddie
Herbie
Ron
Max

This (somewhat contrived) example allows the inner loop to abandon processing early:

callcc {|cont|
  for i in 0..4
    print "\n#{i}: "
    for j in i*5...(i+1)*5
      cont.call() if j == 17
      printf "%3d", j
    end
  end
}
print "\n"

produces:

0:   0  1  2  3  4
1:   5  6  7  8  9
2:  10 11 12 13 14
3:  15 16

Public Instance Methods

cont[args, ...] click to toggle source

Invokes the continuation. The program continues from the end of the callcc block. If no arguments are given, the original callcc returns nil. If one argument is given, callcc returns it. Otherwise, an array containing args is returned.

callcc {|cont|  cont.call }           #=> nil
callcc {|cont|  cont.call 1 }         #=> 1
callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]
 
               static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
    rb_context_t *cont;
    rb_thread_t *th = GET_THREAD();
    GetContPtr(contval, cont);

    if (cont->saved_thread.self != th->self) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (cont->saved_thread.protect_tag != th->protect_tag) {
        rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
    }
    if (cont->saved_thread.fiber) {
        rb_fiber_t *fcont;
        GetFiberPtr(cont->saved_thread.fiber, fcont);

        if (th->fiber != cont->saved_thread.fiber) {
            rb_raise(rb_eRuntimeError, "continuation called across fiber");
        }
    }

    cont->argc = argc;
    cont->value = make_passing_arg(argc, argv);

    cont_restore_0(cont, &contval);
    return Qnil; /* unreachable */
}
            
call(args, ...) click to toggle source

Invokes the continuation. The program continues from the end of the callcc block. If no arguments are given, the original callcc returns nil. If one argument is given, callcc returns it. Otherwise, an array containing args is returned.

callcc {|cont|  cont.call }           #=> nil
callcc {|cont|  cont.call 1 }         #=> 1
callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]
 
               static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
    rb_context_t *cont;
    rb_thread_t *th = GET_THREAD();
    GetContPtr(contval, cont);

    if (cont->saved_thread.self != th->self) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (cont->saved_thread.protect_tag != th->protect_tag) {
        rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
    }
    if (cont->saved_thread.fiber) {
        rb_fiber_t *fcont;
        GetFiberPtr(cont->saved_thread.fiber, fcont);

        if (th->fiber != cont->saved_thread.fiber) {
            rb_raise(rb_eRuntimeError, "continuation called across fiber");
        }
    }

    cont->argc = argc;
    cont->value = make_passing_arg(argc, argv);

    cont_restore_0(cont, &contval);
    return Qnil; /* unreachable */
}
            

Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.

If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.

If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.

If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.

blog comments powered by Disqus