Exemplo n.º 1
0
static void
next_init(VALUE obj, struct enumerator *e)
{
    VALUE curr = rb_fiber_current();
    e->dst = curr;
    e->fib = rb_fiber_new(next_i, obj);
}
Exemplo n.º 2
0
Arquivo: cont.c Projeto: genki/ruby
static inline VALUE
fiber_switch(VALUE fib, int argc, VALUE *argv, int is_resume)
{
    VALUE value;
    rb_context_t *cont;
    rb_thread_t *th = GET_THREAD();

    GetContPtr(fib, cont);

    if (cont->saved_thread.self != th->self) {
	rb_raise(rb_eFiberError, "fiber called across threads");
    }
    else if (cont->saved_thread.trap_tag != th->trap_tag) {
	rb_raise(rb_eFiberError, "fiber called across trap");
    }
    else if (!cont->alive) {
	rb_raise(rb_eFiberError, "dead fiber called");
    }

    if (is_resume) {
	cont->prev = rb_fiber_current();
    }

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

    if ((value = fiber_store(cont)) == Qundef) {
	cont_restore_0(cont, &value);
	rb_bug("rb_fiber_resume: unreachable");
    }

    RUBY_VM_CHECK_INTS();

    return value;
}
Exemplo n.º 3
0
static void
fiber_link_join(rb_fiber_t *fib)
{
    VALUE current_fibval = rb_fiber_current();
    rb_fiber_t *current_fib;
    GetFiberPtr(current_fibval, current_fib);

    /* join fiber link */
    fib->next_fiber = current_fib->next_fiber;
    fib->prev_fiber = current_fib;
    current_fib->next_fiber->prev_fiber = fib;
    current_fib->next_fiber = fib;
}
Exemplo n.º 4
0
static VALUE
enumerator_next(VALUE obj)
{
    struct enumerator *e = enumerator_ptr(obj);
    VALUE curr, v;
    curr = rb_fiber_current();

    if (!e->fib || !rb_fiber_alive_p(e->fib)) {
        next_init(obj, e);
    }

    v = rb_fiber_resume(e->fib, 1, &curr);
    if (e->no_next) {
        e->fib = 0;
        e->dst = Qnil;
        e->no_next = Qfalse;
        rb_raise(rb_eStopIteration, "iteration reached at end");
    }
    return v;
}
Exemplo n.º 5
0
static VALUE
return_fiber(void)
{
    rb_fiber_t *fib;
    VALUE curr = rb_fiber_current();
    GetFiberPtr(curr, fib);

    if (fib->prev == Qnil) {
	rb_thread_t *th = GET_THREAD();

	if (th->root_fiber != curr) {
	    return th->root_fiber;
	}
	else {
	    rb_raise(rb_eFiberError, "can't yield from root fiber");
	}
    }
    else {
	VALUE prev = fib->prev;
	fib->prev = Qnil;
	return prev;
    }
}
Exemplo n.º 6
0
Arquivo: cont.c Projeto: genki/ruby
static VALUE
return_fiber(void)
{
    rb_context_t *cont;
    VALUE curr = rb_fiber_current();
    GetContPtr(curr, cont);

    if (cont->prev == Qnil) {
	rb_thread_t *th = GET_THREAD();

	if (th->root_fiber != curr) {
	    return th->root_fiber;
	}
	else {
	    rb_raise(rb_eFiberError, "can't yield from root fiber");
	}
    }
    else {
	VALUE prev = cont->prev;
	cont->prev = Qnil;
	return prev;
    }
}
Exemplo n.º 7
0
static VALUE
get_next_values(VALUE obj, struct enumerator *e)
{
    VALUE curr, vs;

    if (e->stop_exc)
	rb_exc_raise(e->stop_exc);

    curr = rb_fiber_current();

    if (!e->fib || !rb_fiber_alive_p(e->fib)) {
	next_init(obj, e);
    }

    vs = rb_fiber_resume(e->fib, 1, &curr);
    if (e->stop_exc) {
	e->fib = 0;
	e->dst = Qnil;
	e->lookahead = Qundef;
	e->feedvalue = Qundef;
	rb_exc_raise(e->stop_exc);
    }
    return vs;
}
Exemplo n.º 8
0
/*
 *  call-seq:
 *     Fiber.current() -> fiber
 *  
 *  Returns the current fiber. You need to <code>require 'fiber'</code>
 *  before using this method. If you are not running in the context of
 *  a fiber this method will return the root fiber.
 */
