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 * alarm [-r] [varname [+]when]
23da2e3ebdSchin *
24da2e3ebdSchin * David Korn
25da2e3ebdSchin * AT&T Labs
26da2e3ebdSchin *
27da2e3ebdSchin */
28da2e3ebdSchin
29da2e3ebdSchin #include "defs.h"
30da2e3ebdSchin #include <error.h>
31da2e3ebdSchin #include <stak.h>
32da2e3ebdSchin #include "builtins.h"
33da2e3ebdSchin #include "FEATURE/time"
34da2e3ebdSchin
35da2e3ebdSchin #define R_FLAG 1
36da2e3ebdSchin #define L_FLAG 2
37da2e3ebdSchin
38da2e3ebdSchin struct tevent
39da2e3ebdSchin {
40da2e3ebdSchin Namfun_t fun;
41da2e3ebdSchin Namval_t *node;
42da2e3ebdSchin Namval_t *action;
43da2e3ebdSchin struct tevent *next;
44da2e3ebdSchin long milli;
45da2e3ebdSchin int flags;
46da2e3ebdSchin void *timeout;
47da2e3ebdSchin Shell_t *sh;
48da2e3ebdSchin };
49da2e3ebdSchin
50da2e3ebdSchin static const char ALARM[] = "alarm";
51da2e3ebdSchin
52da2e3ebdSchin static void trap_timeout(void*);
53da2e3ebdSchin
54da2e3ebdSchin /*
55da2e3ebdSchin * insert timeout item on current given list in sorted order
56da2e3ebdSchin */
time_add(struct tevent * item,void * list)57da2e3ebdSchin static void *time_add(struct tevent *item, void *list)
58da2e3ebdSchin {
59da2e3ebdSchin register struct tevent *tp = (struct tevent*)list;
60da2e3ebdSchin if(!tp || item->milli < tp->milli)
61da2e3ebdSchin {
62da2e3ebdSchin item->next = tp;
63da2e3ebdSchin list = (void*)item;
64da2e3ebdSchin }
65da2e3ebdSchin else
66da2e3ebdSchin {
67da2e3ebdSchin while(tp->next && item->milli > tp->next->milli)
68da2e3ebdSchin tp = tp->next;
69da2e3ebdSchin item->next = tp->next;
70da2e3ebdSchin tp->next = item;
71da2e3ebdSchin }
72da2e3ebdSchin tp = item;
73da2e3ebdSchin tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp);
74da2e3ebdSchin return(list);
75da2e3ebdSchin }
76da2e3ebdSchin
77da2e3ebdSchin /*
78da2e3ebdSchin * delete timeout item from current given list, delete timer
79da2e3ebdSchin */
time_delete(register struct tevent * item,void * list)80da2e3ebdSchin static void *time_delete(register struct tevent *item, void *list)
81da2e3ebdSchin {
82da2e3ebdSchin register struct tevent *tp = (struct tevent*)list;
83da2e3ebdSchin if(item==tp)
84da2e3ebdSchin list = (void*)tp->next;
85da2e3ebdSchin else
86da2e3ebdSchin {
87da2e3ebdSchin while(tp && tp->next != item)
88da2e3ebdSchin tp = tp->next;
89da2e3ebdSchin if(tp)
90da2e3ebdSchin tp->next = item->next;
91da2e3ebdSchin }
92da2e3ebdSchin if(item->timeout)
93da2e3ebdSchin timerdel((void*)item->timeout);
94da2e3ebdSchin return(list);
95da2e3ebdSchin }
96da2e3ebdSchin
print_alarms(void * list)97da2e3ebdSchin static void print_alarms(void *list)
98da2e3ebdSchin {
99da2e3ebdSchin register struct tevent *tp = (struct tevent*)list;
100da2e3ebdSchin while(tp)
101da2e3ebdSchin {
102da2e3ebdSchin if(tp->timeout)
103da2e3ebdSchin {
104da2e3ebdSchin register char *name = nv_name(tp->node);
105da2e3ebdSchin if(tp->flags&R_FLAG)
106da2e3ebdSchin {
107da2e3ebdSchin double d = tp->milli;
108da2e3ebdSchin sfprintf(sfstdout,e_alrm1,name,d/1000.);
109da2e3ebdSchin }
110da2e3ebdSchin else
111da2e3ebdSchin sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node));
112da2e3ebdSchin }
113da2e3ebdSchin tp = tp->next;
114da2e3ebdSchin }
115da2e3ebdSchin }
116da2e3ebdSchin
trap_timeout(void * handle)117da2e3ebdSchin static void trap_timeout(void* handle)
118da2e3ebdSchin {
119da2e3ebdSchin register struct tevent *tp = (struct tevent*)handle;
120da2e3ebdSchin tp->sh->trapnote |= SH_SIGALRM;
121da2e3ebdSchin if(!(tp->flags&R_FLAG))
122da2e3ebdSchin tp->timeout = 0;
123da2e3ebdSchin tp->flags |= L_FLAG;
124da2e3ebdSchin tp->sh->sigflag[SIGALRM] |= SH_SIGALRM;
125da2e3ebdSchin if(sh_isstate(SH_TTYWAIT))
126da2e3ebdSchin sh_timetraps();
127da2e3ebdSchin }
128da2e3ebdSchin
sh_timetraps(void)129da2e3ebdSchin void sh_timetraps(void)
130da2e3ebdSchin {
131da2e3ebdSchin register struct tevent *tp, *tpnext;
132da2e3ebdSchin register struct tevent *tptop;
133da2e3ebdSchin while(1)
134da2e3ebdSchin {
135da2e3ebdSchin sh.sigflag[SIGALRM] &= ~SH_SIGALRM;
136da2e3ebdSchin tptop= (struct tevent*)sh.st.timetrap;
137da2e3ebdSchin for(tp=tptop;tp;tp=tpnext)
138da2e3ebdSchin {
139da2e3ebdSchin tpnext = tp->next;
140da2e3ebdSchin if(tp->flags&L_FLAG)
141da2e3ebdSchin {
142da2e3ebdSchin tp->flags &= ~L_FLAG;
143da2e3ebdSchin if(tp->action)
144da2e3ebdSchin sh_fun(tp->action,tp->node,(char**)0);
145da2e3ebdSchin tp->flags &= ~L_FLAG;
146da2e3ebdSchin if(!tp->flags)
147da2e3ebdSchin {
148da2e3ebdSchin nv_unset(tp->node);
149da2e3ebdSchin nv_close(tp->node);
150da2e3ebdSchin }
151da2e3ebdSchin }
152da2e3ebdSchin }
153da2e3ebdSchin if(!(sh.sigflag[SIGALRM]&SH_SIGALRM))
154da2e3ebdSchin break;
155da2e3ebdSchin }
156da2e3ebdSchin }
157da2e3ebdSchin
158da2e3ebdSchin
159da2e3ebdSchin /*
160da2e3ebdSchin * This trap function catches "alarm" actions only
161da2e3ebdSchin */
setdisc(Namval_t * np,const char * event,Namval_t * action,Namfun_t * fp)162da2e3ebdSchin static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t
163da2e3ebdSchin *fp)
164da2e3ebdSchin {
165da2e3ebdSchin register struct tevent *tp = (struct tevent*)fp;
166da2e3ebdSchin if(!event)
167da2e3ebdSchin return(action?"":(char*)ALARM);
168da2e3ebdSchin if(strcmp(event,ALARM)!=0)
169da2e3ebdSchin {
170da2e3ebdSchin /* try the next level */
171da2e3ebdSchin return(nv_setdisc(np, event, action, fp));
172da2e3ebdSchin }
173da2e3ebdSchin if(action==np)
174da2e3ebdSchin action = tp->action;
175da2e3ebdSchin else
176da2e3ebdSchin tp->action = action;
177da2e3ebdSchin return(action?(char*)action:"");
178da2e3ebdSchin }
179da2e3ebdSchin
180da2e3ebdSchin /*
181da2e3ebdSchin * catch assignments and set alarm traps
182da2e3ebdSchin */
putval(Namval_t * np,const char * val,int flag,Namfun_t * fp)183da2e3ebdSchin static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
184da2e3ebdSchin {
185da2e3ebdSchin register struct tevent *tp;
186da2e3ebdSchin register double d;
187da2e3ebdSchin if(val)
188da2e3ebdSchin {
189da2e3ebdSchin double now;
190da2e3ebdSchin #ifdef timeofday
191da2e3ebdSchin struct timeval tmp;
192da2e3ebdSchin timeofday(&tmp);
193da2e3ebdSchin now = tmp.tv_sec + 1.e-6*tmp.tv_usec;
194da2e3ebdSchin #else
195da2e3ebdSchin now = (double)time(NIL(time_t*));
196da2e3ebdSchin #endif /* timeofday */
197da2e3ebdSchin nv_putv(np,val,flag,fp);
198da2e3ebdSchin d = nv_getnum(np);
199da2e3ebdSchin tp = (struct tevent*)fp;
200da2e3ebdSchin if(*val=='+')
201da2e3ebdSchin {
202da2e3ebdSchin double x = d + now;
203da2e3ebdSchin nv_putv(np,(char*)&x,NV_INTEGER,fp);
204da2e3ebdSchin }
205da2e3ebdSchin else
206da2e3ebdSchin d -= now;
207da2e3ebdSchin tp->milli = 1000*(d+.0005);
208da2e3ebdSchin if(tp->timeout)
209da2e3ebdSchin sh.st.timetrap = time_delete(tp,sh.st.timetrap);
210da2e3ebdSchin if(tp->milli > 0)
211da2e3ebdSchin sh.st.timetrap = time_add(tp,sh.st.timetrap);
212da2e3ebdSchin }
213da2e3ebdSchin else
214da2e3ebdSchin {
215da2e3ebdSchin tp = (struct tevent*)nv_stack(np, (Namfun_t*)0);
216da2e3ebdSchin sh.st.timetrap = time_delete(tp,sh.st.timetrap);
217da2e3ebdSchin if(tp->action)
218da2e3ebdSchin nv_close(tp->action);
219da2e3ebdSchin nv_unset(np);
220da2e3ebdSchin free((void*)fp);
221da2e3ebdSchin }
222da2e3ebdSchin }
223da2e3ebdSchin
224da2e3ebdSchin static const Namdisc_t alarmdisc =
225da2e3ebdSchin {
226da2e3ebdSchin sizeof(struct tevent),
227da2e3ebdSchin putval,
228da2e3ebdSchin 0,
229da2e3ebdSchin 0,
230da2e3ebdSchin setdisc,
231da2e3ebdSchin };
232da2e3ebdSchin
b_alarm(int argc,char * argv[],void * extra)233da2e3ebdSchin int b_alarm(int argc,char *argv[],void *extra)
234da2e3ebdSchin {
235da2e3ebdSchin register int n,rflag=0;
236da2e3ebdSchin register Namval_t *np;
237da2e3ebdSchin register struct tevent *tp;
2387c2fbfb3SApril Chin register Shell_t *shp = ((Shbltin_t*)extra)->shp;
239da2e3ebdSchin while (n = optget(argv, sh_optalarm)) switch (n)
240da2e3ebdSchin {
241da2e3ebdSchin case 'r':
242da2e3ebdSchin rflag = R_FLAG;
243da2e3ebdSchin break;
244da2e3ebdSchin case ':':
245da2e3ebdSchin errormsg(SH_DICT,2, "%s", opt_info.arg);
246da2e3ebdSchin break;
247da2e3ebdSchin case '?':
248da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
249da2e3ebdSchin break;
250da2e3ebdSchin }
251da2e3ebdSchin argc -= opt_info.index;
252da2e3ebdSchin argv += opt_info.index;
253da2e3ebdSchin if(error_info.errors)
254da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
255da2e3ebdSchin if(argc==0)
256da2e3ebdSchin {
257da2e3ebdSchin print_alarms(shp->st.timetrap);
258da2e3ebdSchin return(0);
259da2e3ebdSchin }
260da2e3ebdSchin if(argc!=2)
261da2e3ebdSchin errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
262da2e3ebdSchin np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN);
263da2e3ebdSchin if(!nv_isnull(np))
264da2e3ebdSchin nv_unset(np);
2657c2fbfb3SApril Chin nv_setattr(np, NV_DOUBLE);
266da2e3ebdSchin if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0)))
267da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_nospace);
268da2e3ebdSchin tp->fun.disc = &alarmdisc;
269da2e3ebdSchin tp->flags = rflag;
270da2e3ebdSchin tp->node = np;
271da2e3ebdSchin tp->sh = shp;
272da2e3ebdSchin nv_stack(np,(Namfun_t*)tp);
273da2e3ebdSchin nv_putval(np, argv[1], 0);
274da2e3ebdSchin return(0);
275da2e3ebdSchin }
276da2e3ebdSchin
277