1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2011 AT&T Intellectual Property * 5* and is licensed under the * 6* Common Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.opensource.org/licenses/cpl1.0.txt * 11* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 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 38struct 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 50static const char ALARM[] = "alarm"; 51 52static void trap_timeout(void*); 53 54/* 55 * insert timeout item on current given list in sorted order 56 */ 57static 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 */ 80static 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 97static 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 117static 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)) 126 sh_timetraps(tp->sh); 127} 128 129void 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 */ 162static 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 */ 183static 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 224static const Namdisc_t alarmdisc = 225{ 226 sizeof(struct tevent), 227 putval, 228 0, 229 0, 230 setdisc, 231}; 232 233int b_alarm(int argc,char *argv[],void *extra) 234{ 235 register int n,rflag=0; 236 register Namval_t *np; 237 register struct tevent *tp; 238 register Shell_t *shp = ((Shbltin_t*)extra)->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