/* Copyright 2000 (c) by Reto Gaehler, George Fankhauser Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Threads/TMTimer.c,v $ Author(s): Affiliation: ETH Zuerich, TIK Version: $Revision: 1.1 $ Creation Date: Last Date of Change: $Date: 2000/03/31 17:50:40 $ by: $Author: gfa $ $Log: TMTimer.c,v $ Revision 1.1 2000/03/31 17:50:40 gfa Merged with /Net from several term projects */ #include "TMTimer.h" #include "Lock.h" //************************************************************************************************** // TMTimer globals //************************************************************************************************** static long int gn32TQTimer; static LockDesc gLock; static tqentptr gpTQHead; static tqentptr gpFreeEvents; static long int gnNumOfFreeEvents; static tqent gTimerEvents[TIMER_MAX_EVENTS]; //************************************************************************************************** // tmTimerInit //************************************************************************************************** void tmTimerInit() { gpTQHead=0L; gpFreeEvents=0L; for (gnNumOfFreeEvents=0;gnNumOfFreeEventstq_next) { if (newtq->tq_timeleft < tq->tq_timeleft) break; newtq->tq_timeleft -= tq->tq_timeleft; ptq = tq; } newtq->tq_next = tq; if (ptq) ptq->tq_next = newtq; else gpTQHead = newtq; if (tq) tq->tq_timeleft -= newtq->tq_timeleft; } //************************************************************************************************** // tmTimerInterrupt // timer interrupt service routine (called every 10ms) //************************************************************************************************** void tmTimerInterrupt() { tqentptr tq; gn32TQTimer++; //timer interrupt, reject if somebody is working in the queue? if (gLock.lockVariable==FALSE) { if (gpTQHead) { gpTQHead->tq_timeleft--; } while (gpTQHead != 0 && gpTQHead->tq_timeleft <= 0) { tq = gpTQHead; gpTQHead = gpTQHead->tq_next; tq->tq_fire(tq->tq_pParam,tq->tq_n32Param,tq->tq_pMsg1,tq->tq_pMsg2,tq->tq_u32Msg); if (tq->tq_interval>0) { tq->tq_next = NULL; tq->tq_entrytime = gn32TQTimer; tq->tq_timeleft = tq->tq_interval; tmInsertElement(tq); } else { //insert in free list tq->tq_next=gpFreeEvents; gpFreeEvents=tq; gnNumOfFreeEvents++; } } } else { //reject interrupt } } //************************************************************************************************** // tmLeftTimer // returns the remaining time of a timer queue element //************************************************************************************************** int tmLeftTimer(tmCallBackProc fire,void *pParam, long n32Param, void *pMsg1,void *pMsg2,unsigned long u32Msg) { tqentptr tq; int timeleft = 0; if (gpTQHead == NULL) return 0; lock(&gLock); for (tq = gpTQHead; tq != NULL; tq = tq->tq_next) { timeleft += tq->tq_timeleft; if (tq->tq_fire==fire && tq->tq_pParam==pParam && tq->tq_n32Param==n32Param && tq->tq_pMsg1==pMsg1 && tq->tq_pMsg2==pMsg2 && tq->tq_u32Msg==u32Msg) { unlock(&gLock); return timeleft; } } unlock(&gLock); return 0; } //************************************************************************************************** // tmClearTimer // removes a timer queue element //************************************************************************************************** int tmClearTimer( tmCallBackProc fire,void *pParam, long n32Param, void *pMsg1,void *pMsg2,unsigned long u32Msg) { tqentptr prev, ptq; int timespent; lock(&gLock); prev = 0; for (ptq = gpTQHead; ptq != NULL; ptq = ptq->tq_next) { if (ptq->tq_fire==fire && ptq->tq_pParam==pParam && ptq->tq_n32Param==n32Param && ptq->tq_pMsg1==pMsg1 && ptq->tq_pMsg2==pMsg2 && ptq->tq_u32Msg==u32Msg) { timespent = gn32TQTimer - ptq->tq_entrytime; if (prev) prev->tq_next = ptq->tq_next; else gpTQHead = ptq->tq_next; if (ptq->tq_next) ptq->tq_next->tq_timeleft += ptq->tq_timeleft; //insert in free list ptq->tq_next=gpFreeEvents; gpFreeEvents=ptq; gnNumOfFreeEvents++; unlock(&gLock); return timespent; } prev = ptq; } unlock(&gLock); return TIMER_FAILED; } //************************************************************************************************** // tmSetTimer // inserts a timer queue element //************************************************************************************************** int tmSetTimer( tmCallBackProc fire, void *pParam, long n32Param, void *pMsg1,void *pMsg2,unsigned long u32Msg,int time,Boolean bRepeat) { tqentptr newtq; //are any events in free list? if (gnNumOfFreeEvents>0) { newtq=gpFreeEvents; gpFreeEvents=newtq->tq_next; gnNumOfFreeEvents--; } else { return TIMER_FAILED; } newtq->tq_fire=fire; newtq->tq_timeleft=time; newtq->tq_pParam=pParam; newtq->tq_n32Param=n32Param; newtq->tq_pMsg1=pMsg1; newtq->tq_pMsg2=pMsg2; newtq->tq_u32Msg=u32Msg; newtq->tq_next = NULL; newtq->tq_entrytime = gn32TQTimer; if (bRepeat) { newtq->tq_interval=time; } else { newtq->tq_interval=0; } /* clear duplicates */ tmClearTimer(fire,pParam,n32Param,pMsg1,pMsg2,u32Msg); lock(&gLock); newtq->tq_next = NULL; tmInsertElement(newtq); unlock(&gLock); return TIMER_OK; }