📄 kern_thread.cxx
字号:
} 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 + -