--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (c) 2002 Cray Inc.
+ * Copyright (c) 2002 Eric Hoffman
+ *
+ * This file is part of Portals, http://www.sf.net/projects/sandiaportals/
+ *
+ * Portals is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General
+ * Public License as published by the Free Software Foundation.
+ *
+ * Portals 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Portals; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* timer.c:
+ * this file implements a simple priority-queue based timer system. when
+ * combined with a file which implements now() and block(), it can
+ * be used to provide course-grained time-based callbacks.
+ */
+
+#include <pqtimer.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct timer {
+ void (*function)(void *);
+ void *arg;
+ when w;
+ int interval;
+ int disable;
+};
+
+typedef struct thunk *thunk;
+struct thunk {
+ void (*f)(void *);
+ void *a;
+ thunk next;
+};
+
+extern when now(void);
+
+static thunk thunks;
+static int internal;
+static void (*block_function)(when);
+static int number_of_timers;
+static int size_of_pqueue;
+static timer *timers;
+
+
+static void heal(int where)
+{
+ int left=(where<<1);
+ int right=(where<<1)+1;
+ int min=where;
+ timer temp;
+
+ if (left <= number_of_timers)
+ if (timers[left]->w < timers[min]->w) min=left;
+ if (right <= number_of_timers)
+ if (timers[right]->w < timers[min]->w) min=right;
+ if (min != where){
+ temp=timers[where];
+ timers[where]=timers[min];
+ timers[min]=temp;
+ heal(min);
+ }
+}
+
+static void add_pqueue(int i)
+{
+ timer temp;
+ int parent=(i>>1);
+ if ((i>1) && (timers[i]->w< timers[parent]->w)){
+ temp=timers[i];
+ timers[i]=timers[parent];
+ timers[parent]=temp;
+ add_pqueue(parent);
+ }
+}
+
+static void add_timer(timer t)
+{
+ if (size_of_pqueue<(number_of_timers+2)){
+ int oldsize=size_of_pqueue;
+ timer *new=(void *)malloc(sizeof(struct timer)*(size_of_pqueue+=10));
+ memcpy(new,timers,sizeof(timer)*oldsize);
+ timers=new;
+ }
+ timers[++number_of_timers]=t;
+ add_pqueue(number_of_timers);
+}
+
+/* Function: register_timer
+ * Arguments: interval: the time interval from the current time when
+ * the timer function should be called
+ * function: the function to call when the time has expired
+ * argument: the argument to call it with.
+ * Returns: a pointer to a timer structure
+ */
+timer register_timer(when interval,
+ void (*function)(void *),
+ void *argument)
+{
+ timer t=(timer)malloc(sizeof(struct timer));
+
+ t->arg=argument;
+ t->function=function;
+ t->interval=interval;
+ t->disable=0;
+ t->w=now()+interval;
+ add_timer(t);
+ if (!internal && (number_of_timers==1))
+ block_function(t->w);
+ return(t);
+}
+
+/* Function: remove_timer
+ * Arguments: t:
+ * Returns: nothing
+ *
+ * remove_timer removes a timer from the system, insuring
+ * that it will never be called. It does not actually
+ * free the timer due to reentrancy issues.
+ */
+
+void remove_timer(timer t)
+{
+ t->disable=1;
+}
+
+
+
+void timer_fire()
+{
+ timer current;
+
+ current=timers[1];
+ timers[1]=timers[number_of_timers--];
+ heal(1);
+ if (!current->disable) {
+ (*current->function)(current->arg);
+ }
+ free(current);
+}
+
+when next_timer(void)
+{
+ when here=now();
+
+ while (number_of_timers && (timers[1]->w <= here)) timer_fire();
+ if (number_of_timers) return(timers[1]->w);
+ return(0);
+}
+
+/* Function: timer_loop
+ * Arguments: none
+ * Returns: never
+ *
+ * timer_loop() is the blocking dispatch function for the timer.
+ * Is calls the block() function registered with init_timer,
+ * and handles associated with timers that have been registered.
+ */
+void timer_loop()
+{
+ when here;
+
+ while (1){
+ thunk z;
+ here=now();
+
+ for (z=thunks;z;z=z->next) (*z->f)(z->a);
+
+ if (number_of_timers){
+ if (timers[1]->w > here){
+ (*block_function)(timers[1]->w);
+ } else {
+ timer_fire();
+ }
+ } else {
+ thunk z;
+ for (z=thunks;z;z=z->next) (*z->f)(z->a);
+ (*block_function)(0);
+ }
+ }
+}
+
+
+/* Function: register_thunk
+ * Arguments: f: the function to call
+ * a: the single argument to call it with
+ *
+ * Thunk functions get called at irregular intervals, they
+ * should not assume when, or take a particularily long
+ * amount of time. Thunks are for background cleanup tasks.
+ */
+void register_thunk(void (*f)(void *),void *a)
+{
+ thunk t=(void *)malloc(sizeof(struct thunk));
+ t->f=f;
+ t->a=a;
+ t->next=thunks;
+ thunks=t;
+}
+
+/* Function: initialize_timer
+ * Arguments: block: the function to call to block for the specified interval
+ *
+ * initialize_timer() must be called before any other timer function,
+ * including timer_loop.
+ */
+void initialize_timer(void (*block)(when))
+{
+ block_function=block;
+ number_of_timers=0;
+ size_of_pqueue=10;
+ timers=(timer *)malloc(sizeof(timer)*size_of_pqueue);
+ thunks=0;
+}