14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * alarm [-r] [varname [+]when] 234887Schin * 244887Schin * David Korn 254887Schin * AT&T Labs 264887Schin * 274887Schin */ 284887Schin 294887Schin #include "defs.h" 304887Schin #include <error.h> 314887Schin #include <stak.h> 324887Schin #include "builtins.h" 334887Schin #include "FEATURE/time" 344887Schin 354887Schin #define R_FLAG 1 364887Schin #define L_FLAG 2 374887Schin 384887Schin struct tevent 394887Schin { 404887Schin Namfun_t fun; 414887Schin Namval_t *node; 424887Schin Namval_t *action; 434887Schin struct tevent *next; 444887Schin long milli; 454887Schin int flags; 464887Schin void *timeout; 474887Schin Shell_t *sh; 484887Schin }; 494887Schin 504887Schin static const char ALARM[] = "alarm"; 514887Schin 524887Schin static void trap_timeout(void*); 534887Schin 544887Schin /* 554887Schin * insert timeout item on current given list in sorted order 564887Schin */ 574887Schin static void *time_add(struct tevent *item, void *list) 584887Schin { 594887Schin register struct tevent *tp = (struct tevent*)list; 604887Schin if(!tp || item->milli < tp->milli) 614887Schin { 624887Schin item->next = tp; 634887Schin list = (void*)item; 644887Schin } 654887Schin else 664887Schin { 674887Schin while(tp->next && item->milli > tp->next->milli) 684887Schin tp = tp->next; 694887Schin item->next = tp->next; 704887Schin tp->next = item; 714887Schin } 724887Schin tp = item; 734887Schin tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp); 744887Schin return(list); 754887Schin } 764887Schin 774887Schin /* 784887Schin * delete timeout item from current given list, delete timer 794887Schin */ 804887Schin static void *time_delete(register struct tevent *item, void *list) 814887Schin { 824887Schin register struct tevent *tp = (struct tevent*)list; 834887Schin if(item==tp) 844887Schin list = (void*)tp->next; 854887Schin else 864887Schin { 874887Schin while(tp && tp->next != item) 884887Schin tp = tp->next; 894887Schin if(tp) 904887Schin tp->next = item->next; 914887Schin } 924887Schin if(item->timeout) 934887Schin timerdel((void*)item->timeout); 944887Schin return(list); 954887Schin } 964887Schin 974887Schin static void print_alarms(void *list) 984887Schin { 994887Schin register struct tevent *tp = (struct tevent*)list; 1004887Schin while(tp) 1014887Schin { 1024887Schin if(tp->timeout) 1034887Schin { 1044887Schin register char *name = nv_name(tp->node); 1054887Schin if(tp->flags&R_FLAG) 1064887Schin { 1074887Schin double d = tp->milli; 1084887Schin sfprintf(sfstdout,e_alrm1,name,d/1000.); 1094887Schin } 1104887Schin else 1114887Schin sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node)); 1124887Schin } 1134887Schin tp = tp->next; 1144887Schin } 1154887Schin } 1164887Schin 1174887Schin static void trap_timeout(void* handle) 1184887Schin { 1194887Schin register struct tevent *tp = (struct tevent*)handle; 1204887Schin tp->sh->trapnote |= SH_SIGALRM; 1214887Schin if(!(tp->flags&R_FLAG)) 1224887Schin tp->timeout = 0; 1234887Schin tp->flags |= L_FLAG; 1244887Schin tp->sh->sigflag[SIGALRM] |= SH_SIGALRM; 1254887Schin if(sh_isstate(SH_TTYWAIT)) 1264887Schin sh_timetraps(); 1274887Schin } 1284887Schin 1294887Schin void sh_timetraps(void) 1304887Schin { 1314887Schin register struct tevent *tp, *tpnext; 1324887Schin register struct tevent *tptop; 1334887Schin while(1) 1344887Schin { 1354887Schin sh.sigflag[SIGALRM] &= ~SH_SIGALRM; 1364887Schin tptop= (struct tevent*)sh.st.timetrap; 1374887Schin for(tp=tptop;tp;tp=tpnext) 1384887Schin { 1394887Schin tpnext = tp->next; 1404887Schin if(tp->flags&L_FLAG) 1414887Schin { 1424887Schin tp->flags &= ~L_FLAG; 1434887Schin if(tp->action) 1444887Schin sh_fun(tp->action,tp->node,(char**)0); 1454887Schin tp->flags &= ~L_FLAG; 1464887Schin if(!tp->flags) 1474887Schin { 1484887Schin nv_unset(tp->node); 1494887Schin nv_close(tp->node); 1504887Schin } 1514887Schin } 1524887Schin } 1534887Schin if(!(sh.sigflag[SIGALRM]&SH_SIGALRM)) 1544887Schin break; 1554887Schin } 1564887Schin } 1574887Schin 1584887Schin 1594887Schin /* 1604887Schin * This trap function catches "alarm" actions only 1614887Schin */ 1624887Schin static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t 1634887Schin *fp) 1644887Schin { 1654887Schin register struct tevent *tp = (struct tevent*)fp; 1664887Schin if(!event) 1674887Schin return(action?"":(char*)ALARM); 1684887Schin if(strcmp(event,ALARM)!=0) 1694887Schin { 1704887Schin /* try the next level */ 1714887Schin return(nv_setdisc(np, event, action, fp)); 1724887Schin } 1734887Schin if(action==np) 1744887Schin action = tp->action; 1754887Schin else 1764887Schin tp->action = action; 1774887Schin return(action?(char*)action:""); 1784887Schin } 1794887Schin 1804887Schin /* 1814887Schin * catch assignments and set alarm traps 1824887Schin */ 1834887Schin static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp) 1844887Schin { 1854887Schin register struct tevent *tp; 1864887Schin register double d; 1874887Schin if(val) 1884887Schin { 1894887Schin double now; 1904887Schin #ifdef timeofday 1914887Schin struct timeval tmp; 1924887Schin timeofday(&tmp); 1934887Schin now = tmp.tv_sec + 1.e-6*tmp.tv_usec; 1944887Schin #else 1954887Schin now = (double)time(NIL(time_t*)); 1964887Schin #endif /* timeofday */ 1974887Schin nv_putv(np,val,flag,fp); 1984887Schin d = nv_getnum(np); 1994887Schin tp = (struct tevent*)fp; 2004887Schin if(*val=='+') 2014887Schin { 2024887Schin double x = d + now; 2034887Schin nv_putv(np,(char*)&x,NV_INTEGER,fp); 2044887Schin } 2054887Schin else 2064887Schin d -= now; 2074887Schin tp->milli = 1000*(d+.0005); 2084887Schin if(tp->timeout) 2094887Schin sh.st.timetrap = time_delete(tp,sh.st.timetrap); 2104887Schin if(tp->milli > 0) 2114887Schin sh.st.timetrap = time_add(tp,sh.st.timetrap); 2124887Schin } 2134887Schin else 2144887Schin { 2154887Schin tp = (struct tevent*)nv_stack(np, (Namfun_t*)0); 2164887Schin sh.st.timetrap = time_delete(tp,sh.st.timetrap); 2174887Schin if(tp->action) 2184887Schin nv_close(tp->action); 2194887Schin nv_unset(np); 2204887Schin free((void*)fp); 2214887Schin } 2224887Schin } 2234887Schin 2244887Schin static const Namdisc_t alarmdisc = 2254887Schin { 2264887Schin sizeof(struct tevent), 2274887Schin putval, 2284887Schin 0, 2294887Schin 0, 2304887Schin setdisc, 2314887Schin }; 2324887Schin 2334887Schin int b_alarm(int argc,char *argv[],void *extra) 2344887Schin { 2354887Schin register int n,rflag=0; 2364887Schin register Namval_t *np; 2374887Schin register struct tevent *tp; 238*8462SApril.Chin@Sun.COM register Shell_t *shp = ((Shbltin_t*)extra)->shp; 2394887Schin while (n = optget(argv, sh_optalarm)) switch (n) 2404887Schin { 2414887Schin case 'r': 2424887Schin rflag = R_FLAG; 2434887Schin break; 2444887Schin case ':': 2454887Schin errormsg(SH_DICT,2, "%s", opt_info.arg); 2464887Schin break; 2474887Schin case '?': 2484887Schin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 2494887Schin break; 2504887Schin } 2514887Schin argc -= opt_info.index; 2524887Schin argv += opt_info.index; 2534887Schin if(error_info.errors) 2544887Schin errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); 2554887Schin if(argc==0) 2564887Schin { 2574887Schin print_alarms(shp->st.timetrap); 2584887Schin return(0); 2594887Schin } 2604887Schin if(argc!=2) 2614887Schin errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0)); 2624887Schin np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN); 2634887Schin if(!nv_isnull(np)) 2644887Schin nv_unset(np); 265*8462SApril.Chin@Sun.COM nv_setattr(np, NV_DOUBLE); 2664887Schin if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0))) 2674887Schin errormsg(SH_DICT,ERROR_exit(1),e_nospace); 2684887Schin tp->fun.disc = &alarmdisc; 2694887Schin tp->flags = rflag; 2704887Schin tp->node = np; 2714887Schin tp->sh = shp; 2724887Schin nv_stack(np,(Namfun_t*)tp); 2734887Schin nv_putval(np, argv[1], 0); 2744887Schin return(0); 2754887Schin } 2764887Schin 277