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

📄 kern_invoke.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 4 页
字号:
  inv.suppressXfer = false;  /* suppress compiler bitching */    /* If preparation causes a depend entry to get zapped, it may be US   * that gets zapped.  Set up to check for that...   */  PteZapped = false;  ObjectHeader::BeginTransaction();    SetupEntryBlock(inv);#ifdef OPTION_DDB  if ( ddb_inv_flags )    goto general_path;#endif  /* Send is a pain in the butt.  Fuck 'em if they can't take a joke. */  if (inv.invType == IT_Send)    goto general_path;  /* If it's a segment key, it might be a red segment key.  Take the   * long way:   */  if (inv.keyType == KT_Segment)    goto general_path;#ifdef KT_Wrapper  /* If it's a wrapper key, take the long way:   */  if (inv.keyType == KT_Wrapper)    goto general_path;#endif  /* Handle the return via returner case efficiently: */  if (inv.key->IsType(KT_Returner)) {    inv.key = inv.entry.key[3];    inv.keyType = inv.key->GetType();    if (inv.keyType != KT_Resume) {      /* NOTE: this also captures key being unprepared!!  */      goto general_path;    }    inv.entry.key[3] = &Key::VoidKey;  }      if (inv.keyType <= KT_Resume) {    inv.invokee = inv.key->gk.pContext;    if (inv.invokee->IsWellFormed() == false)      goto general_path;    /* If this is a resume key, we know the process is in the     * RS_Waiting state.  If it is a start key, the process might be     * in any state.  Do not solve the problem here to avoid loss of     * I-cache locality in this case; we are going to sleep anyway.     */    if (inv.keyType == KT_Start && inv.invokee->runState != RS_Available)      goto general_path;  }  else {    if (inv.invType != IT_Call)      goto general_path;        inv.invokee = this;  }  #ifdef OPTION_PURE_ENTRY_STRINGS  if (inv.entry.len != 0)    SetupEntryString(inv);#endif  if (inv.invokee->IsRunnable() == false)    goto general_path;    if (inv.keyType == KT_Resume && inv.key->keyData != KsitResume)    inv.suppressXfer = true;  /* Following is a truly disgusting piece of numerology, which is   * done deliberately:   */  assert (IT_Call == RS_Waiting);  assert (IT_Reply == RS_Available);  runState = inv.invType;  /* 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 OPTION_PURE_EXIT_STRINGS  if (inv.validLen != 0)    inv.invokee->SetupExitString(inv, inv.validLen);#endif  {#if defined(DBG_WILD_PTR) || defined(TESTING_INVOCATION)    if (dbg_wild_ptr)      Check::Consistency("DoKeyInvocation() before invoking handler\n");#endif#if defined(OPTION_KERN_TIMING_STATS)    pre_handler = rdtsc();#endif    keyHandler[inv.keyType](inv);#if defined(OPTION_KERN_TIMING_STATS)    {      extern uint32_t inv_delta_reset;      if (inv_delta_reset == 0) {	extern uint64_t inv_handler_cy;	uint64_t post_handler = rdtsc();	inv_handler_cy += (post_handler - pre_handler);	Invocation::KeyHandlerCycles[inv.keyType][inv.invType] +=	  (post_handler - pre_handler);	Invocation::KeyHandlerCounts[inv.keyType][inv.invType] ++;      }    }  #endif#if defined(DBG_WILD_PTR) || defined(TESTING_INVOCATION)    if (dbg_wild_ptr)      Check::Consistency("DoKeyInvocation() after invoking handler\n");#endif    assert (InvocationCommitted);#ifndef NDEBUG    InvocationCommitted = false;    #endif  }  /* Now for the tricky part.  It's possible that the proces did an   * invocation whose effect was to blow the invokee apart.  I know of   * no way to speed these checks:   */  if (inv.invokee->IsNotRunnable()) {    if (inv.invokee->procRoot == 0)      goto invokee_died;    inv.invokee->Prepare();    if (inv.invokee->IsNotRunnable())      goto invokee_died;  }  inv.invokee->runState = RS_Running;  if (!inv.suppressXfer) {    inv.invokee->DeliverResult(inv);#if defined(DBG_WILD_PTR) || defined(TESTING_INVOCATION)    if (dbg_wild_ptr)      Check::Consistency("DoKeyInvocation() after DeliverResult()\n");#endif  }  if (inv.invokee != this) {    /* Following is only safe because we handle non-call on primary     * key in the general path.     */    if (inv.keyType == KT_Resume)      inv.invokee->kr.ZapResumeKeys();    Thread::Current()->MigrateTo(inv.invokee);#ifdef OPTION_DDB    if (inv.invokee->cpuReserve == &CpuReserve::InactiveReserve)      dprintf(true, "Thread now in ctxt 0x%08x w/ bad schedule\n", 		      inv.invokee);#endif  }    if (runState == RS_Available)    stallQ.WakeAll();      inv.Cleanup();  inv.invokee = 0;#ifdef OPTION_KERN_TIMING_STATS  {    extern uint32_t inv_delta_reset;    if (inv_delta_reset == 0) {      extern uint64_t inv_delta_cy;      uint64_t bot_time = rdtsc();#ifdef OPTION_KERN_EVENT_TRACING      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#if defined(DBG_WILD_PTR) || defined(TESTING_INVOCATION)  if (dbg_wild_ptr)    Check::Consistency("bottom DoKeyInvocation()");#endif    return; general_path:  runState = RS_Running;  /* This path has its own, entirely separate recovery logic.... */  DoGeneralKeyInvocation();  return;   invokee_died:  inv.invokee = 0;  inv.Cleanup();  Thread::Current()->MigrateTo(0);}Thread *threadToRelease = 0;  voidProcess::DoGeneralKeyInvocation(){#ifdef OPTION_KERN_TIMING_STATS  uint64_t top_time = rdtsc();  uint64_t pre_handler;#ifdef OPTION_KERN_EVENT_TRACING  uint64_t top_cnt0 = Machine::ReadCounter(0);  uint64_t top_cnt1 = Machine::ReadCounter(1);#endif#endif  threadToRelease = 0;    /* Set up the entry block, faulting in any necessary data pages and   * constructing an appropriate kernel mapping:   */  SetupEntryBlock(inv);#ifdef OPTION_PURE_ENTRY_STRINGS  if (inv.entry.len != 0)    SetupEntryString(inv);#endif#ifdef GATEDEBUG  dprintf(true, "Populated entry block\n");#endif  assert(inv.key->IsPrepared());    /* There are two cases where the actual invocation may proceed on a   * key other than the invoked key:   *    *   Invocation of kept red segment key proceeds as invocation on   *     the keeper, AND observes the slot 2 convention of the format   *     key!!!   Because this must overwrite slot 2, it must occur   *     following the entry block preparation.   *    *   Gate key to malformed domain proceeds as invocation on void.   *    * The red seg test is done first because the extracted gate key (if   * any) needs to pass the well-formed test too.   *   * In the latest revised kernel, the Wrapper node is beginning to   * subsume the role of the red segment node. We do either/or logic   * here because we don't want them to nest.   */  #ifdef KT_Wrapper  if ( inv.key->IsType(KT_Wrapper)       && inv.key->IsReadOnly() == false       && inv.key->IsNoCall() == false       && inv.key->IsWeak() == false ) {    /* The original plan here was to hide all of the sanity checking     * for the wrapper node in the PrepAsWrapper() logic. That doesn't     * work out -- it causes the wrapper node to need deprepare as a     * unit when slots are altered, with the unfortunate consequence     * that perfectly good mapping tables can get discarded. It is     * therefore better to check the necessary constraints here.     */    Node *wrapperNode = (Node *) inv.key->GetObjectPtr();    Key& fmtKey = wrapperNode->slot[WrapperFormat];    if (fmtKey.IsType(KT_Number)	&& wrapperNode->slot[WrapperKeeper].IsGateKey() ) {      /* Unlike the older red segment logic, the format key has       * preassigned slots for the keeper, address space, and so       * forth.       */      if (fmtKey.nk.value[0] & WRAPPER_SEND_NODE) {	/* Not hazarded because invocation key */	inv.scratchKey.NH_Set(*inv.key);	inv.scratchKey.SetType(KT_Node);	inv.entry.key[2] = &inv.scratchKey;	inv.flags |= INV_SCRATCHKEY;      }      if (fmtKey.nk.value[0] & WRAPPER_SEND_WORD)	inv.entry.w1 = fmtKey.nk.value[1];      /* Not hazarded because invocation key */      inv.key = &(wrapperNode->slot[WrapperKeeper]);      inv.keyType = inv.key->GetType();      /* Prepared resume keys can only reside in dirty objects! */      if (inv.keyType == KT_Resume)	wrapperNode->MakeObjectDirty();	          inv.key->Prepare();	/* MAY YIELD!!! */    }  } #else  if ( inv.key->IsType(KT_Segment)       && inv.key->IsRedSegmentKey()       && inv.key->IsReadOnly() == false       && inv.key->IsNoCall() == false       && inv.key->IsWeak() == false ) {    /*    dprintf(false, "It's a red segment key\n"); */    Node *redSegNode = (Node *) inv.key->GetObjectPtr();    Key& fmtKey = redSegNode->slot[RedSegFormat];    /* Only pass through if red segment is well-formed and has gate     * key as keeper!     */        if ( fmtKey.IsType(KT_Number) ) {      uint32_t kprSlot = REDSEG_GET_KPR_SLOT(fmtKey.nk);      if ( kprSlot != EROS_NODE_SLOT_MASK	   && redSegNode->slot[kprSlot].IsGateKey() ) {	/* See if we need to clobber slot 2 with a node key to the red	 * segment.  Need to do this BEFORE we bash inv.key... :-)	 */	if ( REDSEG_GET_SENDNODE(fmtKey.nk) == REDSEG_SEND_NODE ) {	  /* Not hazarded because invocation key */	  inv.scratchKey.NH_Set(*inv.key);	  inv.scratchKey.SetType(KT_Node);	  inv.entry.key[2] = &inv.scratchKey;	  inv.flags |= INV_SCRATCHKEY;	}	/* Not hazarded because invocation key */	inv.key = &(redSegNode->slot[kprSlot]);	inv.keyType = inv.key->GetType();	/* Prepared resume keys can only reside in dirty objects! */	if (inv.keyType == KT_Resume)	  redSegNode->MakeObjectDirty();	    	inv.key->Prepare();	/* MAY YIELD!!! */	inv.entry.w1 = fmtKey.nk.value[1];      }      else	dprintf(true, "Keeper not gate key or no keeper\n");    }    else      dprintf(true, "Format key is bad\n");  }#endif    assert(inv.key->IsPrepared());  inv.invokee = 0;		/* until proven otherwise */    /* Right now a corner case here is buggered because we have not yet   * updated the caller's runstate according to the call type.  As a   * result, a return on a start key to yourself won't work in this   * code.   */    if ( inv.key->IsGateKey() ) {    assert (inv.key->IsPrepared());    /* Make a local copy (subvert alias analysis pessimism) */    Process *p = inv.key->gk.pContext;    inv.invokee = p;    p->Prepare();		/* may yield */    /* This is now checked in pk_GateKey.cxx */    if (inv.keyType == KT_Resume && inv.key->keyData != KsitResume)      inv.suppressXfer = true;    if (p->IsWellFormed() == false) {      /* Not hazarded because invocation key */      /* Pretend he invoked a void key. */      inv.key = &Key::VoidKey;      inv.keyType = KT_Void;      inv.invokee = this;      inv.entry.key[3] = &Key::VoidKey;#ifndef NDEBUG      printf("Jumpee malformed\n");#endif    }#ifndef NDEBUG    else if (inv.keyType == KT_Resume &&	     p->runState != RS_Waiting) {      fatal("Resume key to wrong-state context\n");    }#endif    else if (inv.keyType == KT_Start && p->runState != RS_Available) {      Thread::Current()->SleepOn(p->stallQ);      Thread::Current()->Yield();    }#if 0    else if ( inv.invType == IT_Call ) {      BuildResumeKey(inv.resumeKey);      inv.entry.key[3] = &inv.resumeKey;      inv.flags |= INV_RESUMEKEY;    }#endif  }  else if (inv.invType == IT_Call) {    /* Call on non-gate key always returns to caller and requires no     * resume key.     *     * ISSUE: This will not look right to DDB, but it's correct. When     * you next look at puzzling DDB state and wonder why the resume     * key never got generated, it is because I did not want to deal     * with the necessary key destruction overhead. The register     * renaming key fabrication strategy should regularize this rather     * nicely when we get there.     */    inv.invokee = this;    inv.entry.key[3] = &Key::VoidKey;  }  else {    /* Kernel key invoked with REPLY or SEND.  Key in slot 3 must be a     * resume key, and if so the process must be waiting, else we will     * not return to anyone.     */    Key& rk = *inv.entry.key[3];    rk.Prepare();    /* Kernel keys return as though via the returner, so the key in     * slot four must be a resume key to a party in the right state.     */    assert(rk.IsHazard() == false);        if (rk.IsPreparedResumeKey()) {      Process *p = rk.gk.pContext;      p->Prepare();      assert(p->runState == RS_Waiting);      inv.invokee = p;      /* it can, however, be a fault key.  Since we are not going via       * GateKey(), request xfer suppression here.       */      if (rk.keyData == KsitFault)	inv.suppressXfer = true;    }    else      assert (inv.invokee == 0);  }  /* 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 uint8_t newState[3] = {    RS_Available,		/* IT_Reply */    RS_Waiting,			/* IT_Call */    RS_Running,			/* IT_Send */  };  runState = newState[inv.invType];

⌨️ 快捷键说明

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