📄 kern_cpureserve.cxx
字号:
/* * 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. *//* Data structures for reserve management. The current kernel * implementation uses a fixed-priority strategy for implementing * cpu reserves. */#include <kerninc/kernel.hxx>#include <kerninc/Thread.hxx>#include <kerninc/CpuReserve.hxx>#include <kerninc/Machine.hxx>#include <kerninc/PhysMem.hxx>#include <arch-kerninc/KernTune.hxx>#include <eros/Reserve.h>const int DEFAULT_SCHED_QUANTA = 10; /* in ms */CpuReserve *CpuReserve::Current = 0;/* Reserves associated with ordinary schedule keys -- the 'priority' * is actually an index into the reserve table: */CpuReserve *CpuReserve::CpuReserveTable;/* Processes that lack a schedule capability need a reserve that they * can be parked on so as to ensure that they are never scheduled. The * priority of this reserve needs to be BELOW the idle priority. */CpuReserve CpuReserve::InactiveReserve(Prio::Inactive);/* Idle thread requires it's own scheduling reserve, as the user-level * idle reserve is actually higher priority than this one. */CpuReserve CpuReserve::KernIdleCpuReserve(Prio::KernIdle);/* Other kernel threads require their own copy of the normal priority * reserve because the reserve table isn't allocated yet when we * allocate some of the early kernel threads. */CpuReserve CpuReserve::KernThreadCpuReserve(Prio::Normal);/* OnQuantaExpiration() is called whenever the residual quanta of a * reserve goes to zero (i.e. when whenever the quanta expires). When * a process hits the end of it's quanta, we recompute the reserve's * effective priority and re-queue the process at that priority. * * The basic idea is that the * low level clock code will down-count the residual quanta. When it * hits zero, it will call Thread::ShouldYield() on the current * thread. The Yield() code will recompute priority for current * thread if appropriate and drop it to the back of the run queue at * that priority. */voidCpuReserve::OnQuantaExpiration(){ /* dprintf(false, "Quanta expired on cpu reserve 0x%08x\n", this); */ Thread::Current()->Preempt();#if 0 if (!Thread::Current()->CAN_PREEMPT()) { printf("CpuReserve::OnQuantaExpiration(): 0x%08x Quanta expires in NOPREEMPT, state %d.\n", Thread::Current(), Thread::Current()->state); }#endif if (residDuration) { /* reserve still active. */ residQuanta = min(residDuration, quanta); residDuration -= quanta; } else { /* not running under reserve. */ if (active) Deplenish(); residQuanta = quanta; } expired = false;}voidCpuReserve::AdjustCurPrio(int prio){ curPrio = prio; Link *nextLink = threadChain.prev; while (nextLink) { Thread *t = Thread::ThreadFromCpuReserveLinkage(nextLink); nextLink = nextLink->next; /* Reposition the thread in the run queue: */ t->Unlink(); t->Wakeup(); }}/* Note that both Deplenish() and Replenish() preserve ordering of * threads in the run queue! */voidCpuReserve::Deplenish(){ /* dprintf(false, "Deplenishing CpuReserve 0x%08x\n", this); */ active = false; AdjustCurPrio(normPrio);}voidCpuReserve::Replenish(){ /* dprintf(false, "Replenishing CpuReserve 0x%08x\n", this); */ /* If a thread under this reserve happens to be currently running, * it gets an extra boost via quanta extension. */ if (period && duration) { active = true; residQuanta = quanta; residDuration = duration - quanta; AdjustCurPrio(rsrvPrio); uint64_t nextPeriod = SysTimer::Now() + period; reserveTimer.WakeupAtTick(nextPeriod, &CpuReserve::Replenish); } else { active = false; AdjustCurPrio(normPrio); } expired = false;}voidCpuReserve::Replenish(Timer* timer){ CpuReserve &r = *((CpuReserve *) timer->client_ptr); r.Replenish();}CpuReserve::CpuReserve(){ start = 0ll; quanta = Machine::MillisecondsToTicks(DEFAULT_SCHED_QUANTA); duration = 0ll; period = 0ll; expired = false; residQuanta = quanta; residDuration = 0ll; rsrvPrio = Prio::Inactive; normPrio = Prio::Inactive; active = false; curPrio = normPrio; reserveTimer.client_ptr = this;}CpuReserve::CpuReserve(int prio){ start = 0ll; quanta = Machine::MillisecondsToTicks(DEFAULT_SCHED_QUANTA); duration = 0ll; period = 0ll; expired = false; residQuanta = quanta; residDuration = 0ll; rsrvPrio = Prio::Inactive; normPrio = prio; active = false; curPrio = normPrio; reserveTimer.client_ptr = this;}voidCpuReserve::AddKernelThread(Thread *t){ AddUserThread(t); assert (t->context); t->context->cpuReserve = this;}/* Reserve linkage not circular! */voidCpuReserve::AddUserThread(Thread *t){ Link& reserveLinkage = t->reserveLinkage;#if 0 if (t->IsUser()) dprintf(true, "Add user thrd 0x%08x to rsrv 0x%08x\n", t, this); else { assert (reserveLinkage.next == 0); assert (reserveLinkage.prev == 0); }#endif reserveLinkage.Unlink(); t->cpuReserve = this; reserveLinkage.next = threadChain.next; if (threadChain.next) threadChain.next->prev = &reserveLinkage; threadChain.next = &reserveLinkage; reserveLinkage.prev = &threadChain;}voidCpuReserve::AllocUserCpuReserves(){ CpuReserveTable = new (0) CpuReserve[MAX_CPU_RESERVE]; for (int i = 0; i < STD_CPU_RESERVE; i++) { CpuReserveTable[i].normPrio = i; CpuReserveTable[i].AdjustCurPrio(i); } printf("Allocated CPU Reserves: 0x%x at 0x%08x\n", sizeof(CpuReserve[MAX_CPU_RESERVE]), CpuReserveTable);}voidCpuReserve::Reset(){ if (quanta == 0) quanta = Machine::MillisecondsToTicks(DEFAULT_SCHED_QUANTA); if (duration && period) { if (start) reserveTimer.WakeupAtTick(start, Replenish); else /* wake it up right now. */ Replenish(); } else { Deplenish(); }}CpuReserve&CpuReserve::GetReserve(const Key& k){ if (k.IsType(KT_Sched)) return CpuReserveTable[k.keyData]; return InactiveReserve;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -