summaryrefslogtreecommitdiff
path: root/src/cmd/ksh93/bltins/alarm.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/cmd/ksh93/bltins/alarm.c
downloadksh-upstream.tar.gz
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/cmd/ksh93/bltins/alarm.c')
-rw-r--r--src/cmd/ksh93/bltins/alarm.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/cmd/ksh93/bltins/alarm.c b/src/cmd/ksh93/bltins/alarm.c
new file mode 100644
index 0000000..50261c6
--- /dev/null
+++ b/src/cmd/ksh93/bltins/alarm.c
@@ -0,0 +1,276 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * alarm [-r] [varname [+]when]
+ *
+ * David Korn
+ * AT&T Labs
+ *
+ */
+
+#include "defs.h"
+#include <error.h>
+#include <stak.h>
+#include "builtins.h"
+#include "FEATURE/time"
+
+#define R_FLAG 1
+#define L_FLAG 2
+
+struct tevent
+{
+ Namfun_t fun;
+ Namval_t *node;
+ Namval_t *action;
+ struct tevent *next;
+ long milli;
+ int flags;
+ void *timeout;
+ Shell_t *sh;
+};
+
+static const char ALARM[] = "alarm";
+
+static void trap_timeout(void*);
+
+/*
+ * insert timeout item on current given list in sorted order
+ */
+static void *time_add(struct tevent *item, void *list)
+{
+ register struct tevent *tp = (struct tevent*)list;
+ if(!tp || item->milli < tp->milli)
+ {
+ item->next = tp;
+ list = (void*)item;
+ }
+ else
+ {
+ while(tp->next && item->milli > tp->next->milli)
+ tp = tp->next;
+ item->next = tp->next;
+ tp->next = item;
+ }
+ tp = item;
+ tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp);
+ return(list);
+}
+
+/*
+ * delete timeout item from current given list, delete timer
+ */
+static void *time_delete(register struct tevent *item, void *list)
+{
+ register struct tevent *tp = (struct tevent*)list;
+ if(item==tp)
+ list = (void*)tp->next;
+ else
+ {
+ while(tp && tp->next != item)
+ tp = tp->next;
+ if(tp)
+ tp->next = item->next;
+ }
+ if(item->timeout)
+ timerdel((void*)item->timeout);
+ return(list);
+}
+
+static void print_alarms(void *list)
+{
+ register struct tevent *tp = (struct tevent*)list;
+ while(tp)
+ {
+ if(tp->timeout)
+ {
+ register char *name = nv_name(tp->node);
+ if(tp->flags&R_FLAG)
+ {
+ double d = tp->milli;
+ sfprintf(sfstdout,e_alrm1,name,d/1000.);
+ }
+ else
+ sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node));
+ }
+ tp = tp->next;
+ }
+}
+
+static void trap_timeout(void* handle)
+{
+ register struct tevent *tp = (struct tevent*)handle;
+ tp->sh->trapnote |= SH_SIGALRM;
+ if(!(tp->flags&R_FLAG))
+ tp->timeout = 0;
+ tp->flags |= L_FLAG;
+ tp->sh->sigflag[SIGALRM] |= SH_SIGALRM;
+ if(sh_isstate(SH_TTYWAIT))
+ sh_timetraps(tp->sh);
+}
+
+void sh_timetraps(Shell_t *shp)
+{
+ register struct tevent *tp, *tpnext;
+ register struct tevent *tptop;
+ while(1)
+ {
+ shp->sigflag[SIGALRM] &= ~SH_SIGALRM;
+ tptop= (struct tevent*)shp->st.timetrap;
+ for(tp=tptop;tp;tp=tpnext)
+ {
+ tpnext = tp->next;
+ if(tp->flags&L_FLAG)
+ {
+ tp->flags &= ~L_FLAG;
+ if(tp->action)
+ sh_fun(tp->action,tp->node,(char**)0);
+ tp->flags &= ~L_FLAG;
+ if(!tp->flags)
+ {
+ nv_unset(tp->node);
+ nv_close(tp->node);
+ }
+ }
+ }
+ if(!(shp->sigflag[SIGALRM]&SH_SIGALRM))
+ break;
+ }
+}
+
+
+/*
+ * This trap function catches "alarm" actions only
+ */
+static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t
+ *fp)
+{
+ register struct tevent *tp = (struct tevent*)fp;
+ if(!event)
+ return(action?"":(char*)ALARM);
+ if(strcmp(event,ALARM)!=0)
+ {
+ /* try the next level */
+ return(nv_setdisc(np, event, action, fp));
+ }
+ if(action==np)
+ action = tp->action;
+ else
+ tp->action = action;
+ return(action?(char*)action:"");
+}
+
+/*
+ * catch assignments and set alarm traps
+ */
+static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
+{
+ register struct tevent *tp = (struct tevent*)fp;
+ register double d;
+ Shell_t *shp = tp->sh;
+ if(val)
+ {
+ double now;
+#ifdef timeofday
+ struct timeval tmp;
+ timeofday(&tmp);
+ now = tmp.tv_sec + 1.e-6*tmp.tv_usec;
+#else
+ now = (double)time(NIL(time_t*));
+#endif /* timeofday */
+ nv_putv(np,val,flag,fp);
+ d = nv_getnum(np);
+ if(*val=='+')
+ {
+ double x = d + now;
+ nv_putv(np,(char*)&x,NV_INTEGER|NV_DOUBLE,fp);
+ }
+ else
+ d -= now;
+ tp->milli = 1000*(d+.0005);
+ if(tp->timeout)
+ shp->st.timetrap = time_delete(tp,shp->st.timetrap);
+ if(tp->milli > 0)
+ shp->st.timetrap = time_add(tp,shp->st.timetrap);
+ }
+ else
+ {
+ tp = (struct tevent*)nv_stack(np, (Namfun_t*)0);
+ shp->st.timetrap = time_delete(tp,shp->st.timetrap);
+ if(tp->action)
+ nv_close(tp->action);
+ nv_unset(np);
+ free((void*)fp);
+ }
+}
+
+static const Namdisc_t alarmdisc =
+{
+ sizeof(struct tevent),
+ putval,
+ 0,
+ 0,
+ setdisc,
+};
+
+int b_alarm(int argc,char *argv[],Shbltin_t *context)
+{
+ register int n,rflag=0;
+ register Namval_t *np;
+ register struct tevent *tp;
+ register Shell_t *shp = context->shp;
+ while (n = optget(argv, sh_optalarm)) switch (n)
+ {
+ case 'r':
+ rflag = R_FLAG;
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
+ break;
+ }
+ argc -= opt_info.index;
+ argv += opt_info.index;
+ if(error_info.errors)
+ errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
+ if(argc==0)
+ {
+ print_alarms(shp->st.timetrap);
+ return(0);
+ }
+ if(argc!=2)
+ errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
+ np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN);
+ if(!nv_isnull(np))
+ nv_unset(np);
+ nv_setattr(np, NV_DOUBLE);
+ if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0)))
+ errormsg(SH_DICT,ERROR_exit(1),e_nospace);
+ tp->fun.disc = &alarmdisc;
+ tp->flags = rflag;
+ tp->node = np;
+ tp->sh = shp;
+ nv_stack(np,(Namfun_t*)tp);
+ nv_putval(np, argv[1], 0);
+ return(0);
+}
+