Ejemplo n.º 1
0
/* Broadcast a frame in the network. In most cases, the frame should be able to 
 * reach every node in the network, but no guarantee about this.
 */
uintx flood_broadcast( TiFloodNetwork * net, TiFrame * frame, uint8 option )
{
	uintx count=0;
	uintx i = 0;//todo 
	char * pc;
	
	/* This function will try to put the frame into TiFloodNetwork's internal TX buffer. 
	 * The real sending processing is in flood_evolve(). 
	 */
    i = frame_length( frame);//todo
	
	if (frame_empty(net->txque)) 
	{     
		net->txque->option = option;
		count = frame_totalcopyfrom( net->txque, frame );
        

		frame_skipouter( net->txque, 4, 0 );//todo 执行这一局后frame_length又变回0了!

		frame_setlength( net->txque,(i+4));//todo

		
		// assert( frame_skipouter must be success );
		pc = frame_startptr( net->txque );
		
		PACKET_SET_HOPCOUNT( pc,0 );
		PACKET_SET_MAX_HOPCOUNT(pc , CONFIG_FLOOD_MAX_COUNT );
		PACKET_SET_CURSEQID(pc, net->seqid );
	}

	flood_evolve( net, NULL );
	return count;
}
Ejemplo n.º 2
0
// Transfers the arguments from the top of the previous piece (which the frame
// points to) to the bottom of the new stack segment.
static void transfer_top_arguments(value_t new_piece, frame_t *frame,
    size_t arg_count) {
  frame_t new_frame = frame_empty();
  open_stack_piece(new_piece, &new_frame);
  for (size_t i = 0; i < arg_count; i++) {
    value_t value = frame_peek_value(frame, arg_count - i - 1);
    frame_push_value(&new_frame, value);
  }
  close_frame(&new_frame);
}
Ejemplo n.º 3
0
/* Check for arrived frames, no matter who send them. The frame will be returned 
 * through the parameter "frame" only when the frame's destination matches the current 
 * node. The other frames will be forwarded or discarded.
 */