static VALUE
rb_fiber_s_current(VALUE klass)
{
    return rb_fiber_current();
}
Exemplo n.º 9
0
VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame(	rb_control_frame_t**		c_current_frame )	{

	const char*		c_method_name		=	NULL;
	int				c_sourcefile_line	=	0;
	
	//	create new hash for this frame
	VALUE	rb_frame_hash			=	rb_hash_new();
		
	VALUE	rb_sourcefile_name		=	Qnil;
	VALUE	rb_sourcefile_line		=	Qnil;
	VALUE	rb_method_name			=	Qnil;
	VALUE	rb_object_for_frame		=	Qnil;
	
	if ( ( *c_current_frame )->iseq != 0 ) {
		
		if ( ( *c_current_frame )->pc != 0 ) {
			
			rb_iseq_t *iseq			= ( *c_current_frame )->iseq;
			
			//	get sourcefile name and set in hash
			rb_sourcefile_name		=	iseq->filename;
			
			//	get sourcefile line and set in hash
			c_sourcefile_line		=	rb_vm_get_sourceline( *c_current_frame );
			rb_sourcefile_line		=	INT2FIX( c_sourcefile_line );
			
			//	get name of instruction sequence
			rb_method_name			=	ID2SYM( rb_intern( StringValuePtr( iseq->name ) ) );				
			rb_object_for_frame	=	( *c_current_frame )->self;
		}
	}
	else if ( RUBYVM_CFUNC_FRAME_P( *c_current_frame ) ) {
		
		//	get name of method

		#if RUBY_PATCHLEVEL >= -1
		//	For 1.9.2:
		const rb_method_entry_t*	c_method_for_frame	=	( *c_current_frame )->me;
		c_method_name				=	rb_id2name( c_method_for_frame->called_id );
		#else
		//	For 1.9.1:
		c_method_name				=	rb_id2name( ( *c_current_frame )->method_id );
		#endif
		
		rb_method_name				=	( c_method_name == NULL ? Qnil : ID2SYM( rb_intern( c_method_name ) ) );
		rb_object_for_frame	=	( *c_current_frame )->self;		
	}
	//	we have to test this case - it works for blocks but there may be other cases too
	else if (	( *c_current_frame )->block_iseq != 0
			 &&	( *c_current_frame )->pc == 0)	{
	
		//	If we got here we have a fiber
		//	There doesn't seem to be much that we can tell about a fiber's context
			
		VALUE			rb_current_fiber	=	rb_fiber_current();
		rb_fiber_t*		c_current_fiber		=	NULL;

		GetFiberPtr(	rb_current_fiber, 
						c_current_fiber);
						
		rb_context_t*	c_context			=	& c_current_fiber->cont;
		
//		rb_block_t*	c_blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP( *c_current_frame );
		 
		rb_object_for_frame	=	( *c_current_frame )->self;
		
		//	get sourcefile name and set in hash
		rb_sourcefile_name		=	Qnil;

		//	get sourcefile line and set in hash
		rb_sourcefile_line		=	Qnil;
		
		//	get name of instruction sequence
		rb_method_name			=	rb_str_new2( "<Fiber>" );		
		
		//	if we have a fiber we also include its ruby reference since we have so little other context
		rb_hash_aset(	rb_frame_hash,
						ID2SYM( rb_intern( "fiber" ) ),
						c_context->self );
		
		//	The one time that we know a fiber is in use in the Ruby base is with Enumerators
		//	For now we will handle that with a special case
		
		VALUE	rb_enumerator_class	=	rb_const_get(	rb_cObject,
														rb_intern( "Enumerator" ) );
		
		VALUE	rb_object_for_frame_klass	=	( ( TYPE( rb_object_for_frame ) == T_CLASS ) ? rb_object_for_frame : rb_funcall( rb_object_for_frame, rb_intern( "class" ), 0 ) );

		VALUE	rb_ancestors	=	rb_funcall(	rb_object_for_frame_klass,
												rb_intern( "ancestors" ),
												0 );
		
		if ( rb_ary_includes(	rb_ancestors,
								rb_enumerator_class ) )	{
			
			struct enumerator* c_enumerator		=	enumerator_ptr( rb_object_for_frame );
			
			rb_object_for_frame	=	c_enumerator->obj;
			rb_method_name		=	ID2SYM( c_enumerator->meth );			
		}
		
	}
	else if (	( *c_current_frame )->block_iseq == 0
			 &&	( *c_current_frame )->pc == 0)	{
		//	this happens after we had a fiber and we try to go up - which doesn't make sense with a fiber
		//	not sure what we want to do here, if anything
		return Qnil;
	}
	else {
		//	The third possibility is that we have an iseq frame with nil params for what we want
		//	In that case we can simply return the next frame
		*c_current_frame	=	RUBY_VM_PREVIOUS_CONTROL_FRAME( *c_current_frame );
		
		//	in theory this could crash because we are going forward a frame when we don't know what's there
		//	in practice I think we are ok, since we are only jumping forward from nil frames which should never be at the end
		//	at least - I don't think they should... we shall see.
		//	
		//	a fix would be to check the next frame, but that requires access to the thread or the limit cfp, 
		//	which requires passing more context; so for now, I'm leaving it there
		
		return rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( c_current_frame );
	}

	//	Push values to return hash

	rb_hash_aset(	rb_frame_hash,
					ID2SYM( rb_intern( "object" ) ),
					rb_object_for_frame );
					
	rb_hash_aset(	rb_frame_hash,
					ID2SYM( rb_intern( "file" ) ),
					rb_sourcefile_name );

	rb_hash_aset(	rb_frame_hash,
					ID2SYM( rb_intern( "line" ) ),
					rb_sourcefile_line );

	rb_hash_aset(	rb_frame_hash,
					ID2SYM( rb_intern( "method" ) ),
					rb_method_name );
	
	return rb_frame_hash;
}