⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bombilla.tex

📁 tinyos中文手册,是根据tinyos系统自带手册翻译过来的,虽然质量不好,但是对英文不强的人还是有用的
💻 TEX
📖 第 1 页 / 共 3 页
字号:
    interface BombillaStacks;    interface BombillaTypes;  }}implementation {}\end{verbatim}They do not actually provide a service; instead, they represent asingle, common wiring point for all users of that service. Then, thetop-level VM configuration can pick an implementation of that service andwire it to the proxy:\begin{verbatim}configuration AbstractMate{}implementation {  components BStacks, BStacksProxy;  BStacksProxy.BombillaStacks -> BStacks;  BStacksProxy.BombillaTypes -> BStacks;}\end{verbatim}This abstraction is necessary for when there are multiple versions ofa service, and a single implementation needs to be chosen for theentire VM. For example, there are two providers of {\ttBombillaLocks}: {\tt BLocks} and {\tt BLocksSafe}. The former is afast and efficient implementation, while the latter performsadditional checks in case callers have errors in their logic (e.g.,unlocking locks they do not hold). The implementation can be changedby modifying a single line in the VM configuration.\subsection{Instruction Examples}Every instruction component must provide the {\tt BombillaBytecode}interface, which the {\tt BombillaEngine} calls when it reaches theassociated opcode in a program. Perhaps the simplest \bomb instructionis {\tt pop}, which pops an operand off the operand stack. This is thecomplete code for the {\tt OPpopM} module:\begin{verbatim}includes Bombilla;includes BombillaMsgs;module OPpopM {  provides interface BombillaBytecode;  uses interface BombillaStacks as Stacks;}implementation {  command result_t BombillaBytecode.execute(uint8_t instr,                                            BombillaContext* context,                                            BombillaState* state) {    dbg(DBG_USR1, "VM (%i): Popping top operand off of stack. \n", context->which);    call Stacks.popOperand(context);    return SUCCESS;  }}\end{verbatim}Its configuration ({\tt OPpop}) is:\begin{verbatim}includes Bombilla;includes BombillaMsgs;configuration OPpop {  provides interface BombillaBytecode;}implementation {  components OPpopM, BStacksProxy;    BombillaBytecode = OPpopM;  OPpopM.Stacks -> BStacksProxy;}\end{verbatim}\subsubsection{Error Checking}Most of the \mate service components automatically perform checks; forexample, if {\tt BStacks} is told to pop off an empty stack, ittriggers an error condition ({\tt BOMB\_STACK\_UNDERFLOW}). Errorconditions are triggered through the {\tt BErrorProxy}component. Sometimes, however, instructions have additional checks;for example, the {\tt bfull} instruction takes a buffer as anoperand. If the top operand is not a buffer, it triggers an errorcondition.\begin{verbatim}includes Bombilla;includes BombillaMsgs;module OPbfullM {  provides interface BombillaBytecode;  uses interface BombillaStacks as Stacks;  uses interface BombillaTypes as Types;}implementation {  command result_t BombillaBytecode.execute(uint8_t instr,                                            BombillaContext* context,                                            BombillaState* state) {    BombillaStackVariable* arg = call Stacks.popOperand(context);    dbg(DBG_USR1, "VM (%i): Checking if buffer full.\n", (int)context->which);                      if (!call Types.checkTypes(context, arg, BOMB_VAR_B)) {return FAIL;}    call Stacks.pushOperand(context, arg);    call Stacks.pushValue(context, (arg->buffer.var->size == BOMB_BUF_LEN)? 1: 0);    return SUCCESS;  }}\end{verbatim}If {\tt Types.checkTypes()} fails, it triggers an error condition inthe calling context. The final parameter is a bitmask of valid types:{\tt BOMB\_VAR\_B} for buffer, {\tt BOMB\_VAR\_S} for sensor, and {\ttBOMB\_VAR\_V} for value. These can be combined; for example, {\tt(BOMB\_VAR\_B | BOMB\_VAR\_V)} will succeed for buffers or values.Error conditions can also be triggered explicitly. For example, thecomparison instructions {\tt gte, gt, lt, lte, eq} all require twooperands of the same type. The code for {\tt gte} is as follows:\begin{verbatim}module OPgteM {  provides interface BombillaBytecode;  uses interface BombillaStacks as Stacks;  uses interface BombillaError;}implementation {  command result_t BombillaBytecode.execute(uint8_t instr,                                            BombillaContext* context,                                            BombillaState* state) {    BombillaStackVariable* arg1 = call Stacks.popOperand(context);    BombillaStackVariable* arg2 = call Stacks.popOperand(context);        if ((arg1->type == BOMB_VAR_V) &&        (arg2->type == BOMB_VAR_V)) {      call Stacks.pushValue(context, arg2->value.var > arg1->value.var);    }    else if ((arg1->type == BOMB_VAR_S) &&             (arg2->type == BOMB_VAR_S) &&             (arg1->sense.type == arg2->sense.type)) {      call Stacks.pushValue(context, arg2->sense.var > arg1->sense.var);    }    else {      call BombillaError.error(context, BOMB_ERROR_INVALID_TYPE);      return FAIL;    }    return SUCCESS;  }}\end{verbatim}where {\tt BombillaError.error} is explicitly called at the end.\subsubsection{Split Phase Operations}Generally, instructions that merely manipulate operands are fairlysimple, as the examples above show. Instructions that encapsulatesplit-phase operations (such as {\tt sense} and {\tt send}) are a bitmore complex, as these instructions cause contexts to block. Assplit-phase operations are scheduling points, they can also yieldlocks.The basic pseudocode for a scheduling point instruction is this:\begin{tabbing}none\=none\=none\=none\=none\=none\=none\=none\=none\= \killif another context is using the resource \\\>put caller on wait queue\\else if underlying resource is busy \\\>put caller on wait queue \\else  \\\>start split-phase operation \\\>set context state to appropriate value\\\>set active context as one executing operation\\\>call Synch.releaseLocks \\\>call Synch.yieldContext \\\end{tabbing}{\tt Synch.releaseLocks()} releases all of the locks a context has setto yield with, for example, the {\tt unlock} or {\tt punlock}instructions. {\tt Synch.yieldContext()} then takes the context offthe run queue, and checks if there are any contexts made runnable byyielded locks. Putting a caller on a wait queue also requiresrestoring it to its state before it executed this instruction, so itcan retry later.The corresponding event of the split-phase operation is thenresponsible for resuming the blocked context, and pulling a waitingcontext off the wait queue.\begin{tabbing}none\=none\=none\=none\=none\=none\=none\=none\=none\= \killif no active context\\\>return\\put active context in run state\\call Synch.resume\\make any necessary operand stack operations\\clear active context \\if wait queue is not empty\\\>dequeue context from wait queue\\\>call Synch.resume\\\end{tabbing}The second {\tt Synch.resume} will cause the waiting context toexecute its next instruction, which will be the one that executes thesplit-phase operation.For examples of this logic, look at {\tt OPsense} and {\tt OPsend}.\subsubsection{Embedded Operands}Some instructions, such as {\tt pushc}, have embeddedoperands. Instruction components that expect embedded operands have anumber at the end of their name, specifying the bit width of theexpected value. For example, {\tt OPcall2} says that the {\tt call}instruction expects two bits of operand, while {\tt OPpushc6} saysthat {\tt pushc} expects six. These instructions take up more than oneslot in a VM's instruction set. For example,\begin{verbatim}  VM.Bytecode[OPcall0] -> OPcall2;  VM.Bytecode[OPcall0+1] -> OPcall2;  VM.Bytecode[OPcall0+2] -> OPcall2;  VM.Bytecode[OPcall0+3] -> OPcall2;\end{verbatim}The code of {\tt call} then reads:\begin{verbatim}command result_t BombillaBytecode.execute(uint8_t instr,                                          BombillaContext* context,                                          BombillaState* state) {  dbg(DBG_USR1, "VM (%i): Calling subroutine %hhu\n", (int)context->which, (uint8_t)(instr & 0x3));  call Stacks.pushReturnAddr(context);  context->capsule = &(state->capsules[instr & 0x3]);  context->pc = 0;  return SUCCESS;}\end{verbatim}\subsection{Contexts}\mate contexts are essentially what is described in the \bomb section;they have two stacks, etc. Making each instruction a component allowsa user to customize the VM instruction set. Contexts follow a similarmodel: each context is a separate component, which is wired to {\ttBombillaEngine}. The component handles the event that triggers thecontext, and sets it runnable. The context component is responsiblefor both the context state and the context capsule; as withinstructions, this means the VM only needs memory for contexts thatare used. \bomb has four contexts: clock, send, receive, andonce. These implementations can be used as templates for new contexts.The viral propagation subsystem, {\tt BVirusProxy}, requires thatcomponents register capsules with it when the VM boots. This allows itto easily generate version vectors and install new code. When new codeis installed, all running contexts must halt and reset. \section{Customizing \mate}\label{sec:extending}The easiest way to customize \mate is to start from a working VM andmodify it. For example, let's say your application needs to takesquare roots; implementing this in an instruction is much moreefficient than trying to code it in \mate bytecodes.The first step is to write the {\tt OPsqrt} component. {\tt sqrt} popsa single value operand off the stack, takes its square root, andpushes the result back onto the stack. This component provides oneinterface, {\tt BombillaBytecode}, uses two: {\tt BombillaStacks} topush and pop, and {\tt BombillaTypes} to check that the top of thestack is a value.The resulting signature for the module is:\begin{verbatim}includes BombillaMsgs;module OPsqrtM {  provides interface BombillaBytecode;  uses {    interface BombillaStacks as Stacks;    interface BombillaTypes as Types;  }}\end{verbatim}The component only implements one function, {\tt execute}:\begin{verbatim}implementation {  command result_t BombillaBytecode.execute(uint8_t instr,                                            BombillaContext* context,                                            BombillaState* state) {    BombillaStackVariable* arg = call Stacks.popOperand(context);    dbg(DBG_USR1, "VM (%i): Taking squart root of top of stack.\n", (int)context->which);    if (!call Types.checkTypes(context, arg, BOMB_VAR_V)) {return FAIL;}    arg->value.var = (int16_t)sqrt(arg->value.var)    call Stacks.pushOperand(context, arg);    return SUCCESS;  }}\end{verbatim}The module needs a configuration, which wires it to the appropriateproxies:\begin{verbatim}includes Bombilla;includes BombillaMsgs;configuration OPsqrt {  provides interface BombillaBytecode;}implementation {  components OPsqrtM, BStacksProxy;  BombillaBytecode = OPinvM;  OPsqrtM.Stacks -> BStacksProxy;  OPsqrtM.Types -> BStacksProxy;}\end{verbatim}The {\tt OPsqrt} component is now a functioning instruction. The finalstep is to include it in the VM. There are two steps to this: thefirst is to define the opcode value of the instruction (probablyreplacing another instruction), and the second is to wire it to the VM.The first is accomplished by modifying the application's {\ttBombillaOpcodes.h}. In this case, we'll remove the {\tt cpull}instruction. Do this by changing the line {\tt OPcpull = 0x11} to {\ttOPsqrt = 0x11}. Then, in the top-level VM configuration, remove thecomponent {\tt OPcpull}, adding {\tt OPsqrt}, and the line {\ttVM.Bytecode[OPcpull] -> OPcpull;}, replacing it with {\ttVM.Bytecode[OPcpull] -> OPsqrt;}Now, when {\tt BombillaEngine} encounters the opcode {\tt 0x11}, itwill execute the square root instruction.\subsection{Customizing CapsuleInjector}By default, {\tt CapsuleInjector} uses the \bomb configuration for itsopcodes and contexts. Changing contexts and capsule options requireschanging {\tt CapsuleInjector}'s code, but the instruction set can bechanged with much less work.{\tt CapsuleInjector} uses the java class {\tt BombillaConstants} toassemble instructions to binary opcodes. {\tt BombillaConstants} isautomatically generated using {\tt ncg}; if you change the {\tt .h}file that {\tt BombillaConstants} is generated from, then {\ttCapsuleInjector} will recognize a different set of instructions.{\tt CapsuleInjector} recognizes constants whose name begins with {\ttOP} as opcodes. For example, when it reads the instruction {\tt jumpc}from a program, it looks for a constant named {\tt OPjumpc} andtranslates it to the corresponding value.\end{document}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -