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