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

📄 kern_systimer.cxx

📁 C++ 编写的EROS RTOS
💻 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. */#include <kerninc/kernel.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Machine.hxx>#include <kerninc/SysTimer.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Task.hxx>#include <kerninc/ObjectCache.hxx>#include <eros/TimePage.h>#include <eros/TimeOfDay.h>#include <kerninc/PhysMem.hxx>/* SysTimer is a very special sort of device, in that it is only KIND * of an interrupt handler.  When the system hardware clock is * configured, it gives SysTimer::Wakeup() as the routine to call when * the clock interrupt occurs.  That's not really what happens. *  * The clock interrupt needs to be fast when there is nothing to do, * so there is a machine specific fast path interrupt handler for the * clock interrupt that is written in assembly language.  When the * clock interrupt goes off, the fast path handler increments the * value of 'now'.  It then checks to see if wakeup > now, in which * case there is nothing to wake up.  If that condition holds, the * fast path handler returns from the interrupt immediately WITHOUT * running the general interrupt dispatch logic. *  * The end effect is that SysTimer::Wakeup() is only called when there * is really something to wake up. *//* For EROS, the desired timer granularity is milliseconds. * Unfortunately this is very much too fast for some hardware.  The * rule is that you will sleep for as long as you asked for or one * hardclock tick, whichever is LONGER.  Also, you will NEVER sleep * for more than a year. */#if 0  uint64_t wakeTime;		/* if asleep, when to wake up, in milliseconds */  Thread *nextTimer;  void (*wakeFun)();  SleepFor(uint64_t ms, void (*wakeFun)());  Disarm();#endifstruct Thread *ThreadChain = 0;struct Timer *TimerChain = 0;volatile uint64_t SysTimer::now = 0llu;volatile uint64_t SysTimer::wakeup = ~(0llu);voidSysTimer::ResetWakeTime(){  wakeup = ~(0llu);  if (TimerChain && TimerChain->wakeTime < wakeup)    wakeup = TimerChain->wakeTime;  if (ThreadChain && ThreadChain->wakeTime < wakeup)    wakeup = ThreadChain->wakeTime;}voidSysTimer::Wakeup(class fixregs_t *sa){  IRQ::DISABLE();  #if 0  extern intDepth;  printf("Wakeup() at intDepth %d, sleepers? %c\n",	       intDepth, ThreadChain ? 'y' : 'n');#endif#if 0  printf("SysTimer::Tick() resets waketime at %d\n", (long) now);#endif  wakeup = ~(0llu);		/* essentially never */	  if (CpuReserve::Current->expired)    CpuReserve::Current->OnQuantaExpiration();    /* The awkward loop must be used because calling t->wakeup()   * mutates the sleeper list.   */      while (ThreadChain && ThreadChain->wakeTime <= now) {    register Thread *t = ThreadChain;    ThreadChain = ThreadChain->nextTimedThread;#if 0    if ( t->IsUser() )      printf("wake sleeper; now %u waketime %u nextwake %u\n",		     (uint32_t) now, (uint32_t)t->wakeTime,		     (uint32_t) wakeup);#endif    t->Wakeup();  }  while (TimerChain && TimerChain->wakeTime <= now) {    register Timer *t = TimerChain;    TimerChain = TimerChain->nextTimer;    t->wakeFun(t);  }  ResetWakeTime();  IRQ::ENABLE();  IRQ::Enable(IRQ_FROM_EXCEPTION(sa->ExceptNo));}voidSysTimer::AddSleeper(Thread& t){  IRQ::DISABLE();  if (ThreadChain == 0 || t.wakeTime < ThreadChain->wakeTime) {    t.nextTimedThread = ThreadChain;    ThreadChain = &t;    ResetWakeTime();  }  else {    Thread **sleeper = &(ThreadChain->nextTimedThread);    while (*sleeper && (*sleeper)->wakeTime < t.wakeTime)      sleeper = &((*sleeper)->nextTimedThread);    /* We are either off the end of the list or looking at one whose     * wakeup value is greater than ours:     */    t.nextTimedThread = *sleeper;    *sleeper = &t;  }#if 1  /* Sanity check.  We know there is at least 1 thread on the list. */  register Thread *cur = ThreadChain;  do {    register Thread *next = cur->nextTimedThread;    if (next)      assert(cur->wakeTime <= next->wakeTime);    cur = next;  } while(cur);#endif  #if 0  if ( t.IsUser() )    printf("added sleeper; now %u waketime %u nextwake %u\n",		   (uint32_t) now, (uint32_t)t.wakeTime,		   (uint32_t) wakeup);#endif  IRQ::ENABLE();}voidSysTimer::CancelAlarm(Thread& t){  IRQ::DISABLE();#if 0  printf("Canceling alarm on thread 0x%x\n", &t);#endif    if (ThreadChain == &t) {    ThreadChain = t.nextTimedThread;    ResetWakeTime();  }  else {    for ( Thread *sleeper = ThreadChain;	  sleeper; 	  sleeper = sleeper->nextTimedThread ) {      if (sleeper->nextTimedThread == &t) {	sleeper->nextTimedThread = t.nextTimedThread;	break;      }    }  }  IRQ::ENABLE();}voidSysTimer::AddTimer(Timer& t){  IRQ::DISABLE();  if (TimerChain == 0 || t.wakeTime < TimerChain->wakeTime) {#if 0    printf("Insert first timer. nxt=0x%08x tnxt=0x%08x\n",		   TimerChain, t.nextTimer);#endif    t.nextTimer = TimerChain;    TimerChain = &t;    ResetWakeTime();  }  else {    Timer **sleeper = &(TimerChain->nextTimer);    while (*sleeper && (*sleeper)->wakeTime < t.wakeTime)      sleeper = &((*sleeper)->nextTimer);    /* We are either off the end of the list or looking at one whose     * wakeup value is greater than ours:     */    t.nextTimer = *sleeper;    *sleeper = &t;  }#if 1  /* Sanity check.  We know there is at least 1 thread on the list. */  register Timer *cur = TimerChain;  do {    register Timer *next = cur->nextTimer;    if (next)      assert(cur->wakeTime <= next->wakeTime);    cur = next;  } while(cur);#endif  #if 0  printf("added timer; now %u waketime %u nextwake %u\n",	       (uint32_t) now, (uint32_t)t.wakeTime,	       (uint32_t) wakeup);#endif  IRQ::ENABLE();}voidSysTimer::CancelTimer(Timer& t){  IRQ::DISABLE();  if (t.wakeTime == 0ll) {    IRQ::ENABLE();    return;  }  #if 0  printf("Canceling alarm on timer 0x%x\n", &t);#endif    if (TimerChain == &t) {#if 0    printf("Remove first timer. nxt=0x%08x\n", t.nextTimer);#endif    TimerChain = t.nextTimer;    ResetWakeTime();  }  else {    for (Timer *sleeper = TimerChain;	 sleeper;	 sleeper = sleeper->nextTimer) {      if (sleeper->nextTimer == &t) {	sleeper->nextTimer = t.nextTimer;	break;      }    }  }  t.wakeTime = 0ll;  t.nextTimer = 0;  IRQ::ENABLE();}voidTimer::WakeupIn(uint64_t ms, void (*wkfn)(Timer*)){  wakeTime = SysTimer::Now() + Machine::MillisecondsToTicks(ms);  wakeFun = wkfn;  SysTimer::AddTimer(*this);}voidTimer::WakeupAt(uint64_t ms, void (*wkfn)(Timer*)){  wakeTime = Machine::MillisecondsToTicks(ms);  wakeFun = wkfn;  SysTimer::AddTimer(*this);}voidTimer::WakeupAtTick(uint64_t tick, void (*wkfn)(Timer*)){  wakeTime = tick;  wakeFun = wkfn;  SysTimer::AddTimer(*this);}/************************************************** * SUPPORT FOR THE TIME PAGE **************************************************/static volatile TimePageStruct *eros_tod_struct = 0;ObjectHeader *SysTimer::TimePageHdr = 0;Timer TimePageTimer;struct timeval wallBase;void TimePageTick(Timer *){  uint64_t timenow = SysTimer::Now();  timenow = Machine::TicksToMilliseconds(timenow);  uint32_t now_secs = timenow/1000;  uint32_t now_usecs = timenow % 1000;  IRQ::DISABLE();  eros_tod_struct->tps_sinceboot.tv_secs = now_secs;  eros_tod_struct->tps_sinceboot.tv_usecs = now_usecs;  /* Time of day init zeroed usecs, so no need to do that     arithmetic. */  eros_tod_struct->tps_wall.tv_secs = wallBase.tv_secs + now_secs;  eros_tod_struct->tps_wall.tv_usecs = now_usecs;  IRQ::ENABLE();  TimePageTimer.WakeupIn(5ul, TimePageTick);}#define HRS_PER_DAY 24#define MINS_PER_HR 60#define SECS_PER_MIN 60#define SECS_PER_HR (SECS_PER_MIN * MINS_PER_HR)#define SECS_PER_DAY (HRS_PER_DAY * SECS_PER_HR)/* Remember that this runs before the first thread, so must not   yield. */voidSysTimer::BootInit(){}voidSysTimer::InitTimePage(){  printf("Fabricating TOD Page\n");  TimePageHdr = ObjectCache::GrabPageFrame();    eros_tod_struct = (TimePageStruct *)    ObjectCache::ObHdrToPage(TimePageHdr);  eros_tod_struct->tps_version = TIMEPAGE_VERSION;  eros_tod_struct->tps_sinceboot.tv_secs = 0;  eros_tod_struct->tps_sinceboot.tv_usecs = 0;  eros_tod_struct->tps_wall.tv_secs = 0;  eros_tod_struct->tps_wall.tv_usecs = 0;      TimeOfDay tod;  Machine::GetHardwareTimeOfDay(tod);  wallBase.tv_usecs = 0;  wallBase.tv_secs = tod.utcDay * SECS_PER_DAY;  TimePageTimer.WakeupIn(5ul, TimePageTick);}

⌨️ 快捷键说明

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