📄 thread.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 + -