/*
 *  call-seq:
 *     cont.call(args, ...)
 *     cont[args, ...]
 *  
 *  Invokes the continuation. The program continues from the end of the
 *  <code>callcc</code> block. If no arguments are given, the original
 *  <code>callcc</code> returns <code>nil</code>. If one argument is
 *  given, <code>callcc</code> returns it. Otherwise, an array
 *  containing <i>args</i> 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.trap_tag != th->trap_tag) {
        rb_raise(rb_eRuntimeError, "continuation called across trap");
    }
    if (cont->saved_thread.fiber) {
        rb_context_t *fcont;
        GetContPtr(cont->saved_thread.fiber, fcont);

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

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

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