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

📄 kern_thread.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <eros/Key.h>#include <kerninc/Thread.hxx>#include <kerninc/Check.hxx>#include <kerninc/CpuReserve.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Machine.hxx>#include <kerninc/SysTimer.hxx>#include <arch-kerninc/KernTune.hxx>#include <kerninc/util.h>#include <kerninc/Node.hxx>#include <kerninc/Process.hxx>#include <kerninc/PhysMem.hxx>const int SCHED_QUANTA = 10;#define PREEMPTION/* #define THREADDEBUG */const char *Thread::stateNames[Thread::NUM_STATES] = {    "Free",    "Ready",    "Running",    "Stalled",    "IoCompleted",};#if 0/* These definitions were moved to arch/XXX/kernel/IPC-vars.cxx for cache * line locality */Thread* Thread::curThread;bool Thread::threadShouldYield;bool Thread::cannotPreempt;jmp_buf Thread::ThreadRecoveryBlock;#endifThread *Thread::ThreadTable;Thread *Thread::NextFreeThread;#if 0static ThreadPile freeList;#endifThreadPile ProcessorQueue;ThreadPile IdlePile;uint32_t LowestRunningPriority;/* This constructor used when fabricating new threads in IT_Send. * Reserve field will get populated when thread migrates to receiving * context.  */Thread::Thread(){  context = 0;  errCode = 0;  ioCount = 0;  state = Thread::Stall;  nRun = 0;  cpuReserve = 0;}/* Called only for kernel threads */Thread::Thread(Process* pContext){  context = pContext;  errCode = 0;  ioCount = 0;  state = Thread::Stall;  nRun = 0;  cpuReserve = 0;  /* CAREFUL -- reserve cannot be defined here, because of constructor   * order!!!   */}/* Note -- at one point I tried to make all threads have domain keys, * and inoperative threads have domain keys with bad values.  This * DOES NOT WORK, because if the root of the process is rescinded with * a prepared key in an outstanding thread that key will get zeroed. * Yuck!. */voidThread::AllocUserThreads(){  /* Must NOT use the overloaded new() operator!!!!! */  ThreadTable = new (0) Thread[KTUNE_NTHREAD];  NextFreeThread = 0;  for (int i = 0; i < KTUNE_NTHREAD; i++) {    Thread *t = &ThreadTable[i];    t->state = Thread::Free;    t->processKey.IKS_VoidKey();        delete t;  }  printf("Allocated User Threads: 0x%x at 0x%08x\n",		 sizeof(Thread[KTUNE_NTHREAD]), ThreadTable);}void *Thread::operator new(size_t /* sz */){  if (NextFreeThread) {    Thread *t = NextFreeThread;    NextFreeThread = (Thread *) NextFreeThread->next;    t->next = 0;    return t;  }    fatal("Threads exhausted\n");  return 0;}voidThread::operator delete(void *v){  Thread *t = (Thread *) v;  /* dprintf(true, "Deleting thread 0x%08x\n", t); */  /* not hazarded because thread key */  t->processKey.NH_VoidKey();  t->reserveLinkage.Unlink();  t->state = Thread::Free;  if (curThread == t) {#if 0    printf("curthread 0x%08x is deleted\n", t);#endif    curThread = 0;  }  /* This must be done after the unlink, since we are using the field   * in a way that the Link structure doesn't know about.   */  t->next = NextFreeThread;  NextFreeThread = t;}#ifndef NDEBUGboolThread::ValidThreadKey(const Key* pKey){  int i;  for (i = 0; i < KTUNE_NTHREAD; i++) {    if ( &ThreadTable[i].processKey == pKey )      return true;  }  return false;}#endifvoidThread::SleepOn(ThreadPile& p){  IRQ::DISABLE();#if defined(DBG_WILD_PTR)  if (dbg_wild_ptr && 0)    Check::Consistency("In Thread::SleepOn()");#endif  if (state != Running && prev)    fatal("Thread 0x%08x (%s) REqueues q=0x%08x lastq=0x%08x state=%d\n",		  this, Name(), &p, lastq, state);  Thread::DO_NOT_PREEMPT();  lastq = &p;    assert(next == 0);  assert(prev == 0);  Link* ql = &p;  next = ql->next;  prev = ql;  ql->next = this;  if (next)    next->prev = this;  state = Thread::Stall;#ifdef OPTION_DDB  {    extern bool ddb_thread_uqueue_debug;    if (IsUser() && ddb_thread_uqueue_debug)      dprintf(true, "Thread 0x%08x sleeps on queue 0x%08x\n",		      this, &p);  }#endif  IRQ::ENABLE();}voidThread::Delay(uint64_t ms){  assert(curThread == this);  IRQ::DISABLE();  WakeUpIn(ms);  SleepOn(IdlePile);  IRQ::ENABLE();  Yield();}/* Threads only use the timer system when they are about to yield, * sleep, so do not preempt them once they set a timer. */voidThread::WakeUpIn(uint64_t ms){  Thread::DO_NOT_PREEMPT();  assert(Thread::state == Thread::Running);  wakeTime = SysTimer::Now() + Machine::MillisecondsToTicks(ms);  assert(Thread::state == Thread::Running);  SysTimer::AddSleeper(*this);  assert(Thread::state == Thread::Running);}voidThread::WakeUpAtTick(uint64_t tick){  Thread::DO_NOT_PREEMPT();  wakeTime = tick;  SysTimer::AddSleeper(*this);}voidThread::Wakeup(){  IRQ::DISABLE();    int priority = cpuReserve->curPrio;    Unlink();  if (wakeTime) {    assert ( state != Running );    SysTimer::CancelAlarm(*this);    wakeTime = 0;  }    Link* ql = &ProcessorQueue;  Thread *nextThread = (Thread *) ql->next;  while (nextThread && nextThread->cpuReserve->curPrio >= priority) {#ifdef OPTION_DDB    {      extern bool ddb_thread_uqueue_debug;      if (IsUser() && ddb_thread_uqueue_debug)	dprintf(true, "Thread 0x%08x sleeps on queue 0x%08x (ProcessorQueue)\n",			this, &ProcessorQueue);    }#endif    ql = (Link *) nextThread;    nextThread = (Thread *) ql->next;  }  /* Either there are no more threads, or we should be inserted   * after ql:   */  next = ql->next;  prev = ql;  ql->next = this;  if (next)    next->prev = this;  state = Thread::Ready;  lastq = &ProcessorQueue;  /* Do not set threadShouldYield until the first thread runs!   * There may not be a curthread if we are being woken up because   * the previous thread died.   * assert(curThread);   */  if (curThread && cpuReserve->curPrio > curThread->cpuReserve->curPrio) {#if 0    printf("Wake 0x%08x Cur thread should yield. canPreempt=%c\n",		   this, canPreempt ? 'y' : 'n');#endif    curThread->Preempt();  }  IRQ::ENABLE();#ifdef DBG_WILD_PTR  if (dbg_wild_ptr)    Check::Consistency("In Thread::Wakeup()");#endif}#if 0extern "C" {  void resume_from_savearea(SaveArea*);}#endifvoidThread::Expired(Timer*){  Preempt();  #if 0  if (!CAN_PREEMPT()) {    printf("0x%08x Quanta expires in NOPREEMPT, state %d.\n",		   curThread, curThread->state);   }#endif}#ifdef PREEMPTION/* static Timer QuantaTimer; */#endifinline voidThread::ChooseNewCurrentThread(){  assert ( ProcessorQueue.IsEmpty() == false );      assert( IRQ::DISABLE_DEPTH() == 1 );  IRQ::DISABLE();  curThread = (Thread*) ProcessorQueue.next;  assert(curThread);      curThread->Unlink();  curThread->state = Thread::Running;  IRQ::ENABLE();  assert( IRQ::DISABLE_DEPTH() == 1 );}/* DoReschedule() is called for a number of reasons: *  *     1. No current thread *     2. Current thread preempted *     3. Current thread not prepared *     4. Current thread's context not prepared *     5. Current thread has fault code (keeper invocation needed) *  * In the old logic, only thread prepare could Yield().  In the new * logic, the keeper invocation may also yield.  For this reason, both * the prepare logic and the keeper invocation logic are in separate * functions for now.  I am seriously contemplating integrating them * into the main code body and setting up a recovery block here. *//* FIX: Somewhere in here the context pins are not getting updated * correctly.  It's not important until we do SMP. */voidThread::DoReschedule(){  assert( IRQ::DISABLE_DEPTH() == 1 );#ifdef DBG_WILD_PTR  if (dbg_wild_ptr && 0)    Check::Consistency("In DoReschedule()");#endif  /* DoReschedule may be called from the timer interrupt when kernel   * interrupts are enabled.  If so, suppress if we are in a   * no-preempt state, as in this event the thread will shortly yield   * in any case:   */    if (yieldState == (ys_ShouldYield | ys_NoPreempt)) {    printf("0x%08x Preempt suppressed, state=%d\n",		   curThread, curThread->state);    return;  }  /* On the way out of an invocation trap there may be no current   * thread, in which case we may need to choose a new one:   */  if (curThread == 0) {    ChooseNewCurrentThread();    yieldState = 0;  }  if (yieldState == ys_ShouldYield) {    /* Current thread may be stalled or dead; if so, don't stick it     * back on the run list!     */    if ( curThread->state == Thread::Running ) {      curThread->Wakeup();	/* perverse, but correct. */#ifdef THREADDEBUG      if ( curThread->IsUser() )	printf("Active thread goes to end of run queue\n");#endif

⌨️ 快捷键说明

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