📄 kern_keyring.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 <disk/KeyRing.hxx>#include <kerninc/Check.hxx>#include <kerninc/Key.hxx>#include <kerninc/Node.hxx>#include <kerninc/Thread.hxx>#include <kerninc/ObjectCache.hxx>#include <kerninc/Invocation.hxx>voidKeyRing::RescindAll(bool mustUnprepare){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top RescindAll");#endif#ifndef NDEBUG if (IsValid(this) == false) dprintf(true, "Keyring 0x%08x is invalid\n");#endif while (next != (KeyRing*) this) { Key *pKey = (Key *) next;#ifndef NDEBUG if ( ObjectCache::ValidKeyPtr(pKey) == false ) { pKey->Print(); fatal("Invalid keyring ptr. Ring=0x%08x pKey=0x%08x\n", this, pKey); } if ( pKey->IsPreparedObjectKey() == false) pKey->Print(); assert ( pKey->IsPreparedObjectKey() );#endif #ifndef NDEBUG /* Following works fine for gate keys too - representation pun! */ KeyRing *nxt = pKey->ok.next;#endif /* Note that thread-embodied and process-embodied keys are never * hazarded: */ if ( pKey->IsHazard() ) { assert ( Thread::IsThreadKey(pKey) == false ); assert ( Process::IsKeyReg(pKey) == false ); Node *pNode = ObjectCache::ContainingNode(pKey); assert ( ObjectCache::ValidNodePtr(pNode) ); uint32_t slot = pKey - pNode->slot; pNode->RescindHazardedSlot(slot, mustUnprepare); /* Having cleared the hazard, the key we are presently examining may not even be on this ring any more -- it may be a different key entirely. We therefore restart the loop. */ if (pKey->IsUnprepared()) continue; } else { assert (pKey->IsHazard() == false); assert ( pKey->IsPreparedObjectKey() ); /* hazard has been cleared, if any */ if (mustUnprepare) { pKey->NH_Unprepare(); } else { /* Note that we do NOT mark the object dirty. If the object is * already dirty, then it will go out to disk with the key * zeroed. Otherwise, the key will be stale when the node is * re-read, and will be zeroed on preparation. */ pKey->NH_RescindKey(); assert (nxt == next); } } /* If the rescinded key is in a thread that is currently running, * we cannot delete the thread. The current domain may be * committing sepuku, but it might be the case that the domain has * contrived to return to someone else, and the *thread* will * therefore survive. [See: there *is* an afterlife!] This can * happen when the currently running domain calls "destroy this * node and return to fred" where "this node" is the domain root * of the currently running domain. Buggered completely, but in * principle this can happen. * * Rather than test for that case, which is not MP compatible, * simply wake up the thread. If the thread is already awake no * harm will ensue. If the thread was asleep, we will attempt to * run it, discover its demise, and that will be the end of it. */ if (Thread::IsThreadKey(pKey)) { Thread *containingThread = Thread::ContainingThread(pKey); assert(containingThread); Process *pContext = containingThread->context; if (pContext) { /* The key within the thread may not be current. I learned * the hard way that it is possible for a live thread to have * a prepared key to the thing being destroyed -- it was * triggered by DCC. This was hard to debug, as printing out * the thread caused the key to be deprepared. */ /* If the thread key is prepared, then the context is loaded, * which means we can rely on a valid domain root pointer: */ assert( pContext->procRoot ); assert ( pContext->procRoot->ob.oid != pKey->GetKeyOid() ); pContext->SyncThread(); continue; } else containingThread->Wakeup(); }#ifdef OPTION_OB_MOD_CHECK if ( !(inv.IsActive() && inv.IsInvocationKey(pKey)) && !Thread::IsThreadKey(pKey) && !Process::IsKeyReg(pKey) ) { Node *pNode = ObjectCache::ContainingNode(pKey); pNode->ob.check = pNode->CalcCheck(); }#endif }#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Bottom RescindAll()");#endif}#if 0/* This is only called from the checkpoint code, and relies utterly on * the fact that it is never called for a node. */voidKeyRing::ObjectMoved(struct ObjectHeader *newObj){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top ObjectMoved");#endif /* Algorithm below fails if the ring is empty */ if (next == (KeyRing*) this) return; KeyRing *nxt = next; while (nxt != (KeyRing*) this) { Key *pKey = (Key *) nxt; assert (pKey->GetType() == KT_Page); /* We need to ensure that any outstanding dependencies on the prior * location of this page (as occurs in page table entries) will be * reconstructed. Actually, once we need to do this I'm half * tempted to just deprepare all of the keys */ /* Note that thread-embodied and process-embodied keys are never hazarded: */ if ( pKey->IsHazard() ) { assert ( Thread::IsThreadKey(pKey) == false ); assert ( Process::IsKeyReg(pKey) == false ); Node *pNode = ObjectCache::ContainingNode(pKey); assert ( ObjectCache::ValidNodePtr(pNode) ); uint32_t slot = pKey - pNode->slot; pNode->ObMovedHazardedSlot(slot); /* Having cleared the hazard, the key we are presently examining may not even be on this ring any more -- it may be a different key entirely. We therefore restart the loop. */ if (pKey->IsUnprepared()) continue; } else { assert (pKey->IsHazard() == false); assert ( pKey->IsPrepared() ); pKey->ok.pObj = newObj; nxt = pKey->ok.next; } #ifdef OPTION_OB_MOD_CHECK if ( !inv.IsInvocationKey(pKey) && !Thread::IsThreadKey(pKey) && !Process::IsKeyReg(pKey) ) { Node *pNode = ObjectCache::ContainingNode(pKey); pNode->ob.check = pNode->CalcCheck(); }#endif } newObj->kr.next = next; newObj->kr.prev = prev; newObj->kr.next->prev = &newObj->kr; newObj->kr.prev->next = &newObj->kr; ResetRing();#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Bottom ObjectMover()");#endif}#endif#ifndef NDEBUGboolKeyRing::IsValid(const void *pObj) const{ const KeyRing *cur = this; const KeyRing *nxt = next; while (nxt != this) { assert ( (Key *) nxt ); if ( ! ObjectCache::ValidKeyPtr((Key *) nxt) ) { dprintf(true, "Key 0x%08x is not valid in keyring 0x%08x\n", nxt, this); return false; } if ( ((Key*)nxt)->IsUnprepared() ) { dprintf(true, "Key 0x%08x is unprepared in keyring 0x%08x (cur 0x%08x)\n", nxt, this, cur); return false; } if ( ((Key*)nxt)->IsPreparedObjectKey() == false) { dprintf(true, "Key 0x%08x is not object key in keyring 0x%08x\n", nxt, this); return false; } if (nxt->prev != cur) { dprintf(true, "Prev of key 0x%08x is not cur in keyring 0x%08x (cur=0x%08x\n", nxt, this, cur); return false; } if (cur->next != nxt) { dprintf(true, "Next of key 0x%08x is not nxt in keyring 0x%08x\n", nxt, this); return false; } if (((Key *)nxt)->ok.pObj!=pObj) { dprintf(false, "nxt->ok.pObj=0x%08x pObj=0x%08x nxt=0x%08x\n", ((Key *)nxt)->ok.pObj, pObj, nxt); return false; } cur = nxt; nxt = nxt->next; } return true;}#endifboolKeyRing::HasResumeKeys() const{ const Key *pKey = (Key *) prev; if ( pKey->IsPreparedResumeKey() ) return true; return false;}voidKeyRing::ZapResumeKeys(){#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Top ZapResumeKeys");#endif Key *pKey = (Key *) prev; /* Prepared resume keys are never in a thread, so we do not need to * check for that. They cksum as zero, so we do not need to * recompute the checksum. * * It used to be that they were never hazarded, but this is no * longer true -- if a resume key is sitting in a key register that * gets loaded into a process context it can become hazarded. Note, * however that this is the ONLY case in which a resume key can be * hazarded, and in that case we are going to zap the copy in the * context anyway, so it is okay to bash them both. The catch * (there is ALWAYS a catch) is that we must preserve the hazard * bits correctly. */ while ( prev != this && pKey->IsPreparedResumeKey() ) {#ifndef NDEBUG if (pKey->IsHazard()) { Node *pNode = ObjectCache::ContainingNode(pKey); assert (pNode->obType == ObType::NtKeyRegs); }#endif uint8_t oflags = pKey->keyFlags & KFL_HAZARD_BITS; prev = pKey->ok.prev; /* We use KS_VoidInitKey here rather than KS_RescindKey * to avoid doing unnecessary unchains. * We patch the key chain at the bottom of the loop. */ /* Note that we do NOT mark the object dirty. If the object is * already dirty, then it will go out to disk with the key * voided. Otherwise, the key will be stale when the node is * re-read, and will be voided on preparation. */ pKey->KS_VoidInitKey(); pKey->keyFlags = oflags; pKey = (Key *) prev; } /* The following is a no-op if there is no resume key, and necessary * to patch the chain if there is. */ pKey->ok.next = (KeyRing*) this;#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Bottom ZapResumeKeys()");#endif}voidKeyRing::UnprepareAll(){#ifndef NDEBUG if (IsValid(this) == false) dprintf(true, "Keyring 0x%08x is invalid\n");#endif while (next != (KeyRing*) this) { Key *pKey = (Key *) next;#ifndef NDEBUG if ( ObjectCache::ValidKeyPtr(pKey) == false ) { pKey->Print(); fatal("Invalid keyring ptr. Ring=0x%08x pKey=0x%08x\n", this, pKey); } if ( pKey->IsPrepared() == false) pKey->Print(); assert ( pKey->IsPreparedObjectKey() );#endif #ifndef NDEBUG /* Following works fine for gate keys too - representation pun! */ KeyRing *nxt = pKey->ok.next;#endif#if 0 printf("UnprepareAll kr=0x%08x pKey=0x%08x *pKey=0x%08x\n", this, pKey, *((Word*) pKey)); #endif if ( pKey->IsHazard() ) { assert ( Thread::IsThreadKey(pKey) == false ); assert ( Process::IsKeyReg(pKey) == false ); Node *pNode = ObjectCache::ContainingNode(pKey); assert ( ObjectCache::ValidNodePtr(pNode) ); uint32_t slot = pKey - pNode->slot; pNode->UnprepareHazardedSlot(slot); /* Having cleared the hazard, the key we are presently examining may not even be on this ring any more -- it may be a different key entirely. We therefore restart the loop. */ if (pKey->IsUnprepared()) continue; } else { assert (pKey->IsHazard() == false); assert ( pKey->IsPreparedObjectKey() ); /* If we are unpreparing a thread-resident key, and that thread * has a context pointer, the key might be out of date. It is * perfectly okay to deprepare that key PROVIDED that we do not * alter the thread's context pointer. This is safe because of * the sequence of conditions tested by Thread::IsRunnable() and * Thread::Prepare(). */#ifndef NDEBUG if ( pKey->ok.next != this && ObjectCache::ValidKeyPtr((Key*)pKey->ok.next) == false ) fatal("keyring 0x%08x: pKey 0x%08x w/ bad next ptr 0x%08x\n", this, pKey, pKey->ok.next);#endif pKey->NH_Unprepare();#ifndef NDEBUG if (nxt != next) fatal("Depreparing key 0x%08x. nxt was 0x%08x next now 0x%08x\n", pKey, nxt, next);#endif assert (nxt == next); assert ( pKey->IsUnprepared() ); } #ifdef OPTION_OB_MOD_CHECK if ( !(inv.IsActive() && inv.IsInvocationKey(pKey)) && !Thread::IsThreadKey(pKey) && !Process::IsKeyReg(pKey) ) { Node *pNode = ObjectCache::ContainingNode(pKey); pNode->ob.check = pNode->CalcCheck(); }#endif } assert ( IsEmpty() );#ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("Bottom UnprepareAll()");#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -