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

📄 kern_thread.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
    }    yieldState = 0;    ChooseNewCurrentThread();  }    do {    ObjectHeader::BeginTransaction();    #ifdef DBG_WILD_PTR    if (dbg_wild_ptr && 0)      Check::Consistency("In DoReschedule() loop");#endif#if 0    printf("schedloop: curThread 0x%08x ctxt 0x%08x fc 0x%x\n",		   curThread, curThread->context,		   curThread->context ? curThread->context->faultCode		   : 0);#endif    assert (curThread);        /* If thread cannot be successfully prepared, it cannot (ever) run,     * and should be returned to the free thread list.  Do this even if     * we are rescheduling, since we want the thread entry back promptly     * and it doesn't take that long to test.     */    if ( curThread && curThread->Prepare() == false ) {      assert( curThread->IsUser() );          /* We shouldn't be having this happen YET */      fatal("Current thread no longer runnable\n");      delete curThread;      assert (curThread == 0);      ChooseNewCurrentThread();    }    assert (curThread);    /* Thread might have gone to sleep as a result of context being prepared. */    if (curThread->state != Thread::Running)      ChooseNewCurrentThread();    if (curThread->context	&& curThread->context->processFlags & PF_Faulted)       curThread->InvokeMyKeeper();    /* Thread can go away as a consequence of keeper invocation. */    if (curThread == 0 || curThread->state != Thread::Running)      ChooseNewCurrentThread();    assert (curThread);#if 0    static count = 0;    count++;    if (count % 100 == 0) {      count = 0;      printf("schedloop: curThread 0x%08x ctxt 0x%08x (%s) run?"		     " %c st %d fc 0x%x\n",		     curThread,		     curThread->context,		     curThread->context->Name(),		     curThread->context->IsRunnable() ? 'y' : 'n',		     curThread->state,		     curThread->context->faultCode);    }#endif  } while (curThread->IsRunnable() == false);#ifdef DBG_WILD_PTR  if (dbg_wild_ptr)    Check::Consistency("Bottom DoReschedule()");#endif  assert (curThread);  assert (curThread->context);  CpuReserve *cpuReserve = curThread->cpuReserve;  assert (cpuReserve == CurContext()->cpuReserve);#ifdef PREEMPTION  /* printf("Disarming expiration timer\n");   *       QuantaTimer.Disarm();   */  assert( IRQ::DISABLE_DEPTH() == 1 );  yieldState = 0;		/* until proven otherwise */  /* printf("Setting expiration timer\n");   *      QuantaTimer.WakeupIn(SCHED_QUANTA, Expired);   */  /* SysTimer::SetQuanta(Machine::MillisecondsToTicks(SCHED_QUANTA));   *      dprintf(true,"Set quanta to %d\n", (uint32_t) (cpuReserve->residQuanta));   */  CpuReserve::Current = cpuReserve;  assert( IRQ::DISABLE_DEPTH() == 1 );  /* printf("It's set...\n"); */#endif  assert(Thread::Current() == curThread);  /* Thread::Current()->SetStackLimit(); */  Thread::Current()->nRun++;}voidThreadPile::WakeNext(){  IRQ::DISABLE();  if (next)    ((struct Thread *) next)->Wakeup();  IRQ::ENABLE();}voidThreadPile::WakeAll(uint32_t errCode, bool /* verbose */){  IRQ::DISABLE();  while (next) {#ifdef OPTION_DDB    Thread *thread = (struct Thread *) next;        {	extern bool ddb_thread_uqueue_debug;	if (ddb_thread_uqueue_debug && thread->IsUser() )	  dprintf(true, "Waking up thread 0x%08x (%s)\n",			  thread, thread->Name());    }#endif#if 0    if (verbose)      printf("Waking up thread 0x%08x (%s)\n",		     next, ((struct Thread *) next)->Name());#endif    ((struct Thread *) next)->errCode = errCode;    ((struct Thread *) next)->Wakeup();  }  IRQ::ENABLE();}voidThreadPile::IoWakeAll(uint32_t errCode, bool /* verbose */){  IRQ::DISABLE();  while (next) {#ifdef OPTION_DDB    Thread *thread = (struct Thread *) next;        {	extern bool ddb_thread_uqueue_debug;	if (ddb_thread_uqueue_debug && thread->IsUser() )	  dprintf(true, "Waking up thread 0x%08x (%s)\n",			  thread, thread->Name());    }#endif#if 0    if (verbose)      printf("Waking up thread 0x%08x (%s)\n",		     next, ((struct Thread *) next)->Name());#endif    ((struct Thread *) next)->errCode = errCode;    ((struct Thread *) next)->state = Thread::IoCompleted;    ((struct Thread *) next)->Wakeup();  }  IRQ::ENABLE();}boolThreadPile::IsEmpty(){  bool result = false;    IRQ::DISABLE();  if (next == 0)    result = true;    IRQ::ENABLE();  return result;}#ifndef NDEBUGvoidValidateAllThreads(){  for (int i = 0; i < KTUNE_NTHREAD; i++) {    if ( Thread::ThreadTable[i].state != Thread::Free )      Thread::ThreadTable[i].ValidateUserThread();  }}voidThread::ValidateUserThread(){  uint32_t wthis = (uint32_t) this;  uint32_t wtbl = (uint32_t) ThreadTable;    if (wthis < wtbl)    fatal("Thread 'this' pointer too low\n");  wthis -= wtbl;  if (wthis % sizeof(Thread))    fatal("Thread 'this' pointer not valid.\n");  if ((wthis / sizeof(Thread)) >= KTUNE_NTHREAD)    fatal("Thread 'this' pointer too high.\n");  if (!context && processKey.GetType() != KT_Process  &&      ! processKey.IsVoidKey())    fatal("Thread 0x%08x has bad key type.\n", this);}#endifconst char*Thread::Name(){  if ( !IsUser() )    return context->Name();    static char * userThreadName = "userXXX\0";  uint32_t ndx = this - &ThreadTable[0];  if (ndx >= 100) {    userThreadName[4] = (ndx / 100) + '0';    ndx = ndx % 100;    userThreadName[5] = (ndx / 10) + '0';    ndx = ndx % 10;    userThreadName[6] = ndx + '0';    userThreadName[7] = 0;  }  else if (ndx >= 10) {    userThreadName[4] = (ndx / 10) + '0';    ndx = ndx % 10;    userThreadName[5] = ndx + '0';    userThreadName[6] = 0;  }  else {    userThreadName[4] = ndx + '0';    userThreadName[5] = 0;  }  return userThreadName;}/* ALERT *  * There are four places to which a user thread Yield() can return: *  *    Thread::Prepare() -- called from the scheduler *    Thread::InvokeMyKeeper() -- called from the scheduler *    The page fault handler *    The gate jump path. *  * We would prefer a design in which there was only one recovery * point, but if Thread::Prepare() is being called, it is possible * likely that the thread's Context entry is gone, and even possible * that the domain root has gone out of memory. *  * Note that a thread's prepare routine must always be called by that * thread, and not by any other.  Threads prepare themselves. * Contexts, by contrast, can be prepared by anyone. *  * That said, here's the good news: it is not possible for the uses to * conflict.  Any action taken as a result of a gate jump that causes * the thread to Yield() will have put the thread to sleep, in which * case it's not being prepared. */boolThread::Prepare(){  static uint32_t count;  #ifdef DBG_WILD_PTR  if (dbg_wild_ptr && 0)    Check::Consistency("Before ThrdPrepare()");#endif  /* In the absence of the PTE zap case, which is now handled   * separately, it is not clear that we still need the for(;;)   * loop...   */    for (count = 0; count < 20;count++) {    /* If we have a context, the thread ain't dead yet! */    if ( context && context->IsRunnable() ) {      assert(context->cpuReserve);      assert (cpuReserve == context->cpuReserve);            return true;    }      assert ( Thread::state != Thread::Free );        /* Probably not necessary, but it doesn't do any harm: */    assert( Thread::Current() == this );      /* Try to prepare this thread to run: */#ifdef THREADDEBUG    printf("Preparing user thread\n");#endif      if ( context == 0 ) {      /* Domain root may have been rescinded.... */#if 0      printf("prepping dom key ");      processKey.Print();#endif          processKey.Prepare();      if (processKey.IsType(KT_Process) == false) {	fatal("Rescinded thread!\n");	return false;      }        assert( processKey.IsHazard() == false );      assert( processKey.IsPrepared() );      context = ((Node *) processKey.ok.pObj)->GetDomainContext();      if (!context)	return false;          context->SetThread(this);    }#ifdef THREADDEBUG    printf("Preparing context 0x%08x..\n", context);#endif    context->Prepare();    if (state == Thread::IoCompleted) {      state = Thread::Running;      context->SetPC(context->CalcPostInvocationPC());    }        if ( context->IsRunnable() ) {      assert(context->cpuReserve);      assert (cpuReserve == context->cpuReserve);#ifdef DBG_WILD_PTR      if (dbg_wild_ptr && 0)	Check::Consistency("After ThrdPrepare()");#endif      return true;    }    /* The context could not be prepared. */#ifdef OLD_DORESCHED    /* Either context could not be prepared or the resulting context had     * a fault of some kind.  Invoke the domain keeper:     */  #if 1    printf("Invoking domain keeper on Thread 0x%08x pfcount=%d\n",		   this, ((DomainContext*)context)->pfCount);#endif    ((ArchContext *)context)->InvokeDomainKeeper();#ifdef THREADDEBUG    dprintf(true, "After kpr invoke, ctxt=0x%08x, svArea=0x%08x\n",		    context, context->saveArea);#endif#if 0    printf("User thread is prepared!\n");    /* startThread->Wakeup(); */#endif      /* Invoking the domain keeper either stuck us on a sleep queue, in     * which case we Yielded() to the setjmp() above, or migrated the     * current thread to a new domain.  In the latter case, go back to     * the top of this mess to prepare the new context.     */#endif  }  dprintf(true, "Thread start loop exceeded\n");  return false;}voidThread::InvokeMyKeeper(){  ((Process *)context)->InvokeProcessKeeper();      /* Invoking the domain keeper either stuck us on a sleep queue, in   * which case we Yielded() to the setjmp() above, or migrated the   * current thread to a new domain, in which case we will keep   * trying in the Thread::DoReschedule() loop.   */}voidThread::Unprepare(){  if (context) {    context->SyncThread();    context->Unthread();    context = 0;    cpuReserve = 0;  }  /* not hazarded because thread key */  processKey.NH_Unprepare();}

⌨️ 快捷键说明

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