home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume27 / clc / part16 < prev    next >
Encoding:
Text File  |  1993-11-28  |  25.8 KB  |  952 lines

  1. Newsgroups: comp.sources.unix
  2. From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
  3. Subject: v27i122: clc - C Libraries Collection, Part16/20
  4. References: <1.754527080.23891@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
  9. Posting-Number: Volume 27, Issue 122
  10. Archive-Name: clc/part16
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 16 (of 20)."
  19. # Contents:  libs/src/dict/dict.3 libs/src/timer/ostimer.c
  20. # Wrapped by panos@eclipse on Sun Nov 28 14:48:17 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'libs/src/dict/dict.3' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'libs/src/dict/dict.3'\"
  24. else
  25. echo shar: Extracting \"'libs/src/dict/dict.3'\" \(11843 characters\)
  26. sed "s/^X//" >'libs/src/dict/dict.3' <<'END_OF_FILE'
  27. X.\"(c) Copyright 1993 by Panagiotis Tsirigotis
  28. X.\"All rights reserved.  The file named COPYRIGHT specifies the terms 
  29. X.\"and conditions for redistribution.
  30. X.\"
  31. X.\" $Id: dict.3,v 3.4 93/11/23 20:07:28 panos Exp $
  32. X.TH DICT 3X "23 April 1993"
  33. X.SH NAME
  34. Xdictionary management functions
  35. X.SH SYNOPSIS
  36. X.LP
  37. X.nf
  38. X.ft B
  39. X#include "dict.h"
  40. X#include "<lib>.h"
  41. X.LP
  42. X.ft B
  43. Xdict_h <lib>_create( oo_compare, ko_compare, flags, errnop )
  44. Xint (*oo_compare)( dict_obj, dict_obj ) ;
  45. Xint (*ko_compare)( dict_key, dict_obj ) ;
  46. Xint flags ;
  47. Xint *errnop ;
  48. X.LP
  49. X.ft B
  50. Xvoid <lib>_destroy( handle )
  51. Xdict_h handle ;
  52. X.LP
  53. X.ft B
  54. Xint <lib>_insert( handle, object )
  55. Xdict_h handle ;
  56. Xdict_obj object ;
  57. X.LP
  58. X.ft B
  59. Xint <lib>_insert_uniq( handle, object, objectp )
  60. Xdict_h handle ;
  61. Xdict_obj object ;
  62. Xdict_obj *objectp ;
  63. X.LP
  64. X.ft B
  65. Xdict_obj <lib>_search( handle, key )
  66. Xdict_h handle ;
  67. Xdict_key key ;
  68. X.LP
  69. X.ft B
  70. Xint <lib>_delete( handle, object )
  71. Xdict_h handle ;
  72. Xdict_obj object ;
  73. X.LP
  74. X.ft B
  75. Xdict_obj <lib>_minimum( handle )
  76. Xdict_h handle ;
  77. X.LP
  78. X.ft B
  79. Xdict_obj <lib>_maximum( handle )
  80. Xdict_h handle ;
  81. X.LP
  82. X.ft B
  83. Xdict_obj <lib>_successor( handle, object )
  84. Xdict_h handle ;
  85. Xdict_obj object ;
  86. X.LP
  87. X.ft B
  88. Xdict_obj <lib>_predecessor( handle, object )
  89. Xdict_h handle ;
  90. Xdict_obj object ;
  91. X.LP
  92. X.ft B
  93. Xvoid <lib>_iterate( handle, direction )
  94. Xdict_h handle ;
  95. Xenum dict_direction direction ;
  96. X.LP
  97. X.ft B
  98. Xdict_obj <lib>_nextobj( handle )
  99. Xdict_h handle ;
  100. X.LP
  101. X.ft B
  102. Xextern int dict_errno ;
  103. X.SH DESCRIPTION
  104. XThis is a framework for libraries that solve the dictionary problem:
  105. Xinsertion, location, deletion of objects from a set.
  106. XEach library uses a unique prefix in place of
  107. X.I "<lib>_"
  108. Xthat reflects the way it works.
  109. XFor example, the
  110. X.I "binary search tree"
  111. Xlibrary uses the
  112. X.I bst_
  113. Xprefix.
  114. XA dictionary library provides only structure for the objects stored in it.
  115. XIt does not provide storage space.
  116. XTherefore, the
  117. X.I dict_obj
  118. Xand
  119. X.I dict_key
  120. Xtypes are pointer types (the exact pointer type is implementation-dependent).
  121. XThere is no copying of keys. The key is part of the object.
  122. X.LP
  123. XSome dictionary libraries keep the inserted objects ordered. Others
  124. Xmay not support ordering. Others still may support either ordered or
  125. Xunordered objects.
  126. XWhen a library instance is created, the caller
  127. Xcan select between ordered and unordered objects depending on the requirements
  128. Xof the application.
  129. XA request for ordering will be rejected if the library does not support it,
  130. Xbut a request for lack of ordering is usually treated as a hint, and it may 
  131. Xnot be rejected.
  132. X.LP
  133. X.B <lib>_create
  134. Xcreates a library instance and returns a handle to it.
  135. XObject-object comparisons will be required when key uniqueness is requested,
  136. Xor if the library needs to impose an order on the inserted objects.
  137. XSuch comparisons are done using the
  138. X.I oo_compare
  139. Xfunction.
  140. XThis function will be called with two arguments of type
  141. X.I dict_obj,
  142. Xand it should return an integer less-than/equal-to/greater-than 0
  143. Xif the first argument is less-than/equal-to/greater-than the second
  144. Xargument (therefore, it is up to the programmer to define the object ordering).
  145. XIf the library supports the
  146. X.B DICT_UNORDERED
  147. Xflag (which requests that the objects not be ordered), then
  148. Xproviding an
  149. X.I oo_compare
  150. Xfunction is optional.
  151. X.LP
  152. XThe
  153. X.I ko_compare
  154. Xfunction (also specified at the time of library instance creation) is used by
  155. X.B <lib>_search()
  156. Xto locate objects with the specified key value.
  157. XIt will be called with 2 arguments, the first of type
  158. X.I dict_key,
  159. Xand the second of type
  160. X.I dict_obj,
  161. Xand it should return an integer less-than/equal-to/greater-than 0
  162. Xif the specified key (first argument) is less-than/equal-to/greater-than 
  163. Xthe key of the object (second argument). Specifying this function is
  164. Xoptional, but you should note that use of
  165. X.B <lib>_search()
  166. Xwhen this function has not been specified will cause abnormal program
  167. Xtermination.
  168. X.LP
  169. XThe
  170. X.I flags
  171. Xargument is formed by ORing one or more of the following constants:
  172. X.RS
  173. X.TP
  174. X.SB DICT_RETURN_ERROR
  175. XIf a call encounters an error condition, it will return a value that
  176. Xindicates that an error occurred. The default is to terminate the
  177. Xprogram with an appropriate error message. The errors that are
  178. Xhandled this way are usually non-recoverable (for example, lack of
  179. Xmemory), or they are programmer errors.
  180. XErrors like searching for an object that is not in the library instance,
  181. Xor trying to insert an object with a non-unique key value,
  182. Xdo not terminate the program.
  183. X.TP
  184. X.SB DICT_UNIQUE_KEYS
  185. XObjects with equal keys are allowed unless this flag is specified.
  186. XIf objects with equal keys are allowed, it is guaranteed that a
  187. X.B <lib>_search()
  188. Xoperation will locate one of them, and subsequent
  189. X.B <lib>_successor()
  190. Xoperations will return the rest of them.
  191. X.TP
  192. X.SB DICT_UNORDERED
  193. XRequests that inserted objects are not ordered. This request may be
  194. Xrejected if the library requires object ordering.
  195. X.TP
  196. X.SB DICT_ORDERED
  197. XRequests that inserted objects are ordered. This request may be rejected
  198. Xif the library does not support object ordering.
  199. X.RE
  200. X.LP
  201. XSome dictionary library implementations support additional flags.
  202. XSuch flags will be quietly ignored by implementations that don't support them.
  203. XThe constant
  204. X.B DICT_NOFLAGS
  205. Xcan be used to specify no flags.
  206. XThe
  207. X.I errnop
  208. Xargument specifies a location to place error codes when a call fails.
  209. XIf it is specified as
  210. X.I "(int *)0,"
  211. Xthe integer variable
  212. X.I dict_errno
  213. Xwill be used for this purpose.
  214. X.LP
  215. X.B <lib>_destroy()
  216. Xdestroys the library instance identified by the
  217. X.I handle.
  218. X.LP
  219. X.B <lib>_insert()
  220. Xand
  221. X.B <lib>_insert_uniq()
  222. Xare used for object insertions, with the latter requiring that the
  223. Xnew object be unique (in terms of its key).
  224. XIf the 
  225. X.I objectp 
  226. Xargument of 
  227. X.B <lib>_insert_uniq()
  228. Xis not
  229. X.SM NULL
  230. Xthen if the insertion is successful, it will point to
  231. X.I object.
  232. XIf the insertion is not successful because there is already an
  233. Xobject with an equal key value, then
  234. X.I objectp
  235. Xwill point to that object.
  236. X.LP
  237. X.B <lib>_delete()
  238. Xdeletes an object from a library instance.
  239. XIt is not a programmer error if the object does not exist in the library
  240. Xinstance (i.e. the program will not be terminated if the
  241. X.SB DICT_RETURN_ERROR
  242. Xflag is not specified; an error code will always be returned instead).
  243. X.LP
  244. X.B <lib>_search()
  245. Xlocates objects with a key equal to the specified key.
  246. X.LP
  247. XThe action of the 
  248. X.B <lib>_minimum(),
  249. X.B <lib>_maximum(),
  250. X.B <lib>_successor(),
  251. Xand
  252. X.B <lib>_predecessor()
  253. Xoperations depends on whether the library orders the objects stored
  254. Xin it. If it does, then these operations have the meaning denoted by
  255. Xtheir names (although it should be noted that the order is really
  256. Xdefined by the
  257. X.I oo_compare
  258. Xfunction and may not be intuitive).
  259. XIf the objects are stored in any order, then the meaning of these
  260. Xoperations is undefined. However,
  261. Xit is guaranteed that by starting
  262. Xat the object identified by
  263. X.B "<lib>_minimum()"
  264. Xor
  265. X.B "<lib>_maximum(),"
  266. Xand iterating with
  267. X.B "<lib>_successor()"
  268. Xor 
  269. X.B "<lib>_predecessor()"
  270. Xrespectively,
  271. Xall objects stored in the library instance will be enumerated.
  272. X.LP
  273. X.B <lib>_successor()
  274. Xreturns the object that is the successor of the specified
  275. X.I object.
  276. XThe specified object must exist in the library instance
  277. X(non-existence is considered a programmer error).
  278. X.LP
  279. X.B <lib>_predecessor()
  280. Xreturns the object that is the predecessor of the specified  
  281. X.I object.
  282. XThe specified object must exist in the library instance
  283. X(non-existence is considered a programmer error).
  284. X.LP
  285. X.B "<lib>_iterate()"
  286. Xprepares the library instance identified by
  287. X.I handle
  288. Xfor an iteration.
  289. XAssuming a library that orders objects according to non-decreasing key value,
  290. Xif
  291. X.I direction 
  292. Xis
  293. X.I DICT_FROM_START
  294. Xthen the objects will be iterated according to non-decreasing key value,
  295. Xwhile if 
  296. X.I direction 
  297. Xis
  298. X.I DICT_FROM_END
  299. Xthen the objects will be iterated according to non-increasing key value.
  300. XIf the library does not provide any ordering, then the
  301. X.I direction 
  302. Xargument is ignored.
  303. X.LP
  304. X.B "<lib>_nextobj()"
  305. Xreturns the next object.
  306. XThe reason for providing
  307. X.B "<lib>_iterate()"
  308. Xand
  309. X.B "<lib>_nextobj()"
  310. Xis that they are more convenient to use when it is desirable
  311. Xto optionally delete the object returned from
  312. X.B "<lib>_nextobj()"
  313. Xand continue iterating.
  314. X.SH "RETURN VALUES"
  315. X.LP
  316. XFunctions returning handles or objects, return
  317. X.SM NULL
  318. Xif they fail.
  319. X.LP
  320. XFunctions returning \fIint\fRs, return
  321. X.B DICT_OK
  322. Xon success, and
  323. X.B DICT_ERR
  324. Xon failure.
  325. XWhen a call fails, it sets the error variable to an appropriate value.
  326. XThe error variable is either 
  327. X.I dict_errno,
  328. Xor is the one specified in the call to 
  329. X.B <lib>_create()
  330. Xwhich created the given library instance.
  331. X.LP
  332. X.B <lib>_create()
  333. Xreturns a library instance handle if it succeeds, or
  334. X.SM NULL
  335. Xif it fails.
  336. X.LP
  337. X.B <lib>_insert()
  338. Xreturns
  339. X.B DICT_OK
  340. Xif it succeeds, or
  341. X.B DICT_ERR
  342. Xif it fails.
  343. X.LP
  344. X.B <lib>_insert_uniq()
  345. Xreturns 
  346. X.B DICT_OK
  347. Xif it succeeds, or
  348. X.B DICT_ERR
  349. Xif it fails.
  350. X.LP
  351. X.B <lib>_delete()
  352. Xreturns
  353. X.B DICT_OK
  354. Xif it succeeds, or
  355. X.B DICT_ERR
  356. Xif it fails.
  357. X.LP
  358. X.B <lib>_search()
  359. Xreturns an object if it succeeds, or
  360. X.SM NULL
  361. Xif it fails (the error variable is not set in this case as
  362. Xthere is only one explanation for the failure).
  363. X.LP
  364. X.B <lib>_minimum()
  365. Xreturns an object, or
  366. X.SM NULL
  367. Xif there are no objects in the particular library instance.
  368. X.LP
  369. X.B <lib>_maximum()
  370. Xreturns an object, or
  371. X.SM NULL
  372. Xif there are no objects in the particular library instance.
  373. X.LP
  374. X.B <lib>_successor()
  375. X.B "(<lib>_predecessor())"
  376. Xreturns an object, or
  377. X.SM NULL
  378. Xif the specified object has no successor (predecessor),
  379. Xor when the specified object does not exist (assuming the
  380. X.SB DICT_RETURN_ERROR
  381. Xflag was used when the specific library instance was created).
  382. XIn order to discriminate between these two cases, in the former case
  383. Xthe error variable 
  384. X(\fIdict_errno\fP or the one specified when the 
  385. Xspecific library instance was created)
  386. Xwill be set to
  387. X.SB DICT_ENOERROR,
  388. Xand in the latter case it will contain an error code.
  389. X.LP
  390. X.B <lib>_nextobj()
  391. Xreturns an object, or
  392. X.SM NULL
  393. Xif there are no more objects.
  394. X.SH ERRORS
  395. X.LP
  396. XThe following error codes are placed in
  397. X.I dict_errno
  398. Xor in the user-specified error variable.
  399. XError codes marked with "*" cause program termination if the
  400. X.B DICT_RETURN_ERROR
  401. Xflag is not used.
  402. X.IP DICT_ENOERROR 20
  403. XNo error.
  404. X.IP "DICT_ENOMEM *"
  405. XOperation failed because of lack of memory.
  406. X.IP DICT_ENOTFOUND
  407. XObject not found.
  408. X.IP "DICT_ENOOOCOMP *"
  409. XObject-to-object comparator function is missing.
  410. X.\"
  411. X.\" .IP "DICT_ENOKOCOMP *"
  412. X.\" Key-to-object comparator function is missing.
  413. X.\"
  414. X.IP "DICT_ENULLOBJECT *"
  415. XObject is
  416. X.SM NULL.
  417. X.IP DICT_EEXISTS
  418. XObject with equal key exists.
  419. X.IP "DICT_EBADOBJECT *"
  420. XThe object used in a 
  421. X.I "<lib>_successor"
  422. Xor 
  423. X.I "<lib>_predecessor"
  424. Xoperation does not exist.
  425. X.IP "DICT_ENOHVFUNC *"
  426. XThe function to convert a key or object to a hash value is missing.
  427. X.IP "DICT_EBADORDER *"
  428. XBoth the
  429. X.SM DICT_ORDERED
  430. Xand
  431. X.SM DICT_UNORDERED
  432. Xflags were specified.
  433. X.IP "DICT_EORDER"
  434. XThe specified order flag is not supported by the particular library
  435. Ximplementation.
  436. X.SH EXAMPLE
  437. XThe following code fragment reads words from standard input and places them
  438. Xin a set making sure that the set contains no duplicates. At the
  439. Xend-of-file indication, all the words in the set are listed in
  440. Xalphanumeric order. A balanced binary search tree is used to maintain
  441. Xthe set.
  442. X.RS
  443. X.sp 1
  444. X.ft B
  445. X.nf
  446. X#include "bst.h"
  447. X.sp 1
  448. Xdict_h word_set ;
  449. Xchar buf[ 80 ] ;
  450. Xchar *word ;
  451. Xint strcmp() ;
  452. X.sp 1
  453. Xword_set = bst_create( strcmp, strcmp,
  454. X.RS
  455. XDICT_UNIQUE_KEYS + DICT_BALANCED_TREE, (int *)0 ) ;
  456. X.RE
  457. Xwhile ( gets( buf ) )
  458. X{
  459. X.RS
  460. X/*
  461. X * We expect one word per line
  462. X */
  463. Xword = malloc( strlen( buf ) + 1 ) ;
  464. X(void) strcpy( word, buf ) ;
  465. Xif ( bst_insert( word_set, (dict_obj) word ) == DICT_ERR )
  466. X.RS
  467. Xfree( word ) ;
  468. X.RE
  469. X.RE
  470. X}
  471. Xfor ( word = (char *) bst_minimum( word_set ) ; word ;
  472. X.RS
  473. X.RS
  474. Xword = (char *) bst_successor( word_set, word ) )
  475. X.RE
  476. X.RE
  477. X.RS
  478. Xprintf( "%s\\n", word ) ;
  479. X.RE
  480. END_OF_FILE
  481. if test 11843 -ne `wc -c <'libs/src/dict/dict.3'`; then
  482.     echo shar: \"'libs/src/dict/dict.3'\" unpacked with wrong size!
  483. fi
  484. # end of 'libs/src/dict/dict.3'
  485. fi
  486. if test -f 'libs/src/timer/ostimer.c' -a "${1}" != "-c" ; then 
  487.   echo shar: Will not clobber existing file \"'libs/src/timer/ostimer.c'\"
  488. else
  489. echo shar: Extracting \"'libs/src/timer/ostimer.c'\" \(11399 characters\)
  490. sed "s/^X//" >'libs/src/timer/ostimer.c' <<'END_OF_FILE'
  491. X/*
  492. X * (c) Copyright 1993 by Panagiotis Tsirigotis
  493. X * All rights reserved.  The file named COPYRIGHT specifies the terms 
  494. X * and conditions for redistribution.
  495. X */
  496. X
  497. Xstatic char RCSid[] = "$Id: ostimer.c,v 5.1 93/11/26 12:15:00 panos Exp $" ;
  498. X
  499. X#include <stdio.h>
  500. X#include <varargs.h>
  501. X
  502. Xextern int errno ;
  503. X
  504. X#include "timemacros.h"
  505. X#include "defs.h"
  506. X#include "impl.h"
  507. X#include "ostimer.h"
  508. X
  509. X#ifdef DEBUG
  510. X#define DEBUG_REPORT_ERRORS
  511. X#endif
  512. X
  513. X#define OSTIMER_SET( func, otp, itv )                                                        \
  514. X        if ( setitimer( (otp)->ost_systype, &(itv), ITIMERVAL_NULL ) == -1 )        \
  515. X            report( "TIMER %s: setitimer failed. errno = %d\n", func, errno )
  516. X
  517. X#define SET_OSTIMER( otp, itv, func )                                                        \
  518. X    if ( TV_ISZERO( (itv).it_value ) )                                                        \
  519. X        report( "TIMER %s: zero interval\n", func ) ;                                    \
  520. X    else                                                                                                \
  521. X    {                                                                                                    \
  522. X        OSTIMER_SET( func, otp, itv ) ;                                                        \
  523. X    }
  524. X
  525. X
  526. X/* ARGSUSED */
  527. XPRIVATE void report( fmt, va_alist )
  528. X   char *fmt ;
  529. X   va_dcl
  530. X{
  531. X#ifdef DEBUG_REPORT_ERRORS
  532. X   va_list ap ;
  533. X
  534. X   va_start( ap ) ;
  535. X   (void) vfprintf( stderr, fmt, ap ) ;
  536. X#ifdef DEBUG
  537. X   abort() ;
  538. X   _exit( 1 ) ;
  539. X#endif
  540. X#endif   /* DEBUG_REPORT_ERRORS */
  541. X}
  542. X
  543. X/*
  544. X * Initialize the fields of struct timer that are used by the ostimer code
  545. X */
  546. Xint __ostimer_newtimer( tp, type )
  547. X    timer_s                *tp ;
  548. X    enum timer_types    type ;
  549. X{
  550. X    ostimer_s            *otp = __ostimer_init( tp, type ) ;
  551. X
  552. X    if ( otp == OSTIMER_NULL )
  553. X        return( TIMER_ERR ) ;
  554. X
  555. X    tp->t_ostimer = otp ;
  556. X    TV_ZERO( tp->t_expiration ) ;
  557. X    TV_ZERO( tp->t_interval ) ;
  558. X    tp->t_count = 0 ;
  559. X    return( TIMER_OK ) ;
  560. X}
  561. X
  562. X
  563. X
  564. X
  565. X/*
  566. X * The following variables are used to handle the following scenario:
  567. X *
  568. X *        1. INTERRUPT happens ==> ostimer_interrupt called
  569. X *        2. Timers A and B expire.
  570. X *        3. The function associated with A is invoked and running
  571. X *        4. INTERRUPT happens ==> ostimer_interrupt called
  572. X *        5. Timer C expires.
  573. X *        6. Function of timer C invoked and returns with a jmp_buf.
  574. X *
  575. X * If we longjmp to the jmp_buf returned by the function of timer C the 
  576. X * function of timer B will never be called and the function of timer A 
  577. X * will never finish.
  578. X * What we do instead is have ostimer_interrupt check the call_level
  579. X * and if greater than 1, then just save the jmp_buf returned by the
  580. X * function of timer C (only if there is no other ret_env) and simply return.
  581. X *
  582. X * Notice that there can be only one ret_env (since there is only 1 control 
  583. X * flow).
  584. X *
  585. X * XXX:  this complexity stems from the fact that we allow interrupts while
  586. X *            the timer functions are running. Is there a good reason for this ?
  587. X *            (probably because we have to allow interrupts of other timer types).
  588. X */
  589. Xstatic int call_level ;
  590. Xstatic int have_env ;
  591. Xstatic jmp_buf ret_env ;
  592. X
  593. X#define MAX_EXPIRED                    20
  594. X
  595. X/*
  596. X * ostimer_interrupt invokes the functions of the timers that expired.
  597. X * Since we don't know in advance how many timers expired, we follow a
  598. X * two-step procedure:
  599. X *
  600. X *        Step 1: collect all expired timers
  601. X *        Step 2: invoke timer actions
  602. X *
  603. X * The expired timers are collected in an array stored on the stack.
  604. X * If the array overflows, we arrange for another timer interrupt as
  605. X * soon as possible to service remaining timers. The reason we don't
  606. X * allocate the array using malloc is that malloc is not guaranteed
  607. X * to be reentrant and tracking timing-related dynamic memory allocation 
  608. X * problems is guaranteed to be a nightmare.
  609. X *
  610. X * Notice that *all* timer interrupts are blocked during step 1.
  611. X */
  612. Xvoid __ostimer_interrupt( otp )
  613. X    register ostimer_s *otp ;
  614. X{
  615. X    struct timeval        current_time ;
  616. X    register timer_s    *tp ;
  617. X    timer_s                *expired_timers[ MAX_EXPIRED ] ;
  618. X    unsigned                n_expired = 0 ;
  619. X    int                    i ;
  620. X
  621. X    if ( timer_pq_head( otp->ost_timerq.tq_handle ) == TIMER_NULL )
  622. X        return ;
  623. X    
  624. X    call_level++ ;
  625. X    
  626. X    (*otp->ost_get_current_time)( ¤t_time ) ;
  627. X
  628. X    /*
  629. X     * Get all timers that expired
  630. X     */
  631. X    for ( ;; )
  632. X    {
  633. X        tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  634. X
  635. X        if ( tp == TIMER_NULL || TV_GT( tp->t_expiration, current_time ) ||
  636. X                                                                    n_expired == MAX_EXPIRED )
  637. X            break ;
  638. X        
  639. X        tp = timer_pq_extract_head( otp->ost_timerq.tq_handle ) ;
  640. X        if ( tp->t_state == TICKING )
  641. X        {
  642. X            tp->t_state = INACTIVE ;
  643. X
  644. X            tp->t_count++ ;
  645. X            if ( tp->t_blocked )
  646. X            {
  647. X                if ( tp->t_act == IDLE )
  648. X                    tp->t_act = PENDING ;
  649. X                else if ( tp->t_act == INVOKED )
  650. X                    tp->t_act = SCHEDULED ;
  651. X            }
  652. X            else        /* not blocked */
  653. X            {
  654. X                if ( tp->t_act == IDLE || tp->t_act == INVOKED )
  655. X                {
  656. X                    tp->t_act = SCHEDULED ;
  657. X                    expired_timers[ n_expired++ ] = tp ;
  658. X                }
  659. X            }
  660. X        }
  661. X    }
  662. X
  663. X    /*
  664. X     * Check which timers have regular expiration intervals
  665. X     */
  666. X    for ( i = 0 ; i < n_expired ; i++ )
  667. X    {
  668. X        tp = expired_timers[ i ] ;
  669. X
  670. X        if ( ! TV_ISZERO( tp->t_interval ) )
  671. X        {
  672. X            tp->t_state = TICKING ;
  673. X            TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
  674. X            /*
  675. X             * We shouldn't have an insertion problem since we just extracted
  676. X             * the timers from the queue (i.e. there should be enough room)
  677. X             */
  678. X            (void) timer_pq_insert( otp->ost_timerq.tq_handle, tp ) ;
  679. X        }
  680. X    }
  681. X
  682. X    tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  683. X
  684. X    if ( tp != TIMER_NULL )
  685. X    {
  686. X        struct itimerval itv ;
  687. X
  688. X        TV_ZERO( itv.it_interval ) ;
  689. X        /* 
  690. X         * Check if we had too many expired timers
  691. X         */
  692. X        if ( TV_LE( tp->t_expiration, current_time ) )
  693. X        {
  694. X            itv.it_value.tv_sec = 0 ;
  695. X            itv.it_value.tv_usec = 1 ;        /* schedule an interrupt ASAP */
  696. X            /* XXX:    this trick will result in another call to 
  697. X             *            ostimer_interrupt. So why don't we just call it
  698. X             *            recursively, instead of taking another timer interrupt ?
  699. X             */
  700. X        }
  701. X        else
  702. X            TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
  703. X
  704. X        SET_OSTIMER( otp, itv, "ostimer_interrupt" ) ;
  705. X    }
  706. X
  707. X#ifdef DEBUG_MSGS
  708. X   printf( "\t\t%d timers expired\n", n_expired ) ;
  709. X#endif
  710. X
  711. X   /*
  712. X    * Invoke the functions of all expired timers
  713. X     */
  714. X   for ( i = 0 ; i < n_expired ; i++ )
  715. X   {
  716. X      tp = expired_timers[ i ] ;
  717. X        if ( __timer_invoke( tp ) != DESTROYED &&
  718. X                    ! have_env && ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
  719. X        {
  720. X            (void) memcpy( (char *)ret_env,
  721. X                        (char *)tp->t_action.ta_env, sizeof( jmp_buf ) ) ;
  722. X            have_env = TRUE ;
  723. X        }
  724. X   }
  725. X
  726. X    call_level-- ;
  727. X
  728. X    /*
  729. X     * If this is not a recursive call, and there is a jmp_buf, use it.
  730. X     */
  731. X    if ( call_level == 0 && have_env )
  732. X    {
  733. X        have_env = FALSE ;
  734. X        longjmp( ret_env, 1 ) ;
  735. X    }
  736. X}
  737. X
  738. X
  739. X/*
  740. X * Carry out the timer action.
  741. X * If            the call level is 0
  742. X *        AND    there is not already an environment to longjmp to
  743. X *         AND    this timer has such an environment
  744. X *    then
  745. X *        longjmp to that environment
  746. X *
  747. X * Notice that all timer interrupts are blocked while this function is running.
  748. X * Therefore, none of the global variables checked can change.
  749. X */
  750. XPRIVATE void invoke_protocol( tp )
  751. X    timer_s *tp ;
  752. X{
  753. X    if ( __timer_invoke( tp ) != DESTROYED &&
  754. X                    call_level == 0 && ! have_env &&
  755. X                                    ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
  756. X        longjmp( tp->t_action.ta_env, 1 ) ;
  757. X}
  758. X
  759. X
  760. X/*
  761. X * Add a timer to the specified OS timer's queue
  762. X * We assume that the timer already has a valid state and action
  763. X * associated with it.
  764. X * We also assume that no operations (block etc) are applied to the
  765. X * timer while this function is running.
  766. X */
  767. Xint __ostimer_add( otp, tp, itvp, time_type )
  768. X    ostimer_s                *otp ;
  769. X    register timer_s        *tp ;
  770. X    struct itimerval        *itvp ;
  771. X    enum timer_timetypes time_type ;
  772. X{
  773. X    struct timeval        current_time ;
  774. X    int                    expired ;
  775. X
  776. X    /*
  777. X     * While this function (__ostimer_add) is running, this will be our 
  778. X     * notion of the current time.
  779. X     * In reality, there may be some time skew as this function
  780. X     * is running, possibly because of swapping.
  781. X     */
  782. X    (*otp->ost_get_current_time)( ¤t_time ) ;
  783. X
  784. X   /*
  785. X    * Since we use absolute time for our calculations,
  786. X    * convert the user-specified time to that, if necessary
  787. X    *
  788. X    * Also check if the timer has already expired. There are 2 possibilities:
  789. X    *
  790. X    *    1. a zero interval for TIMER_RELATIVE
  791. X    *    2. a time before current time for TIMER_ABSOLUTE
  792. X     *
  793. X     * Note that we always calculate t_expiration in case the user has
  794. X     * specified an it_interval.
  795. X    */
  796. X    
  797. X    if ( time_type == TIMER_RELATIVE )
  798. X    {
  799. X        /*
  800. X         * timer_start has verified that it_value is not negative
  801. X         */
  802. X        TV_ADD( tp->t_expiration, current_time, itvp->it_value ) ;
  803. X        expired = TV_ISZERO( itvp->it_value ) ;
  804. X    }
  805. X    else
  806. X    {
  807. X        tp->t_expiration = itvp->it_value ;
  808. X        expired = TV_LE( tp->t_expiration, current_time ) ;
  809. X    }
  810. X
  811. X    tp->t_interval = itvp->it_interval ;
  812. X
  813. X    if ( expired )
  814. X    {
  815. X        tp->t_count++ ;
  816. X        tp->t_act = SCHEDULED ;
  817. X
  818. X        if ( TV_ISZERO( tp->t_interval ) )
  819. X        {
  820. X            invoke_protocol( tp ) ;
  821. X            return( TIMER_OK ) ;
  822. X        }
  823. X        
  824. X        /*
  825. X         * Keep expiring the timer until it exceeds the current time
  826. X         */
  827. X        time_type = TIMER_ABSOLUTE ;
  828. X        for ( ;; )
  829. X        {
  830. X            TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
  831. X            expired = TV_LE( tp->t_expiration, current_time ) ;
  832. X            if ( ! expired )
  833. X                break ;
  834. X            tp->t_act = SCHEDULED ;
  835. X            tp->t_count++ ;
  836. X        }
  837. X        invoke_protocol( tp ) ;
  838. X    }
  839. X
  840. X    if ( timer_pq_insert( otp->ost_timerq.tq_handle, tp ) == PQ_ERR )
  841. X        HANDLE_ERROR( tp->t_flags, TIMER_ERR, tp->t_errnop, TIMER_ECANTINSERT,
  842. X            "TIMER __ostimer_add: can't insert timer in priority queue\n" ) ;
  843. X
  844. X    tp->t_state = TICKING ;
  845. X
  846. X    /*
  847. X     * Now check if we will need to set the timer again
  848. X     */
  849. X    if ( tp == timer_pq_head( otp->ost_timerq.tq_handle ) )
  850. X    {
  851. X      /*
  852. X       * Check if the user specified relative time.
  853. X       * If so, use the value given (for better accuracy), otherwise compute
  854. X       * a new value.
  855. X       * It is possible that by now the timer that was at the head
  856. X       * of the queue expired and a signal is pending. This can happen
  857. X       * if we are swapped out. The signal handling function will
  858. X       * obviously expire both the new timer and the old one, so our
  859. X       * setting a new timer value may cause a signal at a later time
  860. X       * when the queue is empty. The signal handling function should
  861. X       * be able to deal with an empty queue.
  862. X       */
  863. X        struct itimerval itv ;
  864. X
  865. X        TV_ZERO( itv.it_interval ) ;
  866. X        if ( time_type == TIMER_RELATIVE )
  867. X            itv.it_value = itvp->it_value ;
  868. X        else
  869. X            TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
  870. X        SET_OSTIMER( otp, itv, "__ostimer_add" ) ;
  871. X    }
  872. X
  873. X    return( TIMER_OK ) ;
  874. X}
  875. X
  876. X
  877. X/*
  878. X * Remove the specified timer from the OS timer's queue
  879. X * Timer interrupts should be blocked.
  880. X */
  881. Xvoid __ostimer_remove( otp, tp )
  882. X    ostimer_s    *otp ;
  883. X    timer_s        *tp ;
  884. X{
  885. X    struct itimerval    itv ;
  886. X    struct timeval        current_time ;
  887. X    timer_s                *new_head_timer, *old_head_timer ;
  888. X
  889. X    old_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  890. X    timer_pq_delete( otp->ost_timerq.tq_handle, tp ) ;
  891. X    new_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
  892. X
  893. X    if ( old_head_timer != new_head_timer )
  894. X    {
  895. X        int do_setitimer ;
  896. X
  897. X        if ( new_head_timer != TIMER_NULL )
  898. X        {
  899. X            (*otp->ost_get_current_time)( ¤t_time ) ;
  900. X
  901. X            /*
  902. X             * If the head_timer is less than or equal to the current time, 
  903. X             * the interrupt must be pending, so we leave the OS timer running.
  904. X             * Otherwise, we restart the OS timer.
  905. X             */
  906. X            if ( TV_LE( current_time, new_head_timer->t_expiration ) )
  907. X                do_setitimer = FALSE ;
  908. X            else
  909. X            {
  910. X                do_setitimer = TRUE ;
  911. X                TV_SUB( itv.it_value, new_head_timer->t_expiration, current_time ) ;
  912. X            }
  913. X        }
  914. X        else                /* queue is empty */
  915. X        {
  916. X            do_setitimer = TRUE ;
  917. X            TV_ZERO( itv.it_value ) ;
  918. X        }
  919. X
  920. X        if ( do_setitimer )
  921. X        {
  922. X            TV_ZERO( itv.it_interval ) ;
  923. X            OSTIMER_SET( "__ostimer_remove", otp, itv ) ;
  924. X        }
  925. X    }
  926. X}
  927. X
  928. END_OF_FILE
  929. if test 11399 -ne `wc -c <'libs/src/timer/ostimer.c'`; then
  930.     echo shar: \"'libs/src/timer/ostimer.c'\" unpacked with wrong size!
  931. fi
  932. # end of 'libs/src/timer/ostimer.c'
  933. fi
  934. echo shar: End of archive 16 \(of 20\).
  935. cp /dev/null ark16isdone
  936. MISSING=""
  937. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  938.     if test ! -f ark${I}isdone ; then
  939.     MISSING="${MISSING} ${I}"
  940.     fi
  941. done
  942. if test "${MISSING}" = "" ; then
  943.     echo You have unpacked all 20 archives.
  944.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  945. else
  946.     echo You still need to unpack the following archives:
  947.     echo "        " ${MISSING}
  948. fi
  949. ##  End of shell archive.
  950. exit 0
  951.