aboutsummaryrefslogtreecommitdiffstats
path: root/usr.bin/vi/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/vi/timer.c')
-rw-r--r--usr.bin/vi/timer.c240
1 files changed, 155 insertions, 85 deletions
diff --git a/usr.bin/vi/timer.c b/usr.bin/vi/timer.c
index e2bcfb1c8852..42d366384f67 100644
--- a/usr.bin/vi/timer.c
+++ b/usr.bin/vi/timer.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1993
+ * Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,135 +32,205 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)timer.c 8.7 (Berkeley) 12/2/93";
+static char sccsid[] = "@(#)timer.c 8.13 (Berkeley) 3/23/94";
#endif /* not lint */
+#include <queue.h>
#include <sys/time.h>
-#include "vi.h"
+#include <bitstring.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <db.h>
+#include <regex.h>
-static void busy_handler __P((int));
+#include "vi.h"
/*
- * XXX
- * There are two uses of timers in nvi. The first is to push the recovery
- * information out to disk at periodic intervals. The second is to display
- * a "busy" message if an operation takes too long. Rather than solve this
- * in a general fashion, we depend on the fact that only a single screen in
- * a window is active at a time, and that there are only two parts of the
- * systems that use timers.
+ * There are two uses of the ITIMER_REAL timer (SIGALRM) in nvi. The first
+ * is to push the recovery information out to disk at periodic intervals.
+ * The second is to display a "busy" message if an operation takes more time
+ * that users are willing to wait before seeing something happen. Each of
+ * these uses has a wall clock timer structure in each SCR structure. Since
+ * the busy timer has a much faster timeout than the recovery timer, most of
+ * the code ignores the recovery timer unless it's the only thing running.
*
- * It would be nice to reimplement this with multiple timers, a la POSIX
- * 1003.1, but not many systems offer them yet.
+ * XXX
+ * It would be nice to reimplement this with two timers, a la POSIX 1003.1,
+ * but not many systems offer them yet.
*/
-/*
+/*
* busy_on --
- * Display a message if too much time passes.
+ * Set a busy message timer.
*/
-void
-busy_on(sp, seconds, msg)
+int
+busy_on(sp, msg)
SCR *sp;
- int seconds;
char const *msg;
{
struct itimerval value;
- struct sigaction act;
+ struct timeval tod;
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
+ /*
+ * Give the oldest busy message precedence, since it's
+ * the longer running operation.
+ */
+ if (sp->busy_msg != NULL)
+ return (1);
- /* Turn off the current timer, saving its current value. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &sp->time_value))
- return;
+ /* Get the current time of day, and create a target time. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
+#define USER_PATIENCE_USECS (8 * 100000L)
+ sp->busy_tod.tv_sec = tod.tv_sec;
+ sp->busy_tod.tv_usec = tod.tv_usec + USER_PATIENCE_USECS;
+
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = msg;
/*
- * Decrement the original timer by the number of seconds
- * we're going to wait.
+ * Busy messages turn around fast. Reset the timer regardless
+ * of its current state.
*/
- if (sp->time_value.it_value.tv_sec > seconds)
- sp->time_value.it_value.tv_sec -= seconds;
- else
- sp->time_value.it_value.tv_sec = 1;
-
- /* Reset the handler, saving its current value. */
- act.sa_handler = busy_handler;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- (void)sigaction(SIGALRM, &act, &sp->time_handler);
-
- /* Reset the timer. */
- value.it_value.tv_sec = seconds;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_usec = USER_PATIENCE_USECS;
value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- (void)setitimer(ITIMER_REAL, &value, NULL);
-
- sp->time_msg = msg;
- F_SET(sp, S_TIMER_SET);
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL))
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (0);
}
/*
* busy_off --
- * Reset the timer handlers.
+ * Turn off a busy message timer.
*/
void
busy_off(sp)
SCR *sp;
{
- struct itimerval ovalue, value;
-
- /* No busy messages in batch mode. */
- if (F_ISSET(sp, S_EXSILENT))
- return;
-
- /* If the timer flag isn't set, it must have fired. */
- if (!F_ISSET(sp, S_TIMER_SET))
- return;
+ /* We depend on this being an atomic instruction. */
+ sp->busy_msg = NULL;
+}
- /* Ignore it if first on one of following system calls. */
- F_CLR(sp, S_TIMER_SET);
+/*
+ * rcv_on --
+ * Turn on recovery timer.
+ */
+int
+rcv_on(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ struct itimerval value;
+ struct timeval tod;
- /* Turn off the current timer. */
- value.it_interval.tv_sec = value.it_value.tv_sec = 0;
- value.it_interval.tv_usec = value.it_value.tv_usec = 0;
- if (setitimer(ITIMER_REAL, &value, &ovalue))
- return;
+ /* Get the current time of day. */
+ if (gettimeofday(&tod, NULL))
+ return (1);
- /* If the timer wasn't running, we're done. */
- if (sp->time_handler.sa_handler == SIG_DFL)
- return;
+ /* Create target time of day. */
+ ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD;
+ ep->rcv_tod.tv_usec = 0;
/*
- * Increment the old timer by the number of seconds
- * remaining in the new one.
+ * If there's a busy message happening, we're done, the
+ * interrupt handler will start our timer as necessary.
*/
- sp->time_value.it_value.tv_sec += ovalue.it_value.tv_sec;
-
- /* Reset the handler to the original handler. */
- (void)sigaction(SIGALRM, &sp->time_handler, NULL);
+ if (sp->busy_msg != NULL)
+ return (0);
- /* Reset the timer. */
- (void)setitimer(ITIMER_REAL, &sp->time_value, NULL);
+ value.it_value.tv_sec = RCV_PERIOD;
+ value.it_value.tv_usec = 0;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &value, NULL)) {
+ msgq(sp, M_SYSERR, "timer: setitimer");
+ return (1);
+ }
+ return (0);
}
/*
- * busy_handler --
- * Display a message when the timer goes off, and restore the
- * timer to its original values.
+ * h_alrm --
+ * Handle SIGALRM.
*/
-static void
-busy_handler(signo)
+void
+h_alrm(signo)
int signo;
{
+ struct itimerval value;
+ struct timeval ntod, tod;
SCR *sp;
+ EXF *ep;
- for (sp = __global_list->dq.cqh_first;
- sp != (void *)&__global_list->dq; sp = sp->q.cqe_next)
- if (F_ISSET(sp, S_TIMER_SET)) {
- sp->s_busy(sp, sp->time_msg);
- busy_off(sp);
+ /* XXX: Get the current time of day; if this fails, we're dead. */
+ if (gettimeofday(&tod, NULL))
+ return;
+
+ /*
+ * Fire any timers that are past due, or any that are due
+ * in a tenth of a second or less.
+ */
+ for (ntod.tv_sec = 0, sp = __global_list->dq.cqh_first;
+ sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) {
+
+ /* Check the busy timer if the msg pointer is set. */
+ if (sp->busy_msg == NULL)
+ goto skip_busy;
+ if (sp->busy_tod.tv_sec > tod.tv_sec ||
+ sp->busy_tod.tv_sec == tod.tv_sec &&
+ sp->busy_tod.tv_usec > tod.tv_usec &&
+ sp->busy_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > sp->busy_tod.tv_sec ||
+ ntod.tv_sec == sp->busy_tod.tv_sec &&
+ ntod.tv_usec > sp->busy_tod.tv_usec)
+ ntod = sp->busy_tod;
+ } else {
+ (void)sp->s_busy(sp, sp->busy_msg);
+ sp->busy_msg = NULL;
+ }
+
+ /*
+ * Check the recovery timer if there's an EXF structure
+ * and the recovery bit is set.
+ */
+skip_busy: if ((ep = sp->ep) == NULL || !F_ISSET(sp->ep, F_RCV_ON))
+ continue;
+ if (ep->rcv_tod.tv_sec > tod.tv_sec ||
+ ep->rcv_tod.tv_sec == tod.tv_sec &&
+ ep->rcv_tod.tv_usec > tod.tv_usec &&
+ ep->rcv_tod.tv_usec - tod.tv_usec > 100000L) {
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
+ } else {
+ F_SET(sp->gp, G_SIGALRM);
+ ep->rcv_tod = tod;
+ ep->rcv_tod.tv_sec += RCV_PERIOD;
+
+ if (ntod.tv_sec == 0 ||
+ ntod.tv_sec > ep->rcv_tod.tv_sec ||
+ ntod.tv_sec == ep->rcv_tod.tv_sec &&
+ ntod.tv_usec > ep->rcv_tod.tv_usec)
+ ntod = ep->rcv_tod;
}
+ }
+
+ if (ntod.tv_sec == 0)
+ return;
+
+ /* XXX: Set the timer; if this fails, we're dead. */
+ value.it_value.tv_sec = ntod.tv_sec - tod.tv_sec;
+ value.it_value.tv_usec = ntod.tv_usec - tod.tv_usec;
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = 0;
+ (void)setitimer(ITIMER_REAL, &value, NULL);
}