1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin
22da2e3ebdSchin #include <ast.h>
23da2e3ebdSchin #include <sig.h>
24da2e3ebdSchin #include <error.h>
25da2e3ebdSchin #include "fault.h"
26da2e3ebdSchin #include "defs.h"
27da2e3ebdSchin #include "FEATURE/sigfeatures"
28da2e3ebdSchin #include "FEATURE/time"
29da2e3ebdSchin
30da2e3ebdSchin typedef struct _timer
31da2e3ebdSchin {
32da2e3ebdSchin double wakeup;
33da2e3ebdSchin double incr;
34da2e3ebdSchin struct _timer *next;
35da2e3ebdSchin void (*action)(void*);
36da2e3ebdSchin void *handle;
37da2e3ebdSchin } Timer_t;
38da2e3ebdSchin
39da2e3ebdSchin #define IN_ADDTIMEOUT 1
40da2e3ebdSchin #define IN_SIGALRM 2
41da2e3ebdSchin #define DEFER_SIGALRM 4
42da2e3ebdSchin #define SIGALRM_CALL 8
43da2e3ebdSchin
44da2e3ebdSchin static Timer_t *tptop, *tpmin, *tpfree;
45da2e3ebdSchin static char time_state;
46da2e3ebdSchin
getnow(void)47da2e3ebdSchin static double getnow(void)
48da2e3ebdSchin {
49da2e3ebdSchin register double now;
50da2e3ebdSchin #ifdef timeofday
51da2e3ebdSchin struct timeval tp;
52da2e3ebdSchin timeofday(&tp);
53da2e3ebdSchin now = tp.tv_sec + 1.e-6*tp.tv_usec;
54da2e3ebdSchin
55da2e3ebdSchin #else
56da2e3ebdSchin now = (double)time((time_t*)0);
57da2e3ebdSchin #endif /* timeofday */
58da2e3ebdSchin return(now+.001);
59da2e3ebdSchin }
60da2e3ebdSchin
61da2e3ebdSchin /*
62da2e3ebdSchin * set an alarm for <t> seconds
63da2e3ebdSchin */
setalarm(register double t)64da2e3ebdSchin static double setalarm(register double t)
65da2e3ebdSchin {
66da2e3ebdSchin #if defined(_lib_setitimer) && defined(ITIMER_REAL)
67da2e3ebdSchin struct itimerval tnew, told;
68da2e3ebdSchin tnew.it_value.tv_sec = t;
69da2e3ebdSchin tnew.it_value.tv_usec = 1.e6*(t- (double)tnew.it_value.tv_sec);
70da2e3ebdSchin if(t && tnew.it_value.tv_sec==0 && tnew.it_value.tv_usec<1000)
71da2e3ebdSchin tnew.it_value.tv_usec = 1000;
72da2e3ebdSchin tnew.it_interval.tv_sec = 0;
73da2e3ebdSchin tnew.it_interval.tv_usec = 0;
74da2e3ebdSchin if(setitimer(ITIMER_REAL,&tnew,&told) < 0)
75da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_alarm);
76da2e3ebdSchin t = told.it_value.tv_sec + 1.e-6*told.it_value.tv_usec;
77da2e3ebdSchin #else
78da2e3ebdSchin unsigned seconds = (unsigned)t;
79da2e3ebdSchin if(t && seconds<1)
80da2e3ebdSchin seconds=1;
81da2e3ebdSchin t = (double)alarm(seconds);
82da2e3ebdSchin #endif
83da2e3ebdSchin return(t);
84da2e3ebdSchin }
85da2e3ebdSchin
86da2e3ebdSchin /* signal handler for alarm call */
sigalrm(int sig)87da2e3ebdSchin static void sigalrm(int sig)
88da2e3ebdSchin {
89da2e3ebdSchin register Timer_t *tp, *tplast, *tpold, *tpnext;
90da2e3ebdSchin double now;
91da2e3ebdSchin static double left;
92da2e3ebdSchin NOT_USED(sig);
93da2e3ebdSchin left = 0;
94da2e3ebdSchin if(time_state&SIGALRM_CALL)
95da2e3ebdSchin time_state &= ~SIGALRM_CALL;
96da2e3ebdSchin else if(alarm(0))
97da2e3ebdSchin sh_fault(SIGALRM|SH_TRAP);
98da2e3ebdSchin if(time_state)
99da2e3ebdSchin {
100da2e3ebdSchin if(time_state&IN_ADDTIMEOUT)
101da2e3ebdSchin time_state |= DEFER_SIGALRM;
102da2e3ebdSchin errno = EINTR;
103da2e3ebdSchin return;
104da2e3ebdSchin }
105da2e3ebdSchin time_state |= IN_SIGALRM;
106da2e3ebdSchin sigrelease(SIGALRM);
107da2e3ebdSchin while(1)
108da2e3ebdSchin {
109da2e3ebdSchin now = getnow();
110da2e3ebdSchin tpold = tpmin = 0;
111da2e3ebdSchin for(tplast=0,tp=tptop; tp; tp=tpnext)
112da2e3ebdSchin {
113da2e3ebdSchin tpnext = tp->next;
114da2e3ebdSchin if(tp->action)
115da2e3ebdSchin {
116da2e3ebdSchin if(tp->wakeup <=now)
117da2e3ebdSchin {
118da2e3ebdSchin if(!tpold || tpold->wakeup>tp->wakeup)
119da2e3ebdSchin tpold = tp;
120da2e3ebdSchin }
121da2e3ebdSchin else
122da2e3ebdSchin {
123da2e3ebdSchin if(!tpmin || tpmin->wakeup>tp->wakeup)
124da2e3ebdSchin tpmin=tp;
125da2e3ebdSchin }
126da2e3ebdSchin tplast = tp;
127da2e3ebdSchin }
128da2e3ebdSchin else
129da2e3ebdSchin {
130da2e3ebdSchin if(tplast)
131da2e3ebdSchin tplast->next = tp->next;
132da2e3ebdSchin else
133da2e3ebdSchin tptop = tp->next;
134da2e3ebdSchin tp->next = tpfree;
135da2e3ebdSchin tpfree = tp;
136da2e3ebdSchin }
137da2e3ebdSchin }
138da2e3ebdSchin if((tp=tpold) && tp->incr)
139da2e3ebdSchin {
140da2e3ebdSchin while((tp->wakeup += tp->incr) <= now);
141da2e3ebdSchin if(!tpmin || tpmin->wakeup>tp->wakeup)
142da2e3ebdSchin tpmin=tp;
143da2e3ebdSchin }
144da2e3ebdSchin if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left))))
145da2e3ebdSchin {
146da2e3ebdSchin if(left==0)
147da2e3ebdSchin signal(SIGALRM,sigalrm);
148da2e3ebdSchin left = setalarm(tpmin->wakeup-now);
149da2e3ebdSchin if(left && (now+left) < tpmin->wakeup)
150da2e3ebdSchin setalarm(left);
151da2e3ebdSchin else
152da2e3ebdSchin left=tpmin->wakeup-now;
153da2e3ebdSchin }
154da2e3ebdSchin if(tp)
155da2e3ebdSchin {
156da2e3ebdSchin void (*action)(void*);
157da2e3ebdSchin action = tp->action;
158da2e3ebdSchin if(!tp->incr)
159da2e3ebdSchin tp->action = 0;
160da2e3ebdSchin errno = EINTR;
161da2e3ebdSchin time_state &= ~IN_SIGALRM;
162da2e3ebdSchin (*action)(tp->handle);
163da2e3ebdSchin time_state |= IN_SIGALRM;
164da2e3ebdSchin }
165da2e3ebdSchin else
166da2e3ebdSchin break;
167da2e3ebdSchin }
168da2e3ebdSchin if(!tpmin)
169da2e3ebdSchin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
170da2e3ebdSchin time_state &= ~IN_SIGALRM;
171da2e3ebdSchin errno = EINTR;
172da2e3ebdSchin }
173da2e3ebdSchin
oldalrm(void * handle)174da2e3ebdSchin static void oldalrm(void *handle)
175da2e3ebdSchin {
176da2e3ebdSchin Handler_t fn = *(Handler_t*)handle;
177da2e3ebdSchin free(handle);
178da2e3ebdSchin (*fn)(SIGALRM);
179da2e3ebdSchin }
180da2e3ebdSchin
sh_timeradd(unsigned long msec,int flags,void (* action)(void *),void * handle)181da2e3ebdSchin void *sh_timeradd(unsigned long msec,int flags,void (*action)(void*),void *handle)
182da2e3ebdSchin {
183da2e3ebdSchin register Timer_t *tp;
184da2e3ebdSchin double t;
185da2e3ebdSchin Handler_t fn;
186da2e3ebdSchin t = ((double)msec)/1000.;
187da2e3ebdSchin if(t<=0 || !action)
188da2e3ebdSchin return((void*)0);
189da2e3ebdSchin if(tp=tpfree)
190da2e3ebdSchin tpfree = tp->next;
191da2e3ebdSchin else if(!(tp=(Timer_t*)malloc(sizeof(Timer_t))))
192da2e3ebdSchin return((void*)0);
193da2e3ebdSchin tp->wakeup = getnow() + t;
194da2e3ebdSchin tp->incr = (flags?t:0);
195da2e3ebdSchin tp->action = action;
196da2e3ebdSchin tp->handle = handle;
197da2e3ebdSchin time_state |= IN_ADDTIMEOUT;
198da2e3ebdSchin tp->next = tptop;
199da2e3ebdSchin tptop = tp;
200da2e3ebdSchin if(!tpmin || tp->wakeup < tpmin->wakeup)
201da2e3ebdSchin {
202da2e3ebdSchin tpmin = tp;
203da2e3ebdSchin fn = (Handler_t)signal(SIGALRM,sigalrm);
204da2e3ebdSchin if((t= setalarm(t))>0 && fn && fn!=(Handler_t)sigalrm)
205da2e3ebdSchin {
206da2e3ebdSchin Handler_t *hp = (Handler_t*)malloc(sizeof(Handler_t));
207da2e3ebdSchin if(hp)
208da2e3ebdSchin {
209da2e3ebdSchin *hp = fn;
210da2e3ebdSchin sh_timeradd((long)(1000*t), 0, oldalrm, (void*)hp);
211da2e3ebdSchin }
212da2e3ebdSchin }
213da2e3ebdSchin tp = tptop;
214da2e3ebdSchin }
215da2e3ebdSchin else if(tpmin && !tpmin->action)
216da2e3ebdSchin time_state |= DEFER_SIGALRM;
217da2e3ebdSchin time_state &= ~IN_ADDTIMEOUT;
218da2e3ebdSchin if(time_state&DEFER_SIGALRM)
219da2e3ebdSchin {
220da2e3ebdSchin time_state=SIGALRM_CALL;
221da2e3ebdSchin sigalrm(SIGALRM);
222da2e3ebdSchin if(tp!=tptop)
223da2e3ebdSchin tp=0;
224da2e3ebdSchin }
225da2e3ebdSchin return((void*)tp);
226da2e3ebdSchin }
227da2e3ebdSchin
228da2e3ebdSchin /*
229da2e3ebdSchin * delete timer <tp>. If <tp> is NULL, all timers are deleted
230da2e3ebdSchin */
timerdel(void * handle)231da2e3ebdSchin void timerdel(void *handle)
232da2e3ebdSchin {
233da2e3ebdSchin register Timer_t *tp = (Timer_t*)handle;
234da2e3ebdSchin if(tp)
235da2e3ebdSchin tp->action = 0;
236da2e3ebdSchin else
237da2e3ebdSchin {
238da2e3ebdSchin for(tp=tptop; tp; tp=tp->next)
239da2e3ebdSchin tp->action = 0;
240da2e3ebdSchin if(tpmin)
241da2e3ebdSchin {
242da2e3ebdSchin tpmin = 0;
243da2e3ebdSchin setalarm((double)0);
244da2e3ebdSchin }
245da2e3ebdSchin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL);
246da2e3ebdSchin }
247da2e3ebdSchin }
248da2e3ebdSchin
249