📄 kthread.c.bak
字号:
}}/* ---------------------------------------------------------------------- * Public functions * ---------------------------------------------------------------------- */void Init_Scheduler(void){ struct Kernel_Thread* mainThread = (struct Kernel_Thread *) KERN_THREAD_OBJ; /* * Create initial kernel thread context object and stack, * and make them current. */ Init_Thread(mainThread, (void *) KERN_STACK, PRIORITY_NORMAL, true); g_currentThread = mainThread; Add_To_Back_Of_All_Thread_List(&s_allThreadList, mainThread); /* * Create the idle thread. */ /*Print("starting idle thread\n");*/ Start_Kernel_Thread(Idle, 0, PRIORITY_IDLE, true); /* * Create the reaper thread. */ /*Print("starting reaper thread\n");*/ Start_Kernel_Thread(Reaper, 0, PRIORITY_NORMAL, true);}/* * Start a kernel-mode-only thread, using given function as its body * and passing given argument as its parameter. Returns pointer * to the new thread if successful, null otherwise. * * startFunc - is the function to be called by the new thread * arg - is a paramter to pass to the new function * priority - the priority of this thread (use PRIORITY_NORMAL) for * most things * detached - use false for kernel threads */struct Kernel_Thread* Start_Kernel_Thread( Thread_Start_Func startFunc, ulong_t arg, int priority, bool detached){ struct Kernel_Thread* kthread = Create_Thread(priority, detached); if (kthread != 0) { /* * Create the initial context for the thread to make * it schedulable. */ Setup_Kernel_Thread(kthread, startFunc, arg); /* Atomically put the thread on the run queue. */ Make_Runnable_Atomic(kthread); } return kthread;}/* * Start a user-mode thread (i.e., a process), using given user context. * Returns pointer to the new thread if successful, null otherwise. */struct Kernel_Thread*Start_User_Thread(struct User_Context* userContext, bool detached){ /* * Hints: * - Use Create_Thread() to create a new "raw" thread object * - Call Setup_User_Thread() to get the thread ready to * execute in user mode * - Call Make_Runnable_Atomic() to schedule the process * for execution */// TODO("Start user thread"); struct Kernel_Thread * kthread = Create_Thread(PRIORITY_USER, detached); if (kthread != 0) { Setup_User_Thread(kthread, userContext); Make_Runnable_Atomic(kthread); } return kthread;}/* * Add given thread to the run queue, so that it * may be scheduled. Must be called with interrupts disabled! */void Make_Runnable(struct Kernel_Thread* kthread){ KASSERT(!Interrupts_Enabled()); { int currentQ = kthread->currentReadyQueue; KASSERT(currentQ >= 0 && currentQ < MAX_QUEUE_LEVEL); kthread->blocked = false; Enqueue_Thread(&s_runQueue[currentQ], kthread); }}/* * Atomically make a thread runnable. * Assumes interrupts are currently enabled. */void Make_Runnable_Atomic(struct Kernel_Thread* kthread){ Disable_Interrupts(); Make_Runnable(kthread); Enable_Interrupts();}/* * Get the thread that currently has the CPU. */struct Kernel_Thread* Get_Current(void){ return g_currentThread;}/* * Get the next runnable thread from the run queue. * This is the scheduler. *///struct Kernel_Thread* Get_Next_Runnable(void)//{// struct Kernel_Thread* best = 0;//// best = Find_Best(&s_runQueue);// KASSERT(best != 0);// Remove_Thread(&s_runQueue, best);/////*// * Print("Scheduling %x\n", best);// */// return best;//}/* * Get the next runnable thread from the run queue. * This is the scheduler. */struct Kernel_Thread* Get_Next_Runnable(void){ struct Kernel_Thread* best = 0; /* Find the best thread from the highest-priority run queue */// TODO("Find a runnable thread from run queues"); if(g_SchedPolicy==1) { best=Find_Best(&s_runQueue[0]); if(best!=0) { KASSERT(best!=0); Remove_Thread(&s_runQueue[0],best); return best; } best=Find_Best(&s_runQueue[1]); if(best!=0) { KASSERT(best!=0); Remove_Thread(&s_runQueue[1],best); return best; } best=Find_Best(&s_runQueue[2]); if(best!=0) { KASSERT(best!=0); Remove_Thread(&s_runQueue[2],best); return best; } best=Find_Best(&s_runQueue[3]); if(best!=0) { KASSERT(best!=0); Remove_Thread(&s_runQueue[3],best); return best; } } else { best = Find_Best(&s_runQueue); KASSERT(best != 0); Remove_Thread(&s_runQueue, best); return best; }}/* * Schedule a thread that is waiting to run. * Must be called with interrupts off! * The current thread should already have been placed * on whatever queue is appropriate (i.e., either the * run queue if it is still runnable, or a wait queue * if it is waiting for an event to occur). */void Schedule(void){ struct Kernel_Thread* runnable; /* Make sure interrupts really are disabled */ KASSERT(!Interrupts_Enabled()); /* Preemption should not be disabled. */ KASSERT(!g_preemptionDisabled); /* Get next thread to run from the run queue */ runnable = Get_Next_Runnable(); /* * Activate the new thread, saving the context of the current thread. * Eventually, this thread will get re-activated and Switch_To_Thread() * will "return", and then Schedule() will return to wherever * it was called from. */ Switch_To_Thread(runnable);}/* * Voluntarily give up the CPU to another thread. * Does nothing if no other threads are ready to run. */void Yield(void){ Disable_Interrupts(); Make_Runnable(g_currentThread); Schedule(); Enable_Interrupts();}/* * Exit the current thread. * Calling this function initiates a context switch. */void Exit(int exitCode){ struct Kernel_Thread* current = g_currentThread; if (Interrupts_Enabled()) Disable_Interrupts(); /* Thread is dead */ current->exitCode = exitCode; current->alive = false; /* Clean up any thread-local memory */ Tlocal_Exit(g_currentThread); /* Notify the thread's owner, if any */ Wake_Up(¤t->joinQueue); /* Remove the thread's implicit reference to itself. */ Detach_Thread(g_currentThread); /* * Schedule a new thread. * Since the old thread wasn't placed on any * thread queue, it won't get scheduled again. */ Schedule(); /* Shouldn't get here */ KASSERT(false);}/* * Wait for given thread to die. * Interrupts must be enabled. * Returns the thread exit code. */int Join(struct Kernel_Thread* kthread){ int exitCode; KASSERT(Interrupts_Enabled()); /* It is only legal for the owner to join */ KASSERT(kthread->owner == g_currentThread); Disable_Interrupts(); /* Wait for it to die */ while (kthread->alive) { Wait(&kthread->joinQueue); } /* Get thread exit code. */ exitCode = kthread->exitCode; /* Release our reference to the thread */ Detach_Thread(kthread); Enable_Interrupts(); return exitCode;}/* * Look up a thread by its process id. * The caller must be the thread's owner. */struct Kernel_Thread* Lookup_Thread(int pid){ struct Kernel_Thread *result = 0; bool iflag = Begin_Int_Atomic(); /* * TODO: we could remove the requirement that the caller * needs to be the thread's owner by specifying that another * reference is added to the thread before it is returned. */ result = Get_Front_Of_All_Thread_List(&s_allThreadList); while (result != 0) { if (result->pid == pid) { if (g_currentThread != result->owner) result = 0; break; } result = Get_Next_In_All_Thread_List(result); } End_Int_Atomic(iflag); return result;}/* * Wait on given wait queue. * Must be called with interrupts disabled! * Note that the function will return with interrupts * disabled. This is desirable, because it allows us to * atomically test a condition that can be affected by an interrupt * and wait for it to be satisfied (if necessary). * See the Wait_For_Key() function in keyboard.c * for an example. */void Wait(struct Thread_Queue* waitQueue){ struct Kernel_Thread* current = g_currentThread; KASSERT(!Interrupts_Enabled()); /* Add the thread to the wait queue. */ current->blocked = true; Enqueue_Thread(waitQueue, current); /* Find another thread to run. */ Schedule();}/* * Wake up all threads waiting on given wait queue. * Must be called with interrupts disabled! * See Keyboard_Interrupt_Handler() function in keyboard.c * for an example. */void Wake_Up(struct Thread_Queue* waitQueue){ struct Kernel_Thread *kthread = waitQueue->head, *next; KASSERT(!Interrupts_Enabled()); /* * Walk throught the list of threads in the wait queue, * transferring each one to the run queue. */ while (kthread != 0) { next = Get_Next_In_Thread_Queue(kthread); Make_Runnable(kthread); kthread = next; } /* The wait queue is now empty. */ Clear_Thread_Queue(waitQueue);}/* * Wake up a single thread waiting on given wait queue * (if there are any threads waiting). Chooses the highest priority thread. * Interrupts must be disabled! */void Wake_Up_One(struct Thread_Queue* waitQueue){ struct Kernel_Thread* best; KASSERT(!Interrupts_Enabled()); best = Find_Best(waitQueue); if (best != 0) { Remove_Thread(waitQueue, best); Make_Runnable(best); /*Print("Wake_Up_One: waking up %x from %x\n", best, g_currentThread); */ }}/* * Allocate a key for accessing thread-local data. */int Tlocal_Create(tlocal_key_t *key, tlocal_destructor_t destructor) { KASSERT(key); bool iflag = Begin_Int_Atomic(); if (s_tlocalKeyCounter == MAX_TLOCAL_KEYS) return -1; s_tlocalDestructors[s_tlocalKeyCounter] = destructor; *key = s_tlocalKeyCounter++; End_Int_Atomic(iflag); return 0;}/* * Store a value for a thread-local item */void Tlocal_Put(tlocal_key_t k, const void *v) { const void **pv; KASSERT(k < s_tlocalKeyCounter); pv = Get_Tlocal_Pointer(k); *pv = v;}/* * Acquire a thread-local value */void *Tlocal_Get(tlocal_key_t k) { const void **pv; KASSERT(k < s_tlocalKeyCounter); pv = Get_Tlocal_Pointer(k); return (void *)*pv;}/* * Print list of all threads in system. * For debugging. */void Dump_All_Thread_List(void){ struct Kernel_Thread *kthread; int count = 0; bool iflag = Begin_Int_Atomic(); kthread = Get_Front_Of_All_Thread_List(&s_allThreadList); Print("["); while (kthread != 0) { ++count; Print("<%lx,%lx,%lx>", (ulong_t) Get_Prev_In_All_Thread_List(kthread), (ulong_t) kthread, (ulong_t) Get_Next_In_All_Thread_List(kthread)); KASSERT(kthread != Get_Next_In_All_Thread_List(kthread)); kthread = Get_Next_In_All_Thread_List(kthread); } Print("]\n"); Print("%d threads are running\n", count); End_Int_Atomic(iflag);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -