📄 kern_node.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 + -