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

📄 thread.hxx

📁 C++ 编写的EROS RTOS
💻 HXX
字号:
#ifndef __THREAD_HXX__#define __THREAD_HXX__/* * Copyright (C) 1998, 1999, 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. *//* EROS thread list management.  For every process that is runnable or * stalled, an entry exists in the thread list.  When one * domain invokes another, it hands its entry to the invoked domain. * When a thread forks, it allocates a new slot.  Threads will * block if they fork when no slot is available.  When a thread * exits, it returns its thread table slot entry to the free list.  */#include <kerninc/Link.hxx>#include <kerninc/Key.hxx>#include <kerninc/Process.hxx>#include <kerninc/SysTimer.hxx>#include <kerninc/CpuReserve.hxx>#include <eros/ProcessState.h>#include <eros/setjmp.h>struct CpuReserve;/* The thread structure captures the portion of a domain's state that * MUST remain in core while the domain is logically running or * blocked.  An idle domain is free to go out of core. * * When one domain invokes another, it's thread table slot is * transferred, but it's VCPU entry is not. */struct Thread : public Link {  class Process *context;	/* zero if no context cache entry. */  void *lastq;  /* FIX: following will only work for a uniprocessor.   * correct thing to do is move it to the processor class   * when we have one.   */    friend int main(int);		/* So that main can set the initial				 * current thread! */    Link reserveLinkage;    static inline void ChooseNewCurrentThread();  static void DoReschedule();protected:  enum {    ys_ShouldYield = 0x1,    ys_NoPreempt = 0x2  };    static uint32_t    yieldState;    static Thread* curThread;  static void Expired(struct Timer *);public:  static void  DO_NOT_PREEMPT()  {    yieldState |= ys_NoPreempt;  }    static bool CAN_PREEMPT()  {    return (yieldState & ys_NoPreempt) == 0;  }    static Thread* Current()	/* retrieves the current thread */  {    return curThread;  }  static void SetCurThread(Thread* thrd)  {    curThread = thrd;  }    enum State {    Free,			/* free thread table slot */    Ready,			/* can be scheduled */    Running,			/* active on a processor */    Stall,			/* blocked on an event, not expecting				   result(s) */    IoCompleted,		/* raw I/O completed */  };  enum { NUM_STATES = IoCompleted + 1 };  static const char *stateNames[NUM_STATES];   uint8_t state;  uint8_t pageWriteCount;		/* for fair-share migration */  enum { FairMigrateWrites = 2 };    Key processKey;		/* type==KtProcess */public:  static Process* CurContext()	/* retrieves the current context */  {    assert(curThread->context);    return curThread->context;  }  bool IsUser()  {    /* hack alert! */    return ( context == 0 || context->IsUser() );  }    bool IsKernel()  {    /* hack alert! */    return ( context && context->IsKernel() );  }    /* ARCHITECTURAL CONSTRAINT!!   *    * If a thread has invoked a kernel key that put it to sleep, then   * the return information must be expressable as an error code + an   * optional ioCount.  The error code will be copied back to the   * thread if it is stalled on a key invocation (as opposed to a   * page fault).  The ioCount will be copied back to the thread if   * it is stalled on a raw I/O event.   */    uint32_t errCode;		/* error code to deliver on restart */  uint32_t ioCount;		/* io bytes xfered - returned in msg		 */				/* data word if raw I/O				 */  CpuReserve *cpuReserve;  /* Support for the per-thread timer structure.  The only user   * threads that will use this are the ones invoking primary system   * timer keys.   */  uint64_t wakeTime;		/* if asleep, when to wake up, in milliseconds */  Thread *nextTimedThread;    Thread();  Thread(Process* pContext);  /* If prepare returns false, the thread is dead and should be placed   * on the free list.  This can happen if the domain root has been   * rescinded.   */  bool Prepare();  void InvokeMyKeeper();  inline void Resume() NORETURN;    void Unprepare();  static bool ShouldYield()  {    return (yieldState & ys_ShouldYield);  }  static void Preempt()  {    yieldState |= ys_ShouldYield;  }    static void ForceResched()  {    yieldState = ys_ShouldYield;  }    static inline void Reschedule();  inline bool IsRunnable();  /* For debugging only: */#ifndef NDEBUG  void ValidateUserThread();#endif  const char *Name();  uint32_t nRun;  inline void MigrateTo(Process *);  inline void ZapContext();  static void HandleYieldEntry() NORETURN;  /* Called by the thread when it wishes to yield the processor: */  inline void Yield(bool verbose = false)  {    __asm__ __volatile__ ("jmp LowYield");  }  /* Called by kernel thread when it wishes to yield the processor: */  void DirectedYield(bool verbose = false);  /* Called by the thread to go to sleep on a queue or pile: */  void Delay(uint64_t ms);    void WakeUpIn(uint64_t ms);  void WakeUpAtTick(uint64_t tick);  /* void SleepOn(class ThreadQueue&, Thread::State newState);   * void SleepOn(class ThreadPile&, Thread::State newState);   */  void SleepOn(class ThreadPile&);private:  friend class ThreadQueue;  friend class ThreadPile;public:  void Wakeup();  /* Pool management: */  void * operator new(size_t);  void operator delete(void *);  static Thread *ThreadTable;  static Thread *NextFreeThread;#ifndef NDEBUG  static bool ValidThreadKey(const Key *pKey);#endif  static Thread *ThreadFromCpuReserveLinkage(Link *tlnk)  {#define woffsetof(s, m) ((uint32_t) &((s *)0)->m)    uint32_t wvp = (uint32_t) tlnk;    wvp -= woffsetof(Thread, reserveLinkage);    return (Thread *) wvp;#undef woffsetof  }    static Thread* ContainingThread(void *vp)  {    uint32_t wvp = (uint32_t) vp;    wvp -= (uint32_t) ThreadTable;    wvp /= sizeof(Thread);    return ThreadTable + wvp;  }    static bool IsThreadKey(const Key *pKey)  {    /* This isn't quite right, as it will return TRUE for any random     * pointer in to the thread table, but that's good enough for all     * the places that we use it.     */        if ( ((uint32_t) pKey >= (uint32_t) ThreadTable) &&	 ((uint32_t) pKey < (uint32_t) &ThreadTable[KTUNE_NTHREAD]) ) {      return true;    }    return false;  }  static void AllocUserThreads();} ;inline voidThread::Resume(){  assert ( context );  context->Resume();}inline boolThread::IsRunnable(){  return (context	  && context->IsRunnable()	  && (context->processFlags & PF_Faulted) == 0);}inline voidThread::Reschedule(){  if (curThread && (yieldState != ys_ShouldYield)      && curThread->IsRunnable())    return;    DoReschedule();}/* This relies on the fact that the context will overwrite our domain * key slot if it is unloaded! *  * It proves that the only thread migrations that occur in EROS are to * domains that are runnable.  If a domain is runnable, we know that * it has a proper schedule key.  We can therefore assume that the * reserve slot of the destination context is populated, and we can * simply pick it up and go with it. */inline voidThread::MigrateTo(Process *dc){  if (context)    context->Unthread();      context = dc;  if (dc) {    dc->SetThread(this);    assert (dc->IsRunnable());    if (cpuReserve != dc->cpuReserve)      dc->cpuReserve->AddUserThread(this);  }  else {    delete this;		/* migrate to 0 context => kill curThread */  }}/* This relies on the fact that the context will overwrite our domain * key slot if it is unloaded! */inline voidThread::ZapContext(){  context = 0;}/* The KernThread structure is completely superfluous; it simply makes * declaring kernel threads somewhat easier. */struct KernThread : public Thread {  KernProcess procContext;  /* NOTE must regrettable hand-initialize the reserves for these   * because cannot guarantee global constructor ordering   */  #if 0  /* used by main(): */  KernThread(const char * name)    : Thread(&procContext),      procContext(name, *this)  {    context = &procContext;  }#endif    KernThread(const char * name,	     void (*pc)(),	     uint32_t *StackBottom, uint32_t *StackTop)    : Thread(&procContext),      procContext(name, *this, pc, StackBottom, StackTop)  {    context = &procContext;  }};#endif /* __THREAD_HXX__ */

⌨️ 快捷键说明

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