Home | History | Annotate | Download | only in bltins
      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 (at) 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