/* Copyright 1996 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Title: alarm.c * Purpose: alarm facilities for wimp programs, using non-busy waiting * for idle events * Author: IDJ * Status: under development * History: 20-Mar-89 IDJ created * 21-Mar-89 IDJ modified kludge to alarm_timedifference * 21-Mar-89 IDJ added alarm__laterthan macro * 08-May-91 ECN #ifndefed out unused ROM functions * 09-May-91 ECN use swi names instead of nos. * 14-Jun-91 IDJ timedifference put back in */ #include <stdlib.h> #include <limits.h> #include "alarm.h" #include "werr.h" #include "os.h" #include "msgs.h" #include "swis.h" #include "h.verintern.messages" #define alarm__laterthan(t1,t2) (t1 > t2) typedef struct alarm__str { struct alarm__str *next; int at; alarm_handler proc; void *handle; } ALARM; /* the list of pending alarms */ static ALARM *alarm__pending_list = 0; void alarm_init(void) { ALARM *p, *save_p; if (alarm__pending_list != 0) { p = alarm__pending_list; while (p != 0) { save_p = p; p = p->next; free(save_p); } alarm__pending_list = 0; } } int alarm_timenow(void) { os_regset r; os_error *e; if ((e = os_swix(OS_ReadMonotonicTime, &r)) != 0) { werr (TRUE, msgs_lookup(MSGS_alarm1)); return 0; /* compiler likes this !*/ } else return (r.r[0]); } int alarm_timedifference(int t1, int t2) { /* * wrap-round of timer is not really a problem * we could just do a subtraction (since large_-ve - large_+ve == small+ve * but this kludge makes doubly sure (I think) */ if (t1>0 && t2<0) { t1 |= 0x80000000; /* ie. neg distance from 0 */ t2 &= ~0x80000000; /* ie. pos distance from 0 */ } return(t2 -t1); } void alarm_set(int at, alarm_handler proc, void *handle) { ALARM *p, *save_p, *new; p = alarm__pending_list; save_p = p; /* find where to put the alarm (in time) */ while (p!=0 && alarm__laterthan(at, p->at)) { #ifdef TRACE tracef1("at = %d\n", (int)(p->handle)); #endif save_p = p; p = p->next; } /* insert new pending alarm */ if((new = malloc(sizeof(ALARM)))==0) werr(TRUE, msgs_lookup(MSGS_alarm2)); new->next = p; new->proc = proc; new->handle = handle; new->at = at; if(save_p == p) alarm__pending_list = new; else save_p->next = new; } BOOL alarm_next(int *result) { if (alarm__pending_list != 0) { /* if there's a pending alarm say when it's for */ *result = alarm__pending_list->at; return TRUE; } else return FALSE; } void alarm_callnext(void) { ALARM *next_alarm; alarm_handler proc_to_call; int called_at; void *handle_to_pass; if (alarm__pending_list != 0) { /* save details of next alarm */ proc_to_call = alarm__pending_list->proc; called_at = alarm__pending_list->at; handle_to_pass = alarm__pending_list->handle; /* farewell and adieu to the next pending alarm */ next_alarm = alarm__pending_list; alarm__pending_list = alarm__pending_list->next; free(next_alarm); /* call supplied routine last (in case it goes bang!) */ proc_to_call(called_at, handle_to_pass); } } #ifndef UROM void alarm_remove(int at, void *handle) { ALARM *p, *save_p; p = alarm__pending_list; save_p = p; while(p != 0) { if(p->at == at && p->handle == handle) break; else { save_p = p; p = p->next; } } if(p != 0) { if(save_p == p) alarm__pending_list = p->next; else save_p->next = p->next; free(p); } } #endif void alarm_removeall(void *handle) { ALARM *p, *save_p; p = alarm__pending_list; save_p = p; while(p != 0) if(p->handle == handle) { if(save_p == p) { alarm__pending_list = p->next; p = alarm__pending_list; free(save_p); save_p = p; } else { save_p->next = p->next; free(p); p = save_p->next; } } else { save_p = p; p = p->next; } } BOOL alarm_anypending(void *handle) { ALARM *p = alarm__pending_list; while(p != 0) { if(p->handle == handle) return TRUE; p = p->next; } return FALSE; }