1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2009 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 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 */ 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 */ 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 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 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)) 126 sh_timetraps(); 127 } 128 129 void sh_timetraps(void) 130 { 131 register struct tevent *tp, *tpnext; 132 register struct tevent *tptop; 133 while(1) 134 { 135 sh.sigflag[SIGALRM] &= ~SH_SIGALRM; 136 tptop= (struct tevent*)sh.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(!(sh.sigflag[SIGALRM]&SH_SIGALRM)) 154 break; 155 } 156 } 157 158 159 /* 160 * This trap function catches "alarm" actions only 161 */ 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 */ 183 static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp) 184 { 185 register struct tevent *tp; 186 register double d; 187 if(val) 188 { 189 double now; 190 #ifdef timeofday 191 struct timeval tmp; 192 timeofday(&tmp); 193 now = tmp.tv_sec + 1.e-6*tmp.tv_usec; 194 #else 195 now = (double)time(NIL(time_t*)); 196 #endif /* timeofday */ 197 nv_putv(np,val,flag,fp); 198 d = nv_getnum(np); 199 tp = (struct tevent*)fp; 200 if(*val=='+') 201 { 202 double x = d + now; 203 nv_putv(np,(char*)&x,NV_INTEGER,fp); 204 } 205 else 206 d -= now; 207 tp->milli = 1000*(d+.0005); 208 if(tp->timeout) 209 sh.st.timetrap = time_delete(tp,sh.st.timetrap); 210 if(tp->milli > 0) 211 sh.st.timetrap = time_add(tp,sh.st.timetrap); 212 } 213 else 214 { 215 tp = (struct tevent*)nv_stack(np, (Namfun_t*)0); 216 sh.st.timetrap = time_delete(tp,sh.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 233 int 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