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