home *** CD-ROM | disk | FTP | other *** search
- Subject: v15i022: Delta time routines for alarm(2) manipulation
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Gregg Wonderly <gregg@a.cs.okstate.edu>
- Posting-number: Volume 15, Issue 22
- Archive-name: timer
-
- This shell archive contains the source, man page and test program for
- some delta time routines. These routines allow you to schedule many things
- to happen in the future (in terms of a delta time) without having to do
- all the typical messing with alarm(2). I.E. these routines maintain a
- list of delta times, routines and corresponding arguments, and then call
- the routine after the delta time expires, passing the arguement to it.
-
- Gregg Wonderly
- Department of Computing and Information Sciences
- Oklahoma State University
-
- UUCP: {cbosgd, ihnp4, rutgers}!okstate!gregg
- Internet: gregg@A.CS.OKSTATE.EDU
-
- ===============================================================================
- echo x - README
- sed '1,$s/^X//' <<\!FUNKY!STUFF! > README
- XTimer.c contains the source for some delta time manipulation routines.
- XThese routines allow you to schedule the execution of a routine at
- Xsome point in the future. ttest.c is a test routine to demonstrate
- Xsome of the uses of the routines. Compile it using the command,
- Xmake install, and then run it using the command, ttest. The results
- Xshould be
- X
- X$ make install
- X cc -O -c timer.c
- X cc -O -c ttest.c
- X cc timer.o ttest.o \
- X -o xttest
- X cp xttest ./ttest
- X$ ttest
- X1
- X*2
- X3
- X5
- X6
- X*6
- X8
- X*10
- X*12
- X**15
- X*16
- X**18
- X**24
- X
- XThe numbers represent elapsed time in seconds since the command, ttest,
- Xwas issued.
- X
- X- 1.2 -
- !FUNKY!STUFF!
- echo x - makefile
- sed '1,$s/^X//' <<\!FUNKY!STUFF! > makefile
- X#
- X# This makefile was generated by MAKEF on Tue Mar 1 16:59:12 1988
- X# Version 1.00, updated: Monday January 11, 1988 at 00:33
- X#
- X# 1.2
- XLIB =
- XCFLAGS = -O
- XLDFLAGS =
- XBIN = .
- X#
- X# This makefile knows how to generate the following program
- X#
- XALL_PROGS = xttest
- X#
- Xall : $(ALL_PROGS)
- X#
- Xinstall : inst-ttest
- X#
- X# Install ttest
- X#
- Xinst-ttest : ${BIN}/ttest
- X${BIN}/ttest : xttest
- X cp xttest ${BIN}/ttest
- X#
- X# Stuff to make `TTEST'
- X#
- XTTEST_CFILES = timer.c ttest.c
- XTTEST_OFILES = timer.o ttest.o
- XTTEST_RPROG = xttest
- XTTEST_PROG = xttest
- XTTEST_SYSLIBS =
- XTTEST_LIBS =
- X#
- X$(TTEST_PROG): $(TTEST_LIBS) $(TTEST_OFILES)
- X cc $(TTEST_OFILES) $(TTEST_LIBS) \
- X $(TTEST_SYSLIBS) -o $(TTEST_PROG)
- X#
- X# File list to be removed for make clean
- X#
- XCLEANUP_FILES = \
- X xttest \
- X \
- X timer.o ttest.o
- Xclean:
- X rm -f $(CLEANUP_FILES)
- X#
- XALWAYS:
- X#
- !FUNKY!STUFF!
- echo x - timer.1
- sed '1,$s/^X//' <<\!FUNKY!STUFF! > timer.1
- X.TH TIMER 3L "Oklahoma State University"
- X.SH NAME
- Xset_timer, can_timer, did_timer, hold_timer, release_timer \- delta timer
- X.SH SYNOPSIS
- X.nf
- X.PP
- X.B int set_timer (delta_time, rout, arg)
- X.B int delta_time;
- X.B void (*rout)();
- X.B char *arg;
- X.PP
- X.B int can_timer (rout, arg)
- X.B int (*rout)();
- X.B char *arg;
- X.PP
- X.B int did_timer ();
- X.PP
- X.B void hold_timer ()
- X.PP
- X.B void release_timer ()
- X.fi
- X.SH DESCRIPTION
- XThese routines manage and provide information about a list of delta time
- Xactivities that a process has queued for processing.
- X.PP
- X.B set_timer
- Xaccepts a delta time in seconds, which represents the time in the future
- Xthat
- X.B rout
- Xshould be called with
- X.B arg
- Xas its only argument. This allows the programmer to queue several events to
- Xoccur at intervals or in the future.
- X.B set_timer
- Xreturns 0 on success and -1 otherwise.
- X.B errno
- Xshould convey the reason for failure.
- X.PP
- X.B can_timer
- Xaccepts two arguments which where the second and third arguments to a previous
- Xcall to
- X.B set_timer.
- XThe corresponding entry from the list that
- X.B set_timer
- Xplaces requests on, is removed, and will no longer be processed.
- X.B can_timer
- Xreturns 0 on success and -1 otherwise.
- X.B errno
- Xshould convey the reason for failure.
- X.PP
- X.B did_timer
- Xis a function which returns true if a timer entry has been processed since
- Xthe last call to
- X.B did_timer.
- X.PP
- X.B hold_timer
- Xcauses the actual processing of any expired timer entries to be delayed until
- X.B release_timer
- Xis called.
- X.SH BUGS
- XDue to the granularity of the UNIX clock, some things may actually happen
- Xat the same time when you expected them to happen 1 second apart.
- X.SH AUTHOR
- XGregg Wonderly -- Oklahoma State University
- X.s
- X.nf
- XInternet: gregg@a.cs.okstate.edu
- XUUCP: {ihnp4, rutgers}!okstate!gregg
- X.fi
- X.SH VERSION
- X- 1.4 -
- !FUNKY!STUFF!
- echo x - timer.c
- sed '1,$s/^X//' <<\!FUNKY!STUFF! > timer.c
- Xstatic char S_timerc[]=
- X "@(#)timer.c, 1.4 - Gregg Wonderly@a.cs.okstate.edu - 17:10:52, 3/1/88";
- X
- X/***************************************************************************
- X *
- X * The routines in this file make up a generalized timer facility
- X * that maintains a list of timer entries, and sorts them according to
- X * their estimated expire times. Thus calls to set_timer() can be made
- X * arbitrarily, and the times passed will be the elapsed time from now
- X * that the timer should go off. set_timer() accepts as arguments the
- X * delta time from now that the timer should go off, the address of a
- X * routine to call, and a parameter to pass to that routine. Typically
- X * this parameter qualifies the timer entry being serviced.
- X *
- X * The second routine is called during servicing of the SIGALRM. It
- X * processes all requests that expire at that time, and then set up the
- X * next alarm.
- X *
- X **************************************************************************/
- X
- X/* System includes. */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <sys/types.h>
- X#include <sys/ipc.h>
- X#include <sys/msg.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X
- Xtypedef struct TIMER {
- X unsigned delta_t; /* Time in seconds till this entry is due. */
- X union {
- X long l_key;
- X char *p_key;
- X } u_t;
- X int (*routine)();
- X struct TIMER *next;
- X} TIMER, *TIMEPTR;
- X
- Xstatic TIMEPTR t_queue = NULL, holdq = NULL;
- Xstatic int hold_timers = 0, done_timer = 0;
- X
- Xstatic int alarm_time();
- X
- Xdid_timer()
- X{
- X register int i = done_timer;
- X
- X done_timer = 0;
- X
- X return (i);
- X}
- X
- X/*
- X * Process all pending timer entries.
- X */
- X
- Xrelease_timer ()
- X{
- X TIMEPTR p, q;
- X
- X hold_timers = 0;
- X for (p = holdq; p != NULL;) {
- X if (p->routine != NULL)
- X (*(p->routine))(p->u_t.p_key);
- X q = p->next;
- X free (p);
- X p = q;
- X }
- X holdq = NULL;
- X}
- X
- Xhold_timer ()
- X{
- X hold_timers = 1;
- X}
- X
- X/*
- X * Cancel a timer request by NULLing the routine pointer. Quick and dirty.
- X */
- X
- Xcan_timer (rout, key)
- X int (*rout)();
- X char *key;
- X{
- X TIMEPTR p;
- X int left;
- X
- X /* Get the time left till the current entry expires. */
- X
- X left = alarm(0);
- X
- X /* Correct the first entry to be up to date with elapsed time. */
- X
- X if (t_queue != NULL)
- X t_queue->delta_t = left;
- X
- X /* Find the requested entry, and mark it. */
- X
- X for (p=t_queue; p != NULL; p=p->next) {
- X if (p->routine == rout && p->u_t.p_key == key) {
- X p->routine = NULL;
- X break;
- X }
- X }
- X
- X if (p == NULL) {
- X alarm (left);
- X return (-1);
- X }
- X
- X /*
- X * Restart the alarm on the next entry so that it doesn't go off until
- X * necessary.
- X */
- X
- X for (p=t_queue; p != NULL; p=p->next) {
- X
- X /* If we did not nullify the first entry then use it. */
- X
- X if (p->routine != NULL) {
- X
- X /*
- X * If the next available slot happens to be the second or later
- X * entry in a group that expires at the same time, then we must
- X * use the value of `left' as the alarm time, NOT the zero value
- X * in the delta_t slot, which would cause the alarms to be
- X * canceled
- X */
- X
- X if (p->delta_t == 0)
- X alarm (p->delta_t = left);
- X else
- X alarm (p->delta_t);
- X break;
- X } else {
- X
- X /* Otherwise, delete the first entry, and look at the next. */
- X
- X t_queue = p->next;
- X free (p);
- X p = t_queue;
- X }
- X }
- X
- X return (0);
- X}
- X
- X/*
- X * Set a new timer request to go off after the interval passed expires.
- X */
- X
- Xset_timer (intv, rout, key)
- X int intv;
- X int (*rout)();
- X char *key;
- X{
- X TIMEPTR p, prevp = NULL, newp;
- X unsigned t_left;
- X
- X /* Get the remaining time, and put the alarm on hold. */
- X
- X if (t_queue != NULL)
- X t_left = alarm(0);
- X else
- X t_left = 0;
- X
- X /* Get a new timer queue entry. */
- X
- X if ((newp = (TIMEPTR) malloc (sizeof (TIMER))) == NULL)
- X return (-1);
- X
- X /* Correct the first entry to be up to date with elapsed time. */
- X
- X if (t_queue != NULL)
- X t_queue->delta_t = t_left;
- X
- X /*
- X * Search for the insertion point. >= makes the ordering consistant.
- X * with the order of the calls to set_timer ().
- X */
- X
- X for (p=t_queue; p != NULL && intv >= p->delta_t; p = p->next) {
- X prevp = p;
- X intv -= p->delta_t;
- X }
- X
- X /* Is this the first entry, or insertion at end of list? */
- X
- X if (p == NULL) {
- X
- X /* If first entry, then put it in. */
- X
- X if (prevp == NULL) {
- X t_queue = newp;
- X
- X /* If last, then just insert the entry. */
- X
- X } else
- X prevp->next = newp;
- X
- X newp->next = NULL;
- X
- X /* If insertion at beginning or in middle. */
- X
- X } else {
- X
- X /* If insertion at beginning then, put in entry, and redo alarm. */
- X
- X if (prevp == NULL) {
- X newp->next = t_queue;
- X t_queue = newp;
- X
- X /* Otherwise, insertion in the middle, so don't touch alarm time. */
- X
- X } else {
- X newp->next = p;
- X prevp->next = newp;
- X }
- X p->delta_t -= intv;
- X }
- X
- X newp->delta_t = intv;
- X newp->u_t.p_key = key;
- X newp->routine = rout;
- X
- X /* Reset the alarm to go off later. */
- X
- X signal (SIGALRM, alarm_time);
- X alarm (t_queue->delta_t);
- X
- X return (0);
- X}
- X
- X/*
- X * Called when an alarm goes off, picks off the first timer entry, queues
- X * the next one, and then processes the one picked off.
- X */
- X
- Xstatic int alarm_time (sig)
- X unsigned sig;
- X{
- X TIMEPTR p;
- X
- X done_timer = 1;
- X signal (SIGALRM, alarm_time);
- X
- X do {
- X p = t_queue;
- X if ((t_queue = t_queue->next) != NULL && (t_queue->delta_t > 0)) {
- X
- X /* Set the next alarm time. */
- X
- X alarm (t_queue->delta_t);
- X }
- X
- X /* If holding timer entries, then place this one on the list. */
- X
- X if (hold_timers) {
- X p->next = holdq;
- X holdq = p;
- X } else {
- X
- X /* Invoke the routine requested. */
- X
- X if (p->routine != NULL)
- X (*(p->routine))(p->u_t.p_key);
- X
- X /* Free the member. */
- X
- X free (p);
- X }
- X } while (t_queue != NULL && t_queue->delta_t == 0);
- X
- X /* And back out. */
- X}
- !FUNKY!STUFF!
- echo x - ttest.c
- sed '1,$s/^X//' <<\!FUNKY!STUFF! > ttest.c
- Xstatic char S_ttestc[]=
- X "@(#)ttest.c, 1.1 - Gregg Wonderly@a.cs.okstate.edu - 16:55:50, 3/1/88";
- X
- X#include <signal.h>
- X
- Xextern exit(), sub1(), sub2(), sub3(), catch();
- X
- Xmain (argc, argv)
- X int argc;
- X char **argv;
- X{
- X
- X if (set_timer (8, sub1, (char *)8)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X if (set_timer (1, sub1, (char *)1)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X if (set_timer (3, sub1, (char *)3)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X if (set_timer (6, sub1, (char *)6)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X if (set_timer (5, sub1, (char *)5)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X
- X if (set_timer (26, exit, (char *)0)) {
- X perror ("set_timer");
- X exit (1);
- X }
- X
- X signal (SIGINT, catch);
- X while (1) {
- X pause ();
- X if (!did_timer())
- X perror ("pause");
- X if (did_timer())
- X perror ("set_timer");
- X }
- X}
- X
- Xsub1(i)
- X char *i;
- X{
- X printf ("%d\n", (int)i);
- X set_timer ((int)i, sub2, (char *) ((int)i*2));
- X}
- X
- Xsub2 (i)
- X char *i;
- X{
- X printf ("*%d\n", (int)i);
- X set_timer ((int)i/2, sub3, (char *)((int)i+((int)i/2)));
- X if ((int)i < 10)
- X can_timer (sub3, (char *)((int)i+((int)i/2)));
- X}
- X
- Xsub3(i)
- X char *i;
- X{
- X printf ("**%d\n", (int)i);
- X}
- X
- Xcatch (i)
- X int i;
- X{
- X signal (i, catch);
- X}
- !FUNKY!STUFF!
-