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

📄 kern_invoke.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 4 页
字号:
      /* 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 + -