📄 kern_invoke.cxx
字号:
/* it can, however, be a fault key. Since we are not going via * GateKey(), request xfer suppression here. */ if (rk.subType != KstResume) inv.suppressXfer = true; } } /* Pointer to the domain root (if any) whose sleepers we should * awaken on successful completion: */ Process *wakeRoot = 0; /* Revise the invoker runState to what it will be when this is all * over. We'll fix it above if we yield. */ static newState[3] = { RS_Available, /* IT_Reply */ RS_Waiting, /* IT_Call */ RS_Running, /* IT_Send */ }; runState = newState[inv.invType]; if (runState == RS_Available) /* Ensure that we awaken the sleeping threads (if any). */ wakeRoot = this; /******************************************************************** * AT THIS POINT we know that the invocation will complete in * principle. It is still possible that the invoker will block while * some part of the invokee gets paged in or while waiting for an * available Thread structure. The latter is a problem, and needs * to be dealt with. Note that the finiteness of the thread pool * isn't the source of the problem -- the real problem is that we * might not be able to fit all of the running domains in the swap * area. Eventually we shall need to implement a decongester to deal * with this, but that can wait. *********************************************************************/#ifdef GATEDEBUG dprintf(GATEDEBUG>3, "Checked for well-formed recipient\n");#endif if (inv.invokee && inv.invokee->IsWellFormed() == false) inv.invokee = 0; assert(inv.key->IsPrepared()); #ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Invokee now valid\n");#endif assert(inv.invokee == 0 || inv.invokee->IsRunnable()); /* It does not matter if the invokee fails to prepare! * Note that we may be calling this with 'this == 0' */ inv.invokee->SetupExitBlock(inv);#ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Populated exit block\n");#endif #ifdef GATEDEBUG if (inv.suppressXfer) dprintf(true, "xfer is suppressed\n");#endif /* Identify the thread that will migrate to the recipient. Normally * it's the current thread. If this is a FORK invocation, it's a * new thread. Populate this thread consistent with the invokee. */ Thread *threadToMigrate = Thread::Current(); if (inv.invType == IT_Send) { if ( inv.key->IsGateKey() ) { threadToMigrate = new Thread; threadToRelease = threadToMigrate; threadToMigrate->state = Thread::Ready;#ifdef GATEDEBUG dprintf(true, "Built new thread for fork\n");#endif } else threadToMigrate = 0; } #if defined(OPTION_DDB) && !defined(NDEBUG) bool invoked_gate_key = inv.key->IsGateKey(); #ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("DoKeyInvocation() before invoking handler\n");#endif /* suppressXfer only gets set if this was a fault key, in which case * this is likely a re-invocation of the process by the keeper. */ if ( ddb_inv_message || (ddb_gate_message && invoked_gate_key) || (ddb_keeper_message && inv.suppressXfer) ) dprintf(true, "About to invoke key handler (inv.ty=%d)\n", inv.keyType);#endif keyHandler[inv.keyType](inv); assert (InvocationCommitted);#ifndef NDEBUG InvocationCommitted = false; #endif #ifdef DBG_WILD_PTR if (dbg_wild_ptr) Check::Consistency("DoKeyInvocation() before invoking handler\n");#endif#if defined(OPTION_DDB) && !defined(NDEBUG) /* inv.suppressXfer only gets set if this was a fault key, in which * case this is likely a re-invocation of the process by the keeper. * FIX: This is no longer true */ if ( ddb_inv_message || ( ddb_gate_message && invoked_gate_key ) || ( ddb_keeper_message && inv.suppressXfer) || ( ddb_return_message && inv.invType == IT_Reply ) || ( ddb_keyerr_message && !invoked_gate_key && ((inv.key->GetType() != KT_Misc) || ( (inv.key->subType != MKT_Returner) && (inv.key->subType != MKT_Void) ) ) && (inv.exit.code != RC_OK) ) ) dprintf(true, "Before DeliverResult() (invokee=0x%08x)\n", inv.invokee); #endif /* Check the sanity of the receiving process in various ways: */ if (inv.invokee) { if (inv.invokee->IsNotRunnable()) { if (inv.invokee->procRoot == 0) { inv.invokee = 0; goto bad_invokee; } inv.invokee->Prepare(); if (inv.invokee->IsNotRunnable()) { inv.invokee = 0; goto bad_invokee; } } /* Invokee is okay. Deliver the result: */ inv.invokee->runState = RS_Running; if (!inv.suppressXfer) inv.invokee->DeliverResult(inv); /* If we are returning to ourselves, the resume key was never * generated. */ if (inv.invokee != this) inv.invokee->kr.ZapResumeKeys(); } bad_invokee: /* ONCE DELIVERRESULT IS CALLED, NONE OF THE INPUT CAPABILITIES REMAINS ALIVE!!! */ /* Clean up the invocation block: */ inv.Cleanup();#ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Cleaned up invocation\n");#endif#ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Updated invokee runstate\n");#endif if (threadToMigrate) { threadToMigrate->MigrateTo(inv.invokee);#ifdef OPTION_DDB if (inv.invoke->cpuReserve == &CpuReserve::InactiveReserve) dprintf(true, "Thread now in ctxt 0x%08x w/ bad schedule\n", inv.invokee);#endif if (inv.invType == IT_Send && inv.invokee) { threadToMigrate->Wakeup();#ifdef GATEDEBUG dprintf(true, "Woke up forkee\n");#endif } } if (wakeRoot) {#if 0 dprintf(false, "Wake up all of the losers sleeping on dr=0x%08x\n", wakeRoot);#endif wakeRoot->stallQ.WakeAll(); } #ifdef DBG_WILD_PTR { extern void ValidateAllThreads(); ValidateAllThreads(); }#endif#ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Migrated the thread\n");#else#if 0 if ( invoked_gate_key ) dprintf(true, "Migrated the thread\n");#endif#endif inv.invokee = 0; threadToRelease = 0; #ifdef INVOKE_TIMING { extern uint32_t inv_delta_reset; if (inv_delta_reset == 0) { extern uint64_t inv_delta_cy; uint64_t bot_time = rdtsc();#if 0 extern uint64_t inv_delta_cnt0; extern uint64_t inv_delta_cnt1; uint64_t bot_cnt0 = Machine::ReadCounter(0); uint64_t bot_cnt1 = Machine::ReadCounter(1); inv_delta_cnt0 += (bot_cnt0 - top_cnt0); inv_delta_cnt1 += (bot_cnt1 - top_cnt1);#endif inv_delta_cy += (bot_time - top_time); } else inv_delta_reset = 0; }#endif}#endif/* KEEPER INVOCATION -- this looks a lot like key invocation, and the * code for the two should probably be merged. The difficulty is that * the keeper invocation code is able to make a variety of useful * assumptions about abandonment that the general path cannot make. */voidProcess::InvokeMyKeeper(uint32_t oc, uint32_t warg1, uint32_t warg2, uint32_t warg3, Key *keeperKey, Key* keyArg2, uint8_t *data, uint32_t len){#ifdef OPTION_KERN_TIMING_STATS uint64_t top_time = rdtsc();#ifdef OPTION_KERN_EVENT_TRACING uint64_t top_cnt0 = Machine::ReadCounter(0); uint64_t top_cnt1 = Machine::ReadCounter(1);#endif#endif inv.suppressXfer = false; KernStats.nInvoke++; KernStats.nInvKpr++; #ifdef KPRDEBUG dprintf(true, "Enter InvokeMyKeeper\n");#endif bool canInvoke = true; /* If preparation causes a depend entry to get zapped, it may be US * that gets zapped. Set up to check for that... */ PteZapped = false; /* Do not call BeginTransaction here -- the only way we can be here * is if we are already in some transaction, and it's okay to let * that transaction prevail. */ keeperKey->Prepare(); if (keeperKey->IsGateKey() == false) canInvoke = false; #ifdef KPRDEBUG dprintf(true, "Kpr key is gate key? '%c'\n", canInvoke ? 'y' : 'n');#endif /* A recovery context has already been established, either by a call * to PageFault handler or by Thread::Resched(). */#ifndef NDEBUG InvocationCommitted = false;#endif /* Not hazarded because invocation key */ inv.key = keeperKey; inv.invType = IT_Call; inv.keyType = keeperKey->GetType(); inv.nextPC = GetPC();#ifdef KPRDEBUG dprintf(true, "Populated invocation block\n");#endif if (keeperKey->IsType(KT_Resume) && keeperKey->keyData == KsitFault) { inv.suppressXfer = true; printf("Suppress xfer -- key is restart key\n"); } Process * const invokee = canInvoke ? keeperKey->gk.pContext : 0; if (invokee) { inv.invokee = invokee; #ifdef KPRDEBUG dprintf(true, "Prepare invokee\n");#endif /* Make sure invokee is valid */ invokee->Prepare(); #ifdef KPRDEBUG dprintf(true, "Invokee prepare completed\n");#endif if ( invokee->IsWellFormed() == false ) canInvoke = false;#ifdef KPRDEBUG dprintf(true, "Have good keeper, ctxt=0x%08x\n", invokee);#endif#ifndef NDEBUG if (keeperKey->IsType(KT_Resume) && invokee->runState != RS_Waiting) /* Bad resume key! */ canInvoke = false;#endif if (keeperKey->IsType(KT_Start) && invokee->runState != RS_Available) { Thread::Current()->SleepOn(invokee->stallQ); Thread::Current()->Yield(); } if (keeperKey->IsType(KT_Resume) && keeperKey->keyData == KsitFault) inv.suppressXfer = true; } if (canInvoke) {#ifdef KPRDEBUG dprintf(true, "Keeper in right state\n");#endif /* Now have valid invokee in proper state. Build exit block: */ invokee->SetupExitBlock(inv); if (inv.validLen != 0) invokee->SetupExitString(inv, len);#ifdef KPRDEBUG dprintf(true, "Populated exit block\n");#endif COMMIT_POINT(); runState = RS_Waiting; assert (InvocationCommitted); if (!inv.suppressXfer) { inv.CopyOut(len, data); /* This is weird, because we are using DeliverGateResult(): */ inv.entry.code = oc; inv.entry.w1 = warg1; inv.entry.w2 = warg2; inv.entry.w3 = warg3; inv.entry.key[0] = &Key::VoidKey; inv.entry.key[1] = &Key::VoidKey; inv.entry.key[2] = keyArg2; inv.entry.key[3] = &Key::VoidKey; invokee->DeliverGateResult(inv, true); #if defined(DBG_WILD_PTR) || defined(TESTING_INVOCATION) if (dbg_wild_ptr) Check::Consistency("DoKeyInvocation() after invoking keeper\n");#endif } #ifndef NDEBUG InvocationCommitted = false; #endif invokee->runState = RS_Running; if (keeperKey->IsType(KT_Resume)) invokee->kr.ZapResumeKeys(); /* Clean up the invocation block: */ inv.Cleanup();#ifdef GATEDEBUG dprintf(GATEDEBUG>2, "Cleaned up invocation\n");#endif Thread::Current()->MigrateTo(invokee);#ifdef OPTION_DDB if (invokee->cpuReserve == &CpuReserve::InactiveReserve) dprintf(true, "Thread now in ctxt 0x%08x w/ bad schedule\n", invokee);#endif#ifdef KPRDEBUG dprintf(true, "Thread %s has migrated\n", Thread::Current()->Name());#endif inv.invokee = 0; } else {#ifndef NDEBUG OID oid = Thread::CurContext()->procRoot->ob.oid; printf("No keeper for OID 0x%08x%08x, FC %d FINFO 0x%08x\n", (uint32_t) (oid >> 32), (uint32_t) oid, ((Process *)Thread::CurContext())->faultCode, ((Process *)Thread::CurContext())->faultInfo); dprintf(true,"Dead context was 0x%08x\n", Thread::CurContext());#endif /* Just retire the thread, leaving the domain in the running * state. */ Thread::Current()->MigrateTo(0);#if 0 Thread::Current()->SleepOn(procRoot->ObjectSleepQueue()); Thread::Current()->Yield();#endif }#ifdef OPTION_KERN_TIMING_STATS { extern uint64_t kpr_delta_cy; uint64_t bot_time = rdtsc();#ifdef OPTION_KERN_EVENT_TRACING extern uint64_t kpr_delta_cnt0; extern uint64_t kpr_delta_cnt1; uint64_t bot_cnt0 = Machine::ReadCounter(0); uint64_t bot_cnt1 = Machine::ReadCounter(1); kpr_delta_cnt0 += (bot_cnt0 - top_cnt0); kpr_delta_cnt1 += (bot_cnt1 - top_cnt1);#endif kpr_delta_cy += (bot_time - top_time); }#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -