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

📄 kern_node.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
字号:
/* * 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. */#include <kerninc/kernel.hxx>#include <kerninc/Node.hxx>#include <kerninc/util.h>#include <kerninc/Check.hxx>#include <kerninc/Process.hxx>#include <kerninc/ObjectHeader.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Depend.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/ObjectCache.hxx>#define PREPDEBUG#include <eros/Invoke.h>#include <disk/DiskNode.hxx>#include <eros/Key.h>     #include <kerninc/StackTester.hxx>Node::Node()  : ObjectHeader(){  obType = ObType::NtFreeFrame;}voidNode::ClearHazard(uint32_t ndx){  if (slot[ndx].IsHazard() == false)    return;  switch(obType) {  case ObType::NtUnprepared:      /* If this is read hazard, the world is in a very very       * inconsistent state.       */    fatal("Unprepared Node 0x%08x%08x Corrupted (slot %d).\n",		  (uint32_t) (ob.oid>>32), (uint32_t) ob.oid, ndx);    break;      case ObType::NtSegment:    if ( slot[ndx].IsRdHazard() )      fatal("Segment Node Corrupted!\n");    Depend_InvalidateKey(&slot[ndx]);    slot[ndx].UnHazard();    break;  case ObType::NtKeyRegs:    /* If this is write hazard, the world is in a very very     * inconsistent state.     */    context->FlushKeyRegs();    break;        case ObType::NtProcessRoot:    /* TRY to Flush just the registers back out of the context     * structure to clear the write hazard.  That is the common case,     * and the less we flush the happier we will be:     */    if (ndx == ProcAddrSpace) {      Depend_InvalidateKey(&slot[ndx]);      slot[ndx].UnHazard();    }    else if ( ndx == ProcGenKeys ) {      /* This hazard exists to ensure that the domain remains well       * formed.  In order to clear it we must decache the entire       * domain from the context cache and revert this domain back to       * the NtUnprepared form.  We do NOT need to unprepare the       * auxiliary nodes.       */      Unprepare(true);      assert( obType == ObType::NtUnprepared );      assert( slot[ProcGenKeys].IsHazard() == false );    }    else {      /* FIX: If the slot is not smashed with a number key... */      context->FlushProcessSlot(ndx);    }    break;  default:    fatal("Clear hazard on unknown type\n");    break;  }  if (slot[ndx].IsHazard() != false)    fatal("Error. Node ty=%d slot=%d still hazarded\n",		  obType, ndx);}/* CAREFUL -- this operation can have the side effect of blowing away * the current thread! */voidNode::DoClearThisNode(){  assert (InvocationCommitted);    Unprepare(true);  for (uint32_t k = 0; k < EROS_NODE_SIZE; k++) {    assert (slot[k].IsHazard() == false); /* node is unprepared! */    slot[k].NH_VoidKey();  }  /* FIX: Not sure this is really necessary, but I think it is a good   * idea.   */  InvalidateProducts();#ifdef DBG_WILD_PTR  if (dbg_wild_ptr)    Check::Consistency("DoClearThisNode");#endif}/* UNPREPARE AND RESCIND (and object relocation) OF HAZARDED SLOTS. *  * The catch is that we don't want to unload the current (or invokee) * contexts unnecessarily.  If this slot contains a key that chances * to be in a capability register of the current (invokee) context, * clearing the hazard will have the effect of rendering the current * (invokee) context unrunnable by virtue of having forced an unload * of the capability registers node. *  * If the capability that we are depreparing/rescinding is in a memory * context, then we really do need to clear the hazard in order to * force the corresponding PTEs to get invalidated.  If, however, the * capability that we are clearing is in a NtKeyRegs node, we can * cheat.  Ultimately, this capability will get overwritten anyway, * and if the capability in the actual context structure is still the * same as this one, it will be getting unprepared/rescinded as well * as we traverse the key ring. *  * Note that the last is true only because this function is called * ONLY from within KeyRing::RescindAll or KeyRing::UnprepareAll * (according to operation). */voidNode::UnprepareHazardedSlot(uint32_t ndx){  Key& key = slot[ndx];    assert(key.IsPrepared());    if (obType == ObType::NtKeyRegs) {    uint8_t oflags = key.keyFlags;    /* TEMPORARILY clear the hazard: */    key.keyFlags &= ~KFL_HAZARD_BITS;    key.NH_Unprepare();        /* RESET the hazard: */    key.keyFlags = oflags;  }  else {    ClearHazard(ndx);    key.NH_Unprepare();  }#ifdef OPTION_OB_MOD_CHECK  if (!IsDirty())    ob.check = CalcCheck();#endif}/* NOTE: Off the top of my head, I can think of no reason why this * capability should NOT be invalidated in place.  The mustUnprepare flag * gets set when the object in question already has on-disk * capabilities, but what relevance this carries for in-place * capabilities is decidedly NOT clear to me. */voidNode::RescindHazardedSlot(uint32_t ndx, bool mustUnprepare){  Key& key = slot[ndx];    assert(key.IsPrepared());    if (obType == ObType::NtKeyRegs) {    uint8_t oflags = key.keyFlags;    /* TEMPORARILY clear the hazard: */    key.keyFlags &= ~KFL_HAZARD_BITS;    if (mustUnprepare)      key.NH_Unprepare();    else      key.NH_RescindKey();        /* RESET the hazard: */    key.keyFlags = oflags;  }  else {    ClearHazard(ndx);    if (mustUnprepare)      key.NH_Unprepare();    else      key.NH_RescindKey();  }  #ifdef OPTION_OB_MOD_CHECK  if (!IsDirty())    ob.check = CalcCheck();#endif}#if 0voidNode::ObMovedHazardedSlot(uint32_t ndx, ObjectHeader *pNewLoc){  Key& key = slot[ndx];    assert(key.IsPrepared());    ClearHazard(ndx);  key.ok.pObj = pNewLoc;#ifdef OPTION_OB_MOD_CHECK  if (!IsDirty())    ob.check = CalcCheck();#endif}#endifProcess *Node::GetDomainContext(){  if (obType == ObType::NtProcessRoot && context)    return context;  PrepAsDomain();    Process::Load(this);#if 0  printf("return ctxt 0x%08x\n", context);#endif  return context;}/* The domain preparation logic has several possible outcomes: *  * 1. It succeeds - all is well, and a node pointer is returned. *  * 2. It must be retried because I/O is required, in which case it * initiates the I/O on behalf of the calling thread and causes a new * thread to be scheduled, resulting in an unwind. *  * 3. It fails because the domain is malformed.  In this case, it * endeavours to run the keeper of the domain that could not be * prepared, if any.  There may not (transitively) be one to run, in * which case we end up with a thread occupying a busted domain, Stick * the thread on the busted domain stall queue, and force a * reschedule. *//* PrepAsDomain marks the domain components dirty as a side effect. * Strictly speaking, this is not necessary, but the number of domains * that get prepared without modification closely approximates 0, and * it's easier to do it here than in the context prepare logic.  Also, * doing the marking here makes it unnecessary to test in the message * transfer path. */voidNode::PrepAsDomain(){  if (obType == ObType::NtProcessRoot)    return;  MakeObjectDirty();  Unprepare(false);  obType = ObType::NtProcessRoot;  context = 0;}boolNode::PrepAsDomainSubnode(ObType::Type nt, Process *ctxt){  assert(IsDirty());#if 0  dprintf(false, "Preparing OID=0x%08x%08x as domsubnode ty %d\n",		  (uint32_t) (oid>>32), (uint32_t) oid, nt);#endif    if (nt == obType && context == ctxt)    return true;  if (nt != ObType::NtUnprepared)    if (!Unprepare(false))      return false;  if (nt == ObType::NtRegAnnex) {    for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) {      if ( slot[i].Prepare(KT_Number) == false )	return false;    }  }  obType = nt;  context = ctxt;  return true;}voidNode::SetSlot(int ndx, Node& node, uint32_t otherSlot){  assert (InvocationCommitted);    assert (IsDirty());  ClearHazard(ndx);  /* If writing a non-number key into a general registers node, domain   * must be deprepared.   */  if (obType == ObType::NtRegAnnex &&      node.slot[ndx].GetType() != KT_Number)    Unprepare(false);    if ( node[otherSlot].IsRdHazard() )    node.ClearHazard(otherSlot);  /* hazard has been cleared */  slot[ndx].NH_Set(node[otherSlot]);  assert ( slot[ndx].IsHazard() == false );}boolNode::PrepAsSegment(){  assert(this);  if (obType == ObType::NtSegment)    return true;	  #if 0  printf("Preparing oid=");  print(oid);  printf(" as segment node\n");#endif  uint8_t ot = obType;    if(!Unprepare(false)) {    /* FIX: this is temporary! */    fatal("Couldn't unprepare oid 0x%08x%08x. Was ot=%d\n",		  (uint32_t) (ob.oid>>32), (uint32_t) ob.oid, ot);    return false;  }  products = 0;	  obType = ObType::NtSegment;  return true;}inline boolNode::IsCurrentDomain(){  /* Note we do NOT use curcontext(), as there is   * presently an assert in Thread.hxx, and if we are trying to   * prepare a new thread to run (ageing can be called from trying   * to prepare a thread, which can call us), the current thread may   * indeed not have a context.   */  if (context && context == Thread::Current()->context)    return true;    return false;}boolNode::Unprepare(bool zapMe){  if (obType == ObType::NtUnprepared)    return true;  if (obType == ObType::NtProcessRoot) {    /* First check to make sure we don't deprepare ourselves if we     * shouldn't.     */    if (zapMe == false && IsCurrentDomain()) {      dprintf(true, "(0x%08x) Domroot 0x%08x%08x no zapme\n",		      this,		      (uint32_t) (ob.oid >> 32), (uint32_t) ob.oid);      return false;    }          /* Invalidate mapping dependencies on the address space slot: */    Depend_InvalidateKey(&slot[ProcAddrSpace]);    if (context)      context->Unload();#if 0    printf("Returned okay\n");#endif    assert (context == 0);  }  else if (obType == ObType::NtKeyRegs || obType == ObType::NtRegAnnex) {    /* First check to make sure we don't deprepare ourselves if we     * shouldn't.     */#if 1    if (context && inv.IsActive() && context == inv.invokee) {      dprintf(true, "zapping keys/annex of invokee nd=0x%08x"		      " ctxt=0x%08x\n", this, context);    }#endif    if (zapMe == false && IsCurrentDomain()) {      dprintf(true, "(0x%08x) keys/annex 0x%08x%08x no zapme\n",		      this,		      (uint32_t) (ob.oid >> 32), (uint32_t) ob.oid);      return false;    }          if (context)      context->Unload();    assert (context == 0);  }  else if (obType == ObType::NtSegment) {#ifdef DBG_WILD_PTR    if (dbg_wild_ptr)      if (Check::Contexts("pre key zap") == false)	halt('a');#endif    for (uint32_t k = 0; k < EROS_NODE_SIZE; k++) {      if ( slot[k].IsHazard() ) {	assert ( slot[k].IsType(KT_Void) == false );	Depend_InvalidateKey(&slot[k]);	slot[k].UnHazard();      }    }#ifdef DBG_WILD_PTR    if (dbg_wild_ptr)      if (Check::Contexts("post key zap") == false)	halt('b');#endif      InvalidateProducts();  }  obType = ObType::NtUnprepared;#if 0  dprintf(true, "Node deprepared okay\n");#endif  return true;}voidDiskNode::operator=(Node& other){  oid = other.ob.oid;  allocCount = other.ob.allocCount;  callCount = other.callCount;  for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) {#ifdef DBG_WILD_PTR    if (other.Validate() == false) {      printf("Prior to unhazarding key %d\n", i);      Debugger();    }#endif    if (other[i].IsRdHazard())      other.ClearHazard(i);#ifdef DBG_WILD_PTR    if (other.Validate() == false) {      printf("Prior to setting key %d\n", i);      Debugger();    }#endif    slot[i] = other[i];    #ifdef DBG_WILD_PTR    if (other.Validate() == false) {      printf("After setting key %d\n", i);      Debugger();    }#endif  }#if 0  return *this;#endif}/* This version is only be called when copying into a new node, * thus no check of hazards! */voidNode::operator=(const DiskNode& other){  assert (kr.IsEmpty());  assert (obType == ObType::NtUnprepared);  /* The invocation does not need to be committed for this one. */    ob.oid = other.oid;  ob.allocCount = other.allocCount;  callCount = other.callCount;  for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) {    assert(slot[i].IsHazard() == false);    assert( slot[i].IsUnprepared() );  }  bcopy(&other.slot[0], &slot[0], EROS_NODE_SIZE * sizeof(slot[0]));}boolNode::Validate() const{  if ( obType > ObType::NtLAST_NODE_TYPE) {    printf("Node 0x%08x has bad object type\n", this);    return false;  }  assert (obType <= ObType::NtLAST_NODE_TYPE);    if (IsFree()) {    for (uint32_t i = 0; i < EROS_NODE_SIZE; i++) {      if (slot[i].IsUnprepared() == false) {	dprintf(true, "Free node 0x%08x has prepared slot %d\n",			this, i);	return false;      }    }    return true;  }  #ifndef NDEBUG  if (kr.IsValid(this) == false)    return false;#endif  #ifdef OPTION_OB_MOD_CHECK  if (IsDirty() == false) {    uint32_t chk = CalcCheck();      if ( ob.check != chk ) {      printf("Invalid Frame 0x%08x Chk=0x%x CalcCheck=0x%x on node ",		     this, ob.check, chk);      printOid(ob.oid);      printf("\n");#if 0      for (uint32_t i = 0; i < EROS_NODE_SIZE; i++)	slot[i].Print();#endif      return false;    }  }  #endif  for (uint32_t k = 0; k < EROS_NODE_SIZE; k++) {    const Key& key = slot[k];#ifndef NDEBUG    if (key.IsValid() == false) {      printf("Key %d is bad in node 0x%x\n", k, this);      key.Print();      return false;    }#endif        if (key.IsHazard() && obType == ObType::NtUnprepared) {      printf("Unprepared node contains hazarded key\n");      return false;    }    /* For now, do not check device keys. */    if ( key.IsObjectKey() == false )      continue;  }  return true;}

⌨️ 快捷键说明

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