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

📄 supernode.c

📁 C++ 编写的EROS RTOS
💻 C
字号:
/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* SuperNode -- domain that looks like a very big node.  Constructs a   tree of nodes to store keys passed by the user.   Key Registers:   KR15: key to root of node tree   KR14: Temporary key slot used to walk tree   KR13: key to space bank   KR12: returner   KR1:  incoming key to store/outgoing key to return   Return Codes:   0: OK   1: Bounds Error   2: Bad Request   Incoming data always comes in as an in-register value.   */#include <eros/target.h>#include <eros/Invoke.h>#include <eros/NodeKey.h>#include <eros/ReturnerKey.h>#include <eros/ProcessKey.h>#include <domain/SpaceBankKey.h>#include <domain/SuperNodeKey.h>#include <domain/domdbg.h>#include <domain/ProtoSpace.h>#include <domain/Runtime.h>#include "constituents.h"#define KR_DOMCRE	3#define KR_OSTREAM	6#define KR_RETURNER	7#define KR_SCRATCH	8#define KR_TREE		9#define KR_WALK		10#define KR_ARG0    28#define KR_RESUME 31#define MAX_LEVEL	5#define dbg_init    0x1#define dbg_op      0x2#define dbg_copy    0x4#define dbg_swap    0x8#define dbg_zap     0x10/* Following should be an OR of some of the above */#define dbg_flags   0  /* ( dbg_op|dbg_copy|dbg_swap|dbg_zap ) */#define DEBUG(x) if (dbg_##x & dbg_flags)/* In principle, treeHeight ought to just be log16(lastKey).   Unfortunately, tree expansion can fail in the middle due to lack of   space, in which case the tree may have been grown but the key may   never have gotten inserted.  We therefore need to track them   separately. *//* There is a TEMPORARY restriction on the tree height of MAX_LEVEL (3),   limiting supernode (somewhat arbitrarily) to 16^3 keys.  This is   due to the stupidity of the current tree delete strategy, which   should be replaced by a chain inverting algorithm similar to that   used in classical GC systems for CONS cells. */typedef struct {		/* wrap globals in a structure for				   small domains */  uint32_t lastKey;		/* initialize to 0 */  uint32_t treeHeight;		/* initialize to 0 */} state;uint32_t snode_xtract(uint32_t ndx, state *mystate, uint32_t depth);uint32_t snode_copy(Message *msg, state *mystate);uint32_t snode_swap(Message *msg, state *mystate);void snode_zap_all_keys(state *mystate);void snode_destroy(state *mystate);void ProcessRequest(Message *msg, state *mystate);voidInitialize(state *mystate){  mystate->lastKey = 0;  mystate->treeHeight = 0;  node_copy(KR_CONSTIT, KC_RETURNER, KR_RETURNER);  node_copy(KR_CONSTIT, KC_OSTREAM, KR_OSTREAM);  copy_key_reg(KR_RETURNER, KR_VOID, KR_TREE);  DEBUG(init) kdprintf(KR_OSTREAM, "Supernode: initialized\n");}intmain(){  state mystate;  Message msg;  Initialize(&mystate);    process_make_start_key(KR_SELF, 0, KR_ARG0);    msg.snd_invKey = KR_RESUME;  msg.snd_key0 = KR_ARG0;  msg.snd_key1 = KR_VOID;  msg.snd_key2 = KR_VOID;  msg.snd_key3 = KR_VOID;  msg.snd_data = 0;  msg.snd_len = 0;  msg.snd_code = 0;  msg.snd_w1 = 0;  msg.snd_w2 = 0;  msg.snd_w3 = 0;  msg.rcv_key0 = KR_ARG0;  msg.rcv_key1 = KR_VOID;  msg.rcv_key2 = KR_VOID;  msg.rcv_key3 = KR_RESUME;  msg.rcv_data = 0;  msg.rcv_len = 0;  msg.rcv_code = 0;  msg.rcv_w1 = 0;  msg.rcv_w2 = 0;  msg.rcv_w3 = 0;  for(;;) {    RETURN(&msg);    msg.snd_key0 = KR_VOID;		 /* until otherwise proven */    ProcessRequest(&msg, &mystate);  }}uint32_tlog16(uint32_t w){  uint32_t log = 0;  while (w > 0) {    w >>= 4;    log++;  }  return log;}voidProcessRequest(Message *msg, state *mystate){  uint32_t result = RC_OK;  msg->snd_len = 0;  msg->snd_key0 = KR_VOID;  msg->snd_key1 = KR_VOID;  msg->snd_key2 = KR_VOID;  msg->snd_key3 = KR_VOID;    switch (msg->rcv_code) {  case OC_SuperNode_Copy:    {      DEBUG(op) kdprintf(KR_OSTREAM, "snode_copy(ndx=%d)\n", msg->rcv_w1);      result = snode_copy(msg, mystate);      if (result == RC_OK)	msg->snd_key0 = KR_WALK;      break;    }  case OC_SuperNode_Swap:    {      DEBUG(op) kdprintf(KR_OSTREAM, "snode_swap(ndx=%d)\n", msg->rcv_w1);      result = snode_swap(msg, mystate);      break;    }  case OC_SuperNode_Zero:    {      DEBUG(op) kdprintf(KR_OSTREAM, "snode_zero(ndx=%d)\n", msg->rcv_w1);      snode_zap_all_keys(mystate);      break;    }  /*   * FIX: we need an order code for destroy, but   * since it doesn't totally work yet I guess   * we'll wait   */  default:    result = RC_UnknownRequest;    break;  }  msg->snd_code = result;}/* Follow the path implied by ndx until you reach a tree depth of   /depth/, and return that kay.   Returns 0 if it terminates the walk early, which reduces   unnecessary calls to spcbank in zap_all_keys. */uint32_tsnode_xtract(uint32_t ndx, state *mystate, uint32_t depth){  uint32_t height = mystate->treeHeight;  /* Until proven otherwise, snd_key0 should remain KR_VOID --   * all slots have void until we know otherwise.   */  /* Copy tree root key into temporary key: */  copy_key_reg(KR_RETURNER, KR_TREE, KR_WALK);      while (height > depth) {    uint32_t nodeNdx;        nodeNdx = (ndx >> ((height-1) * 4));	    nodeNdx &= 0xfu;    if ( node_copy(KR_WALK, nodeNdx, KR_WALK) == RC_Void ) {      /* It was a void key - just return RC_OK, since msg->snd_key0	 still holds KR_VOID. */      return 0;    }    height--;  }  return 1;}/* supernode_copy(): Return key from position described by 'ndx' */uint32_tsnode_copy(Message *msg, state *mystate){  if (msg->rcv_w1 > mystate->lastKey)    return RC_RequestError;  (void) snode_xtract(msg->rcv_w1, mystate, 0);  msg->snd_key0 = KR_WALK;  return RC_OK;}/* supernode_swap(): Exchange argument key with key at position   described by 'ndx'.  The tricky difference between this and   supernode_copy() is that this has to be prepared to grow the tree   on demand. */uint32_tsnode_swap(Message *msg, state *mystate){  uint32_t height;  uint32_t ndxHeight = log16(msg->rcv_w1);  uint32_t result;      if (ndxHeight > MAX_LEVEL) {    kdprintf(KR_OSTREAM, "MAX SNODE HEIGHT EXCEEDED; ndx 0x%08x\n",	     msg->rcv_w1);     return RC_RequestError;  }    /* Step 1: Check if we need to grow the tree upwards: */  while (ndxHeight > mystate->treeHeight) {    DEBUG(swap) kprintf(KR_OSTREAM, "NDX height is %d Height is %d\n", ndxHeight,		  mystate->treeHeight);     /* Using KR_WALK as a scratch register */    if ((result = spcbank_buy_nodes(KR_BANK, 1, KR_WALK, KR_VOID, KR_VOID)) != RC_OK)      return result;    DEBUG(swap) kdprintf(KR_OSTREAM, "Got new node\n", ndxHeight,	     mystate->treeHeight);     /* set slot 0 of new node to old tree: */    node_swap(KR_WALK, 0, KR_TREE, KR_VOID);          /* establish new tree root */    copy_key_reg(KR_RETURNER, KR_WALK, KR_TREE);    mystate->treeHeight++;  }  height = mystate->treeHeight;        /* Special case: if current tree Height is 0 and setting slot 0,     blast the tree root slot: */  if (mystate->treeHeight == 0 && msg->rcv_w1 == 0) {    /* establish new tree root */    copy_key_reg(KR_RETURNER, KR_ARG0, KR_WALK);    copy_key_reg(KR_RETURNER, KR_ARG0, KR_TREE);    msg->snd_key0 = KR_WALK;      return RC_OK;  }  /* Step 2: Attempt to traverse the tree downwards looking for the     right slot.  It's possible that the relevant subtree is not     populated, in which case we should expand it as we go. The key     held in KR_TREE can safely be assumed to be a node key if the     treeHeight is > 0. */      /* establish new tree root */  copy_key_reg(KR_RETURNER, KR_TREE, KR_WALK);  while (height > 1) {    uint32_t nodeNdx;        nodeNdx = (msg->rcv_w1 >> ((height-1) * 4));	    nodeNdx &= 0xfu;    node_copy(KR_WALK, nodeNdx, KR_SCRATCH);    /* KR_SCRATCH may be a void key, in which case it will respond       with RC_Void to the following, and we must populate that       subtree: */          if (node_copy(KR_SCRATCH, 0, KR_VOID) == RC_Void) {#if 0      uint32_t subnodeNdx = (mystate->inNdx >> ((height - 2) * 4));#endif	      if ((result = spcbank_buy_nodes(KR_BANK, 1, KR_SCRATCH, KR_VOID, KR_VOID)) != RC_OK)	return result;      node_swap(KR_WALK, nodeNdx, KR_SCRATCH, KR_VOID);    }    copy_key_reg(KR_RETURNER, KR_SCRATCH, KR_WALK);    height--;  }  node_swap(KR_WALK, (msg->rcv_w1 & 0xf), KR_ARG0, KR_WALK);    msg->snd_key0 = KR_WALK;    if (mystate->lastKey < msg->rcv_w1)    mystate->lastKey = msg->rcv_w1;  return RC_OK;}/* Tree destruction is a little tricky.  We know the height of the   tree, but we have no simple way to build a stack of node pointers   as we traverse it.   After much batting around of rotation and layering, I finally   decided that it just wasn't worthwhile to do anything fancy.  The   following algorithm simply walks the tree once per entry,   efficiently skipping unpopulated subtrees.   */voidsnode_zap_all_keys(state *mystate){  uint32_t depth;  for (depth = 1; depth < mystate->treeHeight; depth++) {    uint32_t lo = 0;    uint32_t hi = mystate->lastKey;    uint32_t increment = 1 << (depth * 16);    for (lo = 0; lo < hi; lo += increment) {      /* We could check if leaf itself is null, but supernodes tend	 not to be sparse, and passing null key to return to bank	 hasn't much negative impact. The test of the snode_xtract	 return value will let us weed large sparsities. */      if ( snode_xtract(lo, mystate, 1) )	spcbank_return_node(KR_BANK, KR_WALK);    }  }  copy_key_reg(KR_RETURNER, KR_VOID, KR_TREE);}   /* In spite of unorthodox fabrication, the constructor self-destructs   in the usual way. */voidSepuku(){  node_copy(KR_CONSTIT, KC_PROTOSPC, KR_WALK);  spcbank_return_node(KR_BANK, KR_CONSTIT);  /* Invoke the protospace with arguments indicating that we should be     demolished as a small space domain */  protospace_destroy(KR_RETURNER, KR_DOMCRE, KR_SELF,		     KR_WALK, KR_BANK, 1);}/* supernode_destroy(): Destroy the supernode.   FIX: This does not yet cause the space bank itself to be destroyed,   because I do not yet understand how to make that work. */voidsnode_destroy(state *mystate){  snode_zap_all_keys(mystate);  Sepuku();}

⌨️ 快捷键说明

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