home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume15 / timer < prev    next >
Encoding:
Text File  |  1989-01-13  |  11.5 KB  |  542 lines

  1. Subject:  v15i022:  Delta time routines for alarm(2) manipulation
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Gregg Wonderly <gregg@a.cs.okstate.edu>
  6. Posting-number: Volume 15, Issue 22
  7. Archive-name: timer
  8.  
  9. This shell archive contains the source, man page and test program for
  10. some delta time routines.  These routines allow you to schedule many things
  11. to happen in the future (in terms of a delta time) without having to do
  12. all the typical messing with alarm(2).  I.E. these routines maintain a
  13. list of delta times, routines and corresponding arguments, and then call
  14. the routine after the delta time expires, passing the arguement to it.
  15.  
  16. Gregg Wonderly
  17. Department of Computing and Information Sciences
  18. Oklahoma State University
  19.  
  20. UUCP:      {cbosgd, ihnp4, rutgers}!okstate!gregg
  21. Internet:  gregg@A.CS.OKSTATE.EDU
  22.  
  23. ===============================================================================
  24. echo x - README
  25. sed '1,$s/^X//' <<\!FUNKY!STUFF! > README
  26. XTimer.c contains the source for some delta time manipulation routines.
  27. XThese routines allow you to schedule the execution of a routine at
  28. Xsome point in the future.  ttest.c is a test routine to demonstrate
  29. Xsome of the uses of the routines.  Compile it using the command,
  30. Xmake install, and then run it using the command, ttest.  The results
  31. Xshould be
  32. X
  33. X$ make install
  34. X     cc -O -c timer.c
  35. X    cc -O -c ttest.c
  36. X    cc timer.o ttest.o   \
  37. X        -o xttest
  38. X    cp xttest ./ttest
  39. X$ ttest
  40. X1
  41. X*2
  42. X3
  43. X5
  44. X6
  45. X*6
  46. X8
  47. X*10
  48. X*12
  49. X**15
  50. X*16
  51. X**18
  52. X**24
  53. X
  54. XThe numbers represent elapsed time in seconds since the command, ttest,
  55. Xwas issued.
  56. X
  57. X- 1.2 -
  58. !FUNKY!STUFF!
  59. echo x - makefile
  60. sed '1,$s/^X//' <<\!FUNKY!STUFF! > makefile
  61. X#
  62. X#    This makefile was generated by MAKEF on Tue Mar  1 16:59:12 1988
  63. X#    Version  1.00, updated: Monday January 11, 1988 at 00:33
  64. X#
  65. X#    1.2
  66. XLIB = 
  67. XCFLAGS = -O
  68. XLDFLAGS = 
  69. XBIN = .
  70. X#
  71. X#  This makefile knows how to generate the following program
  72. X#
  73. XALL_PROGS = xttest 
  74. X#
  75. Xall : $(ALL_PROGS)
  76. X#
  77. Xinstall : inst-ttest 
  78. X#
  79. X# Install ttest
  80. X#
  81. Xinst-ttest : ${BIN}/ttest
  82. X${BIN}/ttest : xttest
  83. X    cp xttest ${BIN}/ttest
  84. X#
  85. X#    Stuff to make `TTEST'
  86. X#
  87. XTTEST_CFILES = timer.c ttest.c 
  88. XTTEST_OFILES = timer.o ttest.o 
  89. XTTEST_RPROG = xttest
  90. XTTEST_PROG = xttest
  91. XTTEST_SYSLIBS = 
  92. XTTEST_LIBS = 
  93. X#
  94. X$(TTEST_PROG): $(TTEST_LIBS) $(TTEST_OFILES)
  95. X    cc $(TTEST_OFILES) $(TTEST_LIBS) \
  96. X       $(TTEST_SYSLIBS) -o $(TTEST_PROG)
  97. X#
  98. X#   File list to be removed for make clean
  99. X#
  100. XCLEANUP_FILES = \
  101. X    xttest \
  102. X    \
  103. X    timer.o ttest.o 
  104. Xclean:
  105. X    rm -f $(CLEANUP_FILES)
  106. X#
  107. XALWAYS:
  108. X#
  109. !FUNKY!STUFF!
  110. echo x - timer.1
  111. sed '1,$s/^X//' <<\!FUNKY!STUFF! > timer.1
  112. X.TH TIMER 3L "Oklahoma State University"
  113. X.SH NAME
  114. Xset_timer, can_timer, did_timer, hold_timer, release_timer \- delta timer
  115. X.SH SYNOPSIS
  116. X.nf
  117. X.PP
  118. X.B int set_timer (delta_time, rout, arg)
  119. X.B int delta_time;
  120. X.B void (*rout)();
  121. X.B char *arg;
  122. X.PP
  123. X.B int can_timer (rout, arg)
  124. X.B int (*rout)();
  125. X.B char *arg;
  126. X.PP
  127. X.B int did_timer ();
  128. X.PP
  129. X.B void hold_timer ()
  130. X.PP
  131. X.B void release_timer ()
  132. X.fi
  133. X.SH DESCRIPTION
  134. XThese routines manage and provide information about a list of delta time
  135. Xactivities that a process has queued for processing.
  136. X.PP
  137. X.B set_timer
  138. Xaccepts a delta time in seconds, which represents the time in the future
  139. Xthat
  140. X.B rout
  141. Xshould be called with
  142. X.B arg
  143. Xas its only argument.  This allows the programmer to queue several events to
  144. Xoccur at intervals or in the future.
  145. X.B set_timer
  146. Xreturns 0 on success and -1 otherwise.
  147. X.B errno
  148. Xshould convey the reason for failure.
  149. X.PP
  150. X.B can_timer
  151. Xaccepts two arguments which where the second and third arguments to a previous
  152. Xcall to
  153. X.B set_timer.
  154. XThe corresponding entry from the list that
  155. X.B set_timer
  156. Xplaces requests on, is removed, and will no longer be processed.
  157. X.B can_timer
  158. Xreturns 0 on success and -1 otherwise.
  159. X.B errno
  160. Xshould convey the reason for failure.
  161. X.PP
  162. X.B did_timer
  163. Xis a function which returns true if a timer entry has been processed since
  164. Xthe last call to
  165. X.B did_timer.
  166. X.PP
  167. X.B hold_timer
  168. Xcauses the actual processing of any expired timer entries to be delayed until
  169. X.B release_timer
  170. Xis called.
  171. X.SH BUGS
  172. XDue to the granularity of the UNIX clock, some things may actually happen
  173. Xat the same time when you expected them to happen 1 second apart.
  174. X.SH AUTHOR
  175. XGregg Wonderly -- Oklahoma State University
  176. X.s
  177. X.nf
  178. XInternet: gregg@a.cs.okstate.edu
  179. XUUCP:     {ihnp4, rutgers}!okstate!gregg
  180. X.fi
  181. X.SH VERSION
  182. X- 1.4 -
  183. !FUNKY!STUFF!
  184. echo x - timer.c
  185. sed '1,$s/^X//' <<\!FUNKY!STUFF! > timer.c
  186. Xstatic char S_timerc[]=
  187. X    "@(#)timer.c, 1.4 - Gregg Wonderly@a.cs.okstate.edu  -  17:10:52, 3/1/88";
  188. X
  189. X/***************************************************************************
  190. X *
  191. X *        The routines in this file make up a generalized timer facility
  192. X *    that maintains a list of timer entries, and sorts them according to
  193. X *    their estimated expire times.  Thus calls to set_timer() can be made
  194. X *    arbitrarily, and the times passed will be the elapsed time from now
  195. X *    that the timer should go off.  set_timer() accepts as arguments the
  196. X *    delta time from now that the timer should go off, the address of a
  197. X *    routine to call, and a parameter to pass to that routine.  Typically
  198. X *    this parameter qualifies the timer entry being serviced.
  199. X *
  200. X *        The second routine is called during servicing of the SIGALRM.  It
  201. X *    processes all requests that expire at that time, and then set up the
  202. X *    next alarm.
  203. X *
  204. X **************************************************************************/
  205. X
  206. X/*  System includes.  */
  207. X
  208. X#include    <stdio.h>
  209. X#include    <errno.h>
  210. X#include    <sys/types.h>
  211. X#include    <sys/ipc.h>
  212. X#include    <sys/msg.h>
  213. X#include    <signal.h>
  214. X#include    <setjmp.h>
  215. X
  216. Xtypedef struct TIMER {
  217. X    unsigned delta_t;        /*  Time in seconds till this entry is due.  */
  218. X    union {
  219. X        long l_key;
  220. X        char *p_key;
  221. X    } u_t;
  222. X    int (*routine)();
  223. X    struct TIMER *next;
  224. X} TIMER, *TIMEPTR;
  225. X
  226. Xstatic TIMEPTR t_queue = NULL, holdq = NULL;
  227. Xstatic int hold_timers = 0, done_timer = 0;
  228. X
  229. Xstatic int alarm_time();
  230. X
  231. Xdid_timer()
  232. X{
  233. X    register int i = done_timer;
  234. X
  235. X    done_timer = 0;
  236. X
  237. X    return (i);
  238. X}
  239. X
  240. X/*
  241. X *  Process all pending timer entries.
  242. X */
  243. X
  244. Xrelease_timer ()
  245. X{
  246. X    TIMEPTR p, q;
  247. X
  248. X    hold_timers = 0;
  249. X    for (p = holdq; p != NULL;) {
  250. X        if (p->routine != NULL)
  251. X            (*(p->routine))(p->u_t.p_key);
  252. X        q = p->next;
  253. X        free (p);
  254. X        p = q;
  255. X    }
  256. X    holdq = NULL;
  257. X}
  258. X
  259. Xhold_timer ()
  260. X{
  261. X    hold_timers = 1;
  262. X}
  263. X
  264. X/*
  265. X *    Cancel a timer request by NULLing the routine pointer.  Quick and dirty.
  266. X */
  267. X
  268. Xcan_timer (rout, key)
  269. X    int (*rout)();
  270. X    char *key;
  271. X{
  272. X    TIMEPTR p;
  273. X    int left;
  274. X
  275. X    /*  Get the time left till the current entry expires.  */
  276. X
  277. X    left = alarm(0);
  278. X
  279. X    /*  Correct the first entry to be up to date with elapsed time.  */
  280. X
  281. X    if (t_queue != NULL)
  282. X        t_queue->delta_t = left;
  283. X
  284. X    /*  Find the requested entry, and mark it.  */
  285. X
  286. X    for (p=t_queue; p != NULL; p=p->next) {
  287. X        if (p->routine == rout && p->u_t.p_key == key) {
  288. X            p->routine = NULL;
  289. X            break;
  290. X        }
  291. X    }
  292. X
  293. X    if (p == NULL) {
  294. X        alarm (left);
  295. X        return (-1);
  296. X    }
  297. X
  298. X    /*
  299. X     *  Restart the alarm on the next entry so that it doesn't go off until
  300. X     *    necessary.
  301. X     */
  302. X
  303. X    for (p=t_queue; p != NULL; p=p->next) {
  304. X
  305. X        /*  If we did not nullify the first entry then use it.  */
  306. X
  307. X        if (p->routine != NULL) {
  308. X
  309. X            /*
  310. X             *    If the next available slot happens to be the second or later
  311. X             *    entry in a group that expires at the same time, then we must
  312. X             *    use the value of `left' as the alarm time, NOT the zero value
  313. X             *    in the delta_t slot, which would cause the alarms to be
  314. X             *    canceled
  315. X             */
  316. X
  317. X            if (p->delta_t == 0)
  318. X                alarm (p->delta_t = left);
  319. X            else
  320. X                alarm (p->delta_t);
  321. X            break;
  322. X        } else {
  323. X
  324. X            /*  Otherwise, delete the first entry, and look at the next.  */
  325. X
  326. X            t_queue = p->next;
  327. X            free (p);
  328. X            p = t_queue;
  329. X        }
  330. X    }
  331. X
  332. X    return (0);
  333. X}
  334. X
  335. X/*
  336. X *    Set a new timer request to go off after the interval passed expires.
  337. X */
  338. X
  339. Xset_timer (intv, rout, key)
  340. X    int intv;
  341. X    int (*rout)();
  342. X    char *key;
  343. X{
  344. X    TIMEPTR p, prevp = NULL, newp;
  345. X    unsigned t_left;
  346. X
  347. X    /*  Get the remaining time, and put the alarm on hold.  */
  348. X
  349. X    if (t_queue != NULL)
  350. X        t_left = alarm(0);
  351. X    else
  352. X        t_left = 0;
  353. X
  354. X    /*  Get a new timer queue entry.  */
  355. X
  356. X    if ((newp = (TIMEPTR) malloc (sizeof (TIMER))) == NULL)
  357. X        return (-1);
  358. X
  359. X    /*  Correct the first entry to be up to date with elapsed time.  */
  360. X
  361. X    if (t_queue != NULL)
  362. X        t_queue->delta_t = t_left;
  363. X
  364. X    /*
  365. X     *  Search for the insertion point.  >= makes the ordering consistant.
  366. X     *    with the order of the calls to set_timer ().
  367. X     */
  368. X
  369. X    for (p=t_queue; p != NULL && intv >= p->delta_t; p = p->next) {
  370. X        prevp = p;
  371. X        intv -= p->delta_t;
  372. X    }
  373. X
  374. X    /*  Is this the first entry, or insertion at end of list?  */
  375. X
  376. X    if (p == NULL) {
  377. X
  378. X        /*  If first entry, then put it in.  */
  379. X
  380. X        if (prevp == NULL) {
  381. X            t_queue = newp;
  382. X
  383. X        /*  If last, then just insert the entry.  */
  384. X
  385. X        } else
  386. X            prevp->next = newp;
  387. X
  388. X        newp->next = NULL;
  389. X
  390. X    /*  If insertion at beginning or in middle.  */
  391. X
  392. X    } else {
  393. X
  394. X        /*  If insertion at beginning then, put in entry, and redo alarm.  */
  395. X
  396. X        if (prevp == NULL) {
  397. X            newp->next = t_queue;
  398. X            t_queue = newp;
  399. X
  400. X        /*  Otherwise, insertion in the middle, so don't touch alarm time.  */
  401. X
  402. X        } else {
  403. X            newp->next = p;
  404. X            prevp->next = newp;
  405. X        }
  406. X        p->delta_t -= intv;
  407. X    }
  408. X
  409. X    newp->delta_t = intv;
  410. X    newp->u_t.p_key = key;
  411. X    newp->routine = rout;
  412. X
  413. X    /*  Reset the alarm to go off later.  */
  414. X
  415. X    signal (SIGALRM, alarm_time);
  416. X    alarm (t_queue->delta_t);
  417. X
  418. X    return (0);
  419. X}
  420. X
  421. X/*
  422. X *        Called when an alarm goes off, picks off the first timer entry, queues
  423. X *    the next one, and then processes the one picked off.
  424. X */
  425. X
  426. Xstatic int alarm_time (sig)
  427. X    unsigned sig;
  428. X{
  429. X    TIMEPTR p;
  430. X
  431. X    done_timer = 1;
  432. X    signal (SIGALRM, alarm_time);
  433. X
  434. X    do {
  435. X        p = t_queue;
  436. X        if ((t_queue = t_queue->next) != NULL && (t_queue->delta_t > 0)) {
  437. X
  438. X            /*  Set the next alarm time.  */
  439. X
  440. X            alarm (t_queue->delta_t);
  441. X        }
  442. X
  443. X        /*  If holding timer entries, then place this one on the list.  */
  444. X
  445. X        if (hold_timers) {
  446. X            p->next = holdq;
  447. X            holdq = p;
  448. X        } else {
  449. X
  450. X            /*  Invoke the routine requested.  */
  451. X
  452. X            if (p->routine != NULL)
  453. X                (*(p->routine))(p->u_t.p_key);
  454. X
  455. X            /*  Free the member.  */
  456. X
  457. X            free (p);
  458. X        }
  459. X    } while (t_queue != NULL && t_queue->delta_t == 0);
  460. X
  461. X    /*  And back out.  */
  462. X}
  463. !FUNKY!STUFF!
  464. echo x - ttest.c
  465. sed '1,$s/^X//' <<\!FUNKY!STUFF! > ttest.c
  466. Xstatic char S_ttestc[]=
  467. X    "@(#)ttest.c, 1.1 - Gregg Wonderly@a.cs.okstate.edu  -  16:55:50, 3/1/88";
  468. X
  469. X#include <signal.h>
  470. X
  471. Xextern exit(), sub1(), sub2(), sub3(), catch();
  472. X
  473. Xmain (argc, argv)
  474. X    int argc;
  475. X    char **argv;
  476. X{
  477. X
  478. X    if (set_timer (8, sub1, (char *)8)) {
  479. X        perror ("set_timer");
  480. X        exit (1);
  481. X    }
  482. X    if (set_timer (1, sub1, (char *)1)) {
  483. X        perror ("set_timer");
  484. X        exit (1);
  485. X    }
  486. X    if (set_timer (3, sub1, (char *)3)) {
  487. X        perror ("set_timer");
  488. X        exit (1);
  489. X    }
  490. X    if (set_timer (6, sub1, (char *)6)) {
  491. X        perror ("set_timer");
  492. X        exit (1);
  493. X    }
  494. X    if (set_timer (5, sub1, (char *)5)) {
  495. X        perror ("set_timer");
  496. X        exit (1);
  497. X    }
  498. X
  499. X    if (set_timer (26, exit, (char *)0)) {
  500. X        perror ("set_timer");
  501. X        exit (1);
  502. X    }
  503. X
  504. X    signal (SIGINT, catch);
  505. X    while (1) {
  506. X        pause ();
  507. X        if (!did_timer())
  508. X            perror ("pause");
  509. X        if (did_timer())
  510. X            perror ("set_timer");
  511. X    }
  512. X}
  513. X
  514. Xsub1(i)
  515. X    char *i;
  516. X{
  517. X    printf ("%d\n", (int)i);
  518. X    set_timer ((int)i, sub2, (char *) ((int)i*2));
  519. X}
  520. X
  521. Xsub2 (i)
  522. X    char *i;
  523. X{
  524. X    printf ("*%d\n", (int)i);
  525. X    set_timer ((int)i/2, sub3, (char *)((int)i+((int)i/2)));
  526. X    if ((int)i < 10)
  527. X        can_timer (sub3, (char *)((int)i+((int)i/2)));
  528. X}
  529. X
  530. Xsub3(i)
  531. X    char *i;
  532. X{
  533. X    printf ("**%d\n", (int)i);
  534. X}
  535. X
  536. Xcatch (i)
  537. X    int i;
  538. X{
  539. X    signal (i, catch);
  540. X}
  541. !FUNKY!STUFF!
  542.