uintx flood_recv( TiFloodNetwork * net, TiFrame * frame, uint8 option )
{
	uintx count=0;

	flood_evolve( net, NULL );

	if (!frame_empty( net->rxque))
	{
		
		count = frame_totalcopyfrom( frame, net->rxque );
		frame_bufferclear( net->rxque );
	}
	
	return count;
}
Ejemplo n.º 4
0
static void push_stack_piece_bottom_frame(runtime_t *runtime, value_t stack_piece,
    value_t arg_map) {
  frame_t bottom = frame_empty();
  value_t code_block = ROOT(runtime, stack_piece_bottom_code_block);
  // The transferred arguments are going to appear as if they were arguments
  // passed from this frame so we have to "allocate" enough room for them on
  // the stack.
  open_stack_piece(stack_piece, &bottom);
  size_t arg_count = get_array_length(arg_map);
  bool pushed = try_push_new_frame(&bottom,
      get_code_block_high_water_mark(code_block) + arg_count,
      ffSynthetic | ffStackPieceBottom, false);
  CHECK_TRUE("pushing bottom frame", pushed);
  frame_set_code_block(&bottom, code_block);
  frame_set_argument_map(&bottom, arg_map);
  close_frame(&bottom);
}
Ejemplo n.º 5
0
frame_t open_stack(value_t stack) {
  CHECK_FAMILY(ofStack, stack);
  frame_t result = frame_empty();
  open_stack_piece(get_stack_top_piece(stack), &result);
  return result;
}
Ejemplo n.º 6
0
// Runs the given stack within the given ambience until a condition is
// encountered or evaluation completes. This function also bails on and leaves
// it to the surrounding code to report error messages.
static value_t run_stack_pushing_signals(value_t ambience, value_t stack) {
    CHECK_FAMILY(ofAmbience, ambience);
    CHECK_FAMILY(ofStack, stack);
    runtime_t *runtime = get_ambience_runtime(ambience);
    frame_t frame = open_stack(stack);
    code_cache_t cache;
    code_cache_refresh(&cache, &frame);
    E_BEGIN_TRY_FINALLY();
    while (true) {
        opcode_t opcode = (opcode_t) read_short(&cache, &frame, 0);
        TOPIC_INFO(Interpreter, "Opcode: %s (%i)", get_opcode_name(opcode),
                   opcode_counter++);
        IF_EXPENSIVE_CHECKS_ENABLED(MAYBE_INTERRUPT());
        switch (opcode) {
        case ocPush: {
            value_t value = read_value(&cache, &frame, 1);
            frame_push_value(&frame, value);
            frame.pc += kPushOperationSize;
            break;
        }
        case ocPop: {
            size_t count = read_short(&cache, &frame, 1);
            for (size_t i = 0; i < count; i++)
                frame_pop_value(&frame);
            frame.pc += kPopOperationSize;
            break;
        }
        case ocCheckStackHeight: {
            size_t expected = read_short(&cache, &frame, 1);
            size_t height = frame.stack_pointer - frame.frame_pointer;
            CHECK_EQ("stack height", expected, height);
            frame.pc += kCheckStackHeightOperationSize;
            break;
        }
        case ocNewArray: {
            size_t length = read_short(&cache, &frame, 1);
            E_TRY_DEF(array, new_heap_array(runtime, length));
            for (size_t i = 0; i < length; i++) {
                value_t element = frame_pop_value(&frame);
                set_array_at(array, length - i - 1, element);
            }
            frame_push_value(&frame, array);
            frame.pc += kNewArrayOperationSize;
            break;
        }
        case ocInvoke: {
            // Look up the method in the method space.
            value_t tags = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofCallTags, tags);
            value_t fragment = read_value(&cache, &frame, 2);
            CHECK_FAMILY(ofModuleFragment, fragment);
            value_t helper = read_value(&cache, &frame, 3);
            CHECK_FAMILY(ofSignatureMap, helper);
            value_t arg_map;
            value_t method = lookup_method_full(ambience, fragment, tags, &frame,
                                                helper, &arg_map);
            if (in_condition_cause(ccLookupError, method)) {
                log_lookup_error(method, tags, &frame);
                E_RETURN(method);
            }
            // The lookup may have failed with a different condition. Check for that.
            E_TRY(method);
            E_TRY_DEF(code_block, ensure_method_code(runtime, method));
            // We should now have done everything that can fail so we advance the
            // pc over this instruction. In reality we haven't, the frame push op
            // below can fail so we should really push the next frame before
            // storing the pc for this one. Laters.
            frame.pc += kInvokeOperationSize;
            // Push a new activation.
            E_TRY(push_stack_frame(runtime, stack, &frame,
                                   get_code_block_high_water_mark(code_block), arg_map));
            frame_set_code_block(&frame, code_block);
            code_cache_refresh(&cache, &frame);
            break;
        }
        case ocSignalContinue:
        case ocSignalEscape: {
            // Look up the method in the method space.
            value_t tags = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofCallTags, tags);
            frame.pc += kSignalEscapeOperationSize;
            value_t arg_map = whatever();
            value_t handler = whatever();
            value_t method = lookup_signal_handler_method(ambience, tags, &frame,
                             &handler, &arg_map);
            bool is_escape = (opcode == ocSignalEscape);
            if (in_condition_cause(ccLookupError, method)) {
                if (is_escape) {
                    // There was no handler for this so we have to escape out of the
                    // interpreter altogether. Push the signal frame onto the stack to
                    // record the state of it for the enclosing code.
                    E_TRY(push_stack_frame(runtime, stack, &frame, 1, nothing()));
                    // The stack tracing code expects all frames to have a valid code block
                    // object. The rest makes less of a difference.
                    frame_set_code_block(&frame, ROOT(runtime, empty_code_block));
                    E_RETURN(new_signal_condition(is_escape));
                } else {
                    // There was no handler but this is not an escape so we skip over
                    // the post-handler goto to the default block.
                    CHECK_EQ("signal not followed by goto", ocGoto,
                             read_short(&cache, &frame, 0));
                    frame.pc += kGotoOperationSize;
                }
            } else {
                // We found a method. Invoke it.
                E_TRY(method);
                E_TRY_DEF(code_block, ensure_method_code(runtime, method));
                E_TRY(push_stack_frame(runtime, stack, &frame,
                                       get_code_block_high_water_mark(code_block), arg_map));
                frame_set_code_block(&frame, code_block);
                CHECK_TRUE("subject not null", is_null(frame_get_argument(&frame, 0)));
                frame_set_argument(&frame, 0, handler);
                code_cache_refresh(&cache, &frame);
            }
            break;
        }
        case ocGoto: {
            size_t delta = read_short(&cache, &frame, 1);
            frame.pc += delta;
            break;
        }
        case ocDelegateToLambda:
        case ocDelegateToBlock: {
            // This op only appears in the lambda and block delegator methods.
            // They should never be executed because the delegation happens during
            // method lookup. If we hit here something's likely wrong with the
            // lookup process.
            UNREACHABLE("delegate to lambda");
            return new_condition(ccWat);
        }
        case ocBuiltin: {
            value_t wrapper = read_value(&cache, &frame, 1);
            builtin_method_t impl = (builtin_method_t) get_void_p_value(wrapper);
            builtin_arguments_t args;
            builtin_arguments_init(&args, runtime, &frame);
            E_TRY_DEF(result, impl(&args));
            frame_push_value(&frame, result);
            frame.pc += kBuiltinOperationSize;
            break;
        }
        case ocBuiltinMaybeEscape: {
            value_t wrapper = read_value(&cache, &frame, 1);
            builtin_method_t impl = (builtin_method_t) get_void_p_value(wrapper);
            builtin_arguments_t args;
            builtin_arguments_init(&args, runtime, &frame);
            value_t result = impl(&args);
            if (in_condition_cause(ccSignal, result)) {
                // The builtin failed. Find the appropriate signal handler and call
                // it. The invocation record is at the top of the stack.
                value_t tags = frame_pop_value(&frame);
                CHECK_FAMILY(ofCallTags, tags);
                value_t arg_map = whatever();
                value_t handler = whatever();
                value_t method = lookup_signal_handler_method(ambience, tags, &frame,
                                 &handler, &arg_map);
                if (in_condition_cause(ccLookupError, method)) {
                    // Push the record back onto the stack to it's available to back
                    // tracing.
                    frame_push_value(&frame, tags);
                    frame.pc += kBuiltinMaybeEscapeOperationSize;
                    // There was no handler for this so we have to escape out of the
                    // interpreter altogether. Push the signal frame onto the stack to
                    // record the state of it for the enclosing code.
                    E_TRY(push_stack_frame(runtime, stack, &frame, 1, nothing()));
                    // The stack tracing code expects all frames to have a valid code block
                    // object. The rest makes less of a difference.
                    frame_set_code_block(&frame, ROOT(runtime, empty_code_block));
                    E_RETURN(new_signal_condition(true));
                }
                // Either found a signal or encountered a different condition.
                E_TRY(method);
                // Skip forward to the point we want the signal to return to, the
                // leave-or-fire-barrier op that will do the leaving.
                size_t dest_offset = read_short(&cache, &frame, 2);
                frame.pc += dest_offset;
                // Run the handler.
                E_TRY_DEF(code_block, ensure_method_code(runtime, method));
                E_TRY(push_stack_frame(runtime, stack, &frame,
                                       get_code_block_high_water_mark(code_block), arg_map));
                frame_set_code_block(&frame, code_block);
                CHECK_TRUE("subject not null", is_null(frame_get_argument(&frame, 0)));
                frame_set_argument(&frame, 0, handler);
                code_cache_refresh(&cache, &frame);
            } else {
                // The builtin didn't cause a condition so we can just keep going.
                E_TRY(result);
                frame_push_value(&frame, result);
                frame.pc += kBuiltinMaybeEscapeOperationSize;
            }
            break;
        }
        case ocReturn: {
            value_t result = frame_pop_value(&frame);
            frame_pop_within_stack_piece(&frame);
            code_cache_refresh(&cache, &frame);
            frame_push_value(&frame, result);
            break;
        }
        case ocStackBottom: {
            value_t result = frame_pop_value(&frame);
            validate_stack_on_normal_exit(&frame);
            E_RETURN(result);
        }
        case ocStackPieceBottom: {
            value_t top_piece = frame.stack_piece;
            value_t result = frame_pop_value(&frame);
            value_t next_piece = get_stack_piece_previous(top_piece);
            set_stack_top_piece(stack, next_piece);
            frame = open_stack(stack);
            code_cache_refresh(&cache, &frame);
            frame_push_value(&frame, result);
            break;
        }
        case ocSlap: {
            value_t value = frame_pop_value(&frame);
            size_t argc = read_short(&cache, &frame, 1);
            for (size_t i = 0; i < argc; i++)
                frame_pop_value(&frame);
            frame_push_value(&frame, value);
            frame.pc += kSlapOperationSize;
            break;
        }
        case ocNewReference: {
            // Create the reference first so that if it fails we haven't clobbered
            // the stack yet.
            E_TRY_DEF(ref, new_heap_reference(runtime, nothing()));
            value_t value = frame_pop_value(&frame);
            set_reference_value(ref, value);
            frame_push_value(&frame, ref);
            frame.pc += kNewReferenceOperationSize;
            break;
        }
        case ocSetReference: {
            value_t ref = frame_pop_value(&frame);
            CHECK_FAMILY(ofReference, ref);
            value_t value = frame_peek_value(&frame, 0);
            set_reference_value(ref, value);
            frame.pc += kSetReferenceOperationSize;
            break;
        }
        case ocGetReference: {
            value_t ref = frame_pop_value(&frame);
            CHECK_FAMILY(ofReference, ref);
            value_t value = get_reference_value(ref);
            frame_push_value(&frame, value);
            frame.pc += kGetReferenceOperationSize;
            break;
        }
        case ocLoadLocal: {
            size_t index = read_short(&cache, &frame, 1);
            value_t value = frame_get_local(&frame, index);
            frame_push_value(&frame, value);
            frame.pc += kLoadLocalOperationSize;
            break;
        }
        case ocLoadGlobal: {
            value_t ident = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofIdentifier, ident);
            value_t fragment = read_value(&cache, &frame, 2);
            CHECK_FAMILY(ofModuleFragment, fragment);
            value_t module = get_module_fragment_module(fragment);
            E_TRY_DEF(value, module_lookup_identifier(runtime, module,
                      get_identifier_stage(ident), get_identifier_path(ident)));
            frame_push_value(&frame, value);
            frame.pc += kLoadGlobalOperationSize;
            break;
        }
        case ocLoadArgument: {
            size_t param_index = read_short(&cache, &frame, 1);
            value_t value = frame_get_argument(&frame, param_index);
            frame_push_value(&frame, value);
            frame.pc += kLoadArgumentOperationSize;
            break;
        }
        case ocLoadRefractedArgument: {
            size_t param_index = read_short(&cache, &frame, 1);
            size_t block_depth = read_short(&cache, &frame, 2);
            value_t subject = frame_get_argument(&frame, 0);
            frame_t home = frame_empty();
            get_refractor_refracted_frame(subject, block_depth, &home);
            value_t value = frame_get_argument(&home, param_index);
            frame_push_value(&frame, value);
            frame.pc += kLoadRefractedArgumentOperationSize;
            break;
        }
        case ocLoadRefractedLocal: {
            size_t index = read_short(&cache, &frame, 1);
            size_t block_depth = read_short(&cache, &frame, 2);
            value_t subject = frame_get_argument(&frame, 0);
            frame_t home = frame_empty();
            get_refractor_refracted_frame(subject, block_depth, &home);
            value_t value = frame_get_local(&home, index);
            frame_push_value(&frame, value);
            frame.pc += kLoadRefractedLocalOperationSize;
            break;
        }
        case ocLoadLambdaCapture: {
            size_t index = read_short(&cache, &frame, 1);
            value_t subject = frame_get_argument(&frame, 0);
            CHECK_FAMILY(ofLambda, subject);
            value_t value = get_lambda_capture(subject, index);
            frame_push_value(&frame, value);
            frame.pc += kLoadLambdaCaptureOperationSize;
            break;
        }
        case ocLoadRefractedCapture: {
            size_t index = read_short(&cache, &frame, 1);
            size_t block_depth = read_short(&cache, &frame, 2);
            value_t subject = frame_get_argument(&frame, 0);
            frame_t home = frame_empty();
            get_refractor_refracted_frame(subject, block_depth, &home);
            value_t lambda = frame_get_argument(&home, 0);
            CHECK_FAMILY(ofLambda, lambda);
            value_t value = get_lambda_capture(lambda, index);
            frame_push_value(&frame, value);
            frame.pc += kLoadRefractedLocalOperationSize;
            break;
        }
        case ocLambda: {
            value_t space = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofMethodspace, space);
            size_t capture_count = read_short(&cache, &frame, 2);
            value_t captures;
            E_TRY_DEF(lambda, new_heap_lambda(runtime, space, nothing()));
            if (capture_count == 0) {
                captures = ROOT(runtime, empty_array);
                frame.pc += kLambdaOperationSize;
            } else {
                E_TRY_SET(captures, new_heap_array(runtime, capture_count));
                // The pc gets incremented here because it is after we've done all
                // the allocation but before anything has been popped off the stack.
                // This way all the above is idempotent, and the below is guaranteed
                // to succeed.
                frame.pc += kLambdaOperationSize;
                for (size_t i = 0; i < capture_count; i++)
                    set_array_at(captures, i, frame_pop_value(&frame));
            }
            set_lambda_captures(lambda, captures);
            frame_push_value(&frame, lambda);
            break;
        }
        case ocCreateBlock: {
            value_t space = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofMethodspace, space);
            // Create the block object.
            E_TRY_DEF(block, new_heap_block(runtime, nothing()));
            // Create the stack section that describes the block.
            value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgBlockSection));
            set_barrier_state_payload(section, block);
            refraction_point_init(section, &frame);
            set_block_section_methodspace(section, space);
            set_block_section(block, section);
            value_validate(block);
            value_validate(section);
            // Push the block object.
            frame_push_value(&frame, block);
            frame.pc += kCreateBlockOperationSize;
            break;
        }
        case ocCreateEnsurer: {
            value_t code_block = read_value(&cache, &frame, 1);
            value_t section = frame_alloc_derived_object(&frame,
                              get_genus_descriptor(dgEnsureSection));
            set_barrier_state_payload(section, code_block);
            refraction_point_init(section, &frame);
            value_validate(section);
            frame_push_value(&frame, section);
            frame.pc += kCreateEnsurerOperationSize;
            break;
        }
        case ocCallEnsurer: {
            value_t value = frame_pop_value(&frame);
            value_t shard = frame_pop_value(&frame);
            frame_push_value(&frame, value);
            frame_push_value(&frame, shard);
            CHECK_GENUS(dgEnsureSection, shard);
            value_t code_block = get_barrier_state_payload(shard);
            CHECK_FAMILY(ofCodeBlock, code_block);
            // Unregister the barrier before calling it, otherwise if we leave
            // by escaping we'll end up calling it over again.
            barrier_state_unregister(shard, stack);
            frame.pc += kCallEnsurerOperationSize;
            value_t argmap = ROOT(runtime, array_of_zero);
            push_stack_frame(runtime, stack, &frame,
                             get_code_block_high_water_mark(code_block), argmap);
            frame_set_code_block(&frame, code_block);
            code_cache_refresh(&cache, &frame);
            break;
        }
        case ocDisposeEnsurer: {
            // Discard the result of the ensure block. If an ensure blocks needs
            // to return a useful value it can do it via an escape.
            frame_pop_value(&frame);
            value_t shard = frame_pop_value(&frame);
            CHECK_GENUS(dgEnsureSection, shard);
            value_t value = frame_pop_value(&frame);
            frame_destroy_derived_object(&frame, get_genus_descriptor(dgEnsureSection));
            frame_push_value(&frame, value);
            frame.pc += kDisposeEnsurerOperationSize;
            break;
        }
        case ocInstallSignalHandler: {
            value_t space = read_value(&cache, &frame, 1);
            CHECK_FAMILY(ofMethodspace, space);
            size_t dest_offset = read_short(&cache, &frame, 2);
            // Allocate the derived object that's going to hold the signal handler
            // state.
            value_t section = frame_alloc_derived_object(&frame,
                              get_genus_descriptor(dgSignalHandlerSection));
            // Initialize the handler.
            set_barrier_state_payload(section, space);
            refraction_point_init(section, &frame);
            // Bring the frame state to the point we'll want to escape to (modulo
            // the destination offset).
            frame_push_value(&frame, section);
            frame.pc += kInstallSignalHandlerOperationSize;
            // Finally capture the escape state.
            capture_escape_state(section, &frame, dest_offset);
            value_validate(section);
            break;
        }
        case ocUninstallSignalHandler: {
            // The result has been left at the top of the stack.
            value_t value = frame_pop_value(&frame);
            value_t section = frame_pop_value(&frame);
            CHECK_GENUS(dgSignalHandlerSection, section);
            barrier_state_unregister(section, stack);
            frame_destroy_derived_object(&frame, get_genus_descriptor(dgSignalHandlerSection));
            frame_push_value(&frame, value);
            frame.pc += kUninstallSignalHandlerOperationSize;
            break;
        }
        case ocCreateEscape: {
            size_t dest_offset = read_short(&cache, &frame, 1);
            // Create an initially empty escape object.
            E_TRY_DEF(escape, new_heap_escape(runtime, nothing()));
            // Allocate the escape section on the stack, hooking the barrier into
            // the barrier chain.
            value_t section = frame_alloc_derived_object(&frame, get_genus_descriptor(dgEscapeSection));
            // Point the state and object to each other.
            set_barrier_state_payload(section, escape);
            set_escape_section(escape, section);
            // Get execution ready for the next operation.
            frame_push_value(&frame, escape);
            frame.pc += kCreateEscapeOperationSize;
            // This is the execution state the escape will escape to (modulo the
            // destination offset) so this is what we want to capture.
            capture_escape_state(section, &frame,
                                 dest_offset);
            break;
        }
        case ocLeaveOrFireBarrier: {
            size_t argc = read_short(&cache, &frame, 1);
            // At this point the handler has been set as the subject of the call
            // to the handler method. Above the arguments are also two scratch
            // stack entries.
            value_t handler = frame_peek_value(&frame, argc + 2);
            CHECK_GENUS(dgSignalHandlerSection, handler);
            if (maybe_fire_next_barrier(&cache, &frame, runtime, stack, handler)) {
                // Pop the scratch entries off.
                frame_pop_value(&frame);
                frame_pop_value(&frame);
                // Pop the value off.
                value_t value = frame_pop_value(&frame);
                // Escape to the handler's home.
                restore_escape_state(&frame, stack, handler);
                code_cache_refresh(&cache, &frame);
                // Push the value back on, now in the handler's home frame.
                frame_push_value(&frame, value);
            } else {
                // If a barrier was fired we'll want to let the interpreter loop
                // around again so just break without touching .pc.
            }
            break;
        }
        case ocFireEscapeOrBarrier: {
            value_t escape = frame_get_argument(&frame, 0);
            CHECK_FAMILY(ofEscape, escape);
            value_t section = get_escape_section(escape);
            // Fire the next barrier or, if there are no more barriers, apply the
            // escape.
            if (maybe_fire_next_barrier(&cache, &frame, runtime, stack, section)) {
                value_t value = frame_get_argument(&frame, 2);
                restore_escape_state(&frame, stack, section);
                code_cache_refresh(&cache, &frame);
                frame_push_value(&frame, value);
            } else {
                // If a barrier was fired we'll want to let the interpreter loop
                // around again so just break without touching .pc.
            }
            break;
        }
        case ocDisposeEscape: {
            value_t value = frame_pop_value(&frame);
            value_t escape = frame_pop_value(&frame);
            CHECK_FAMILY(ofEscape, escape);
            value_t section = get_escape_section(escape);
            value_validate(section);
            barrier_state_unregister(section, stack);
            on_escape_section_exit(section);
            frame_destroy_derived_object(&frame, get_genus_descriptor(dgEscapeSection));
            frame_push_value(&frame, value);
            frame.pc += kDisposeEscapeOperationSize;
            break;
        }
        case ocDisposeBlock: {
            value_t value = frame_pop_value(&frame);
            value_t block = frame_pop_value(&frame);
            CHECK_FAMILY(ofBlock, block);
            value_t section = get_block_section(block);
            barrier_state_unregister(section, stack);
            on_block_section_exit(section);
            frame_destroy_derived_object(&frame, get_genus_descriptor(dgBlockSection));
            frame_push_value(&frame, value);
            frame.pc += kDisposeBlockOperationSize;
            break;
        }
        default:
            ERROR("Unexpected opcode %i", opcode);
            UNREACHABLE("unexpected opcode");
            break;
        }
    }
    E_FINALLY();
    close_frame(&frame);
    E_END_TRY_FINALLY();
}
Ejemplo n.º 7
0
/* This function receive event from other services/objects and drive the evolution 
 * of the TiFloodNetwork service. 
 * 
 * This function can also be the listener of the MAC layer, Though it's not mandatory.
 * 
 * @attention: 
 *	This function cannot run in the interrupt mode.
 */
void flood_evolve( void * netptr, TiEvent * e )
{
	TiFloodNetwork * net = (TiFloodNetwork *)netptr;
	uint8 len, count, cur_hopcount, max_hopcount;
	bool done = true, cont= false;
	char * pc;

	aloha_evolve( net->mac,e );

	// This event is sent from MAC layer. 
	//
	// @todo
	// Currently, all the frames from MAC layer will submitted the listener function.
	// Actually, this isn't necessary. Only those to this node should submitted to 
	// the listener.
	//
	if (e->id == EVENT_DATA_ARRIVAL)
	{
		if (net->listener != NULL)
		{
			net->listener( net->lisowner, e );
			return;
		}
	}

	do{ 
		
		switch (net->state)
		{
		// IDLE is the initial and default state of this state machine. 
		case FLOOD_STATE_IDLE:

			
			// Check if the TX queue is empty. If not then try to send the frame.
			if (!frame_empty(net->txque))
			{   
				
				len = aloha_broadcast( net->mac, net->txque, net->txque->option );
				
				if (len > 0)
				{
					frame_bufferclear( net->txque );
				}

				// @attention
				// @todo: if the aloha_send() is non-blocked operation, then you should
				// transfer to FLOOD_STATE_WAITFOR_TXREPLY state to wait. You should empty
				// the buffer only when this service receives the reply from MAC layer.
				
				 //net->state = FLOOD_STATE_WAIT_TXREPLY
				 done = true;
			}
		
			// Check if the RX queue is empty, then try to receive one from MAC layer
          	if ((frame_empty(net->rxbuf)) && frame_empty(net->rxque))
			{   
				cont = true;
				count = aloha_recv( net->mac, net->rxbuf, 0x00 );
				
				if (count <= 0)
					cont = false;

				// Check: whether the same frame has already been received. This
				// is by searching it in the cache. If it cannot find it in the 
				// cache, then put the frame in the cache.
				//
				// @modified by zhangwei on 2011.03.14
				// - we use the first 4 bytes in the frame (which is essentially 
				// the header of flood protocol as the key to visit the cache.
				//
	            if (cont)
				{   
					if (flood_cache_visit( net->cache, (char*)frame_startptr(net->rxbuf) ))//todo 我将CONFIG_FLOOD_CACHE_CAPACITY改成了1原先为8,不改的话不再接收新的帧.
					{   
						
						frame_bufferclear( net->rxbuf );
						cont = false;
					}
				}

				if (cont)
				{     
					frame_totalcopyto( net->rxbuf, net->rxque );
                  
					// Check whether this frame has reaches its maximum hopcount. 
					// Discard this frame if this is true.
					
					char * pc;
					pc = frame_startptr( net->rxbuf);

					cur_hopcount = PACKET_CUR_HOPCOUNT( pc );
					max_hopcount = PACKET_MAX_HOPCOUNT( pc);
					cur_hopcount ++;
					if (cur_hopcount > max_hopcount)
						frame_bufferclear( net->rxbuf );
					else
						PACKET_SET_HOPCOUNT( pc, cur_hopcount );
				}
				
				done = true;
			}

			// Check whether there's frame pending for forwarding
			if ((!frame_empty(net->rxbuf)) && frame_empty(net->txque))
			{   
				pc = frame_startptr( net->txque);
				// move the frame from rxbuf to txque. For efficiency reasons, this is implmented
				// by switching the two pointers.				 
				_switch_ptr( &(net->rxbuf), &(net->txque) );
				
				// @attention
				// generally, you should change the frame in "txque" with the PAN id
                // and BROADCAST_ADDRESS configured in this flood component. However,
				// here we assume the low level medium access protocol helps us to do so.

				cur_hopcount = PACKET_CUR_HOPCOUNT( pc );
				PACKET_SET_HOPCOUNT( pc, cur_hopcount++ );
				done = false;
			}	
			break;


		// This's the state waiting for MAC layer's reply. The sending process of the 
		// MAC layer may last for quite a long time due to re-transmission. Only at the
		// end of the transmission, the MAC layer does possible to notify the NET layer 
		// the transmission results of the sending request.
		//
		/*case FLOOD_STATE_WAITFOR_TXREPLY:
			 ioresult = aloha_ioresult(net->mac);
			 if ioresult == IDLE|TXDONE
			 {
					opf_clear( net->txque );
					net->state = FLOOD_STATE_IDLE;
			 }
			// if ioresult indicate there's error or failure
			//	report to the master program by call net->listener
			net->state = FLOOD_STATE_IDLE;
			break;*/

		default:
			net->state = FLOOD_STATE_IDLE;
		}
	}while (!done);

	return;
}