1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
/*
* $Id: alarms.c,v 1.1 2005-09-18 22:05:41 dhmunro Exp $
* alarm event functions, implemented using play interface
*/
/* Copyright (c) 2005, The Regents of the University of California.
* All rights reserved.
* This file is part of yorick (http://yorick.sourceforge.net).
* Read the accompanying LICENSE file for details.
*/
#include "config.h"
#include "play.h"
#include "pstdlib.h"
typedef struct p_alarm p_alarm;
struct p_alarm {
p_alarm *next;
double time;
void (*on_alarm)(void *c);
void *context;
};
static p_alarm *alarm_next = 0;
static p_alarm *alarm_free = 0;
static double alarm_query(void);
static int idle_eligible = 1;
static int p_dflt_idle(void);
static int (*p_app_idle)(void)= &p_dflt_idle;
void
p_idler(int (*on_idle)(void))
{
p_app_idle = on_idle;
}
static int
p_dflt_idle(void)
{
return 0;
}
void
p_on_idle(int reset)
{
if (!reset) {
if (alarm_next && !alarm_query()) {
/* alarm has rung - unlink it and call its on_alarm */
p_alarm *next = alarm_next;
alarm_next = next->next;
next->next = alarm_free;
alarm_free = next;
next->on_alarm(next->context);
idle_eligible = 1;
} else {
idle_eligible = p_app_idle();
}
} else {
idle_eligible = 1;
}
}
double
p_timeout(void)
{
int eligible = idle_eligible;
idle_eligible = 1;
return eligible? 0.0 : (alarm_next? alarm_query() : -1.0);
}
void
p_set_alarm(double secs, void (*on_alarm)(void *c), void *context)
{
p_alarm *me;
p_alarm *next = alarm_next;
p_alarm **prev = &alarm_next;
double time;
if (!alarm_free) {
int n = 8;
alarm_free = p_malloc(sizeof(p_alarm)*n);
alarm_free[--n].next = 0;
while (n--) alarm_free[n].next = &alarm_free[n+1];
}
me = alarm_free;
me->time = time = p_wall_secs() + secs;
me->on_alarm = on_alarm;
me->context = context;
/* insert me into alarm_next list, kept in order of time */
while (next && next->time<=time) {
prev = &next->next;
next = next->next;
}
alarm_free = alarm_free->next;
me->next = next;
*prev = me;
}
void
p_clr_alarm(void (*on_alarm)(void *c), void *context)
{
p_alarm *next, **prev = &alarm_next;
for (next=alarm_next ; next ; next=*prev) {
if ((!on_alarm || on_alarm==next->on_alarm) &&
(!context || context==next->context)) {
*prev = next->next;
next->next = alarm_free;
alarm_free = next;
} else {
prev = &next->next;
}
}
}
static double
alarm_query(void)
{
if (alarm_next->time != -1.e35) {
double time = p_wall_secs();
p_alarm *next = alarm_next;
/* if no alarms need to ring yet, return earliest */
if (next->time > time)
return next->time - time;
do {
next->time = -1.e35; /* mark all alarms that need to ring */
next = next->next;
} while (next && next->time<=time);
}
return 0.0;
}
|