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