238 lines
6.7 KiB
C
238 lines
6.7 KiB
C
/*-
|
|
* 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
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)timer.c 8.13 (Berkeley) 3/23/94";
|
|
#endif /* not lint */
|
|
|
|
#include <sys/queue.h>
|
|
#include <sys/time.h>
|
|
|
|
#include <bitstring.h>
|
|
#include <limits.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <termios.h>
|
|
|
|
#include "compat.h"
|
|
#include <db.h>
|
|
#include <regex.h>
|
|
|
|
#include "vi.h"
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* 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 --
|
|
* Set a busy message timer.
|
|
*/
|
|
int
|
|
busy_on(sp, msg)
|
|
SCR *sp;
|
|
char const *msg;
|
|
{
|
|
struct itimerval value;
|
|
struct timeval tod;
|
|
|
|
/*
|
|
* Give the oldest busy message precedence, since it's
|
|
* the longer running operation.
|
|
*/
|
|
if (sp->busy_msg != NULL)
|
|
return (1);
|
|
|
|
/* 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;
|
|
|
|
/*
|
|
* Busy messages turn around fast. Reset the timer regardless
|
|
* of its current state.
|
|
*/
|
|
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 = 0;
|
|
if (setitimer(ITIMER_REAL, &value, NULL))
|
|
msgq(sp, M_SYSERR, "timer: setitimer");
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* busy_off --
|
|
* Turn off a busy message timer.
|
|
*/
|
|
void
|
|
busy_off(sp)
|
|
SCR *sp;
|
|
{
|
|
/* We depend on this being an atomic instruction. */
|
|
sp->busy_msg = NULL;
|
|
}
|
|
|
|
/*
|
|
* rcv_on --
|
|
* Turn on recovery timer.
|
|
*/
|
|
int
|
|
rcv_on(sp, ep)
|
|
SCR *sp;
|
|
EXF *ep;
|
|
{
|
|
struct itimerval value;
|
|
struct timeval tod;
|
|
|
|
/* Get the current time of day. */
|
|
if (gettimeofday(&tod, NULL))
|
|
return (1);
|
|
|
|
/* Create target time of day. */
|
|
ep->rcv_tod.tv_sec = tod.tv_sec + RCV_PERIOD;
|
|
ep->rcv_tod.tv_usec = 0;
|
|
|
|
/*
|
|
* If there's a busy message happening, we're done, the
|
|
* interrupt handler will start our timer as necessary.
|
|
*/
|
|
if (sp->busy_msg != NULL)
|
|
return (0);
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* h_alrm --
|
|
* Handle SIGALRM.
|
|
*/
|
|
void
|
|
h_alrm(signo)
|
|
int signo;
|
|
{
|
|
struct itimerval value;
|
|
struct timeval ntod, tod;
|
|
SCR *sp;
|
|
EXF *ep;
|
|
|
|
/* 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);
|
|
}
|