home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.unix
- From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
- Subject: v27i122: clc - C Libraries Collection, Part16/20
- References: <1.754527080.23891@gw.home.vix.com>
- Sender: unix-sources-moderator@gw.home.vix.com
- Approved: vixie@gw.home.vix.com
-
- Submitted-By: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
- Posting-Number: Volume 27, Issue 122
- Archive-Name: clc/part16
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 16 (of 20)."
- # Contents: libs/src/dict/dict.3 libs/src/timer/ostimer.c
- # Wrapped by panos@eclipse on Sun Nov 28 14:48:17 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'libs/src/dict/dict.3' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'libs/src/dict/dict.3'\"
- else
- echo shar: Extracting \"'libs/src/dict/dict.3'\" \(11843 characters\)
- sed "s/^X//" >'libs/src/dict/dict.3' <<'END_OF_FILE'
- X.\"(c) Copyright 1993 by Panagiotis Tsirigotis
- X.\"All rights reserved. The file named COPYRIGHT specifies the terms
- X.\"and conditions for redistribution.
- X.\"
- X.\" $Id: dict.3,v 3.4 93/11/23 20:07:28 panos Exp $
- X.TH DICT 3X "23 April 1993"
- X.SH NAME
- Xdictionary management functions
- X.SH SYNOPSIS
- X.LP
- X.nf
- X.ft B
- X#include "dict.h"
- X#include "<lib>.h"
- X.LP
- X.ft B
- Xdict_h <lib>_create( oo_compare, ko_compare, flags, errnop )
- Xint (*oo_compare)( dict_obj, dict_obj ) ;
- Xint (*ko_compare)( dict_key, dict_obj ) ;
- Xint flags ;
- Xint *errnop ;
- X.LP
- X.ft B
- Xvoid <lib>_destroy( handle )
- Xdict_h handle ;
- X.LP
- X.ft B
- Xint <lib>_insert( handle, object )
- Xdict_h handle ;
- Xdict_obj object ;
- X.LP
- X.ft B
- Xint <lib>_insert_uniq( handle, object, objectp )
- Xdict_h handle ;
- Xdict_obj object ;
- Xdict_obj *objectp ;
- X.LP
- X.ft B
- Xdict_obj <lib>_search( handle, key )
- Xdict_h handle ;
- Xdict_key key ;
- X.LP
- X.ft B
- Xint <lib>_delete( handle, object )
- Xdict_h handle ;
- Xdict_obj object ;
- X.LP
- X.ft B
- Xdict_obj <lib>_minimum( handle )
- Xdict_h handle ;
- X.LP
- X.ft B
- Xdict_obj <lib>_maximum( handle )
- Xdict_h handle ;
- X.LP
- X.ft B
- Xdict_obj <lib>_successor( handle, object )
- Xdict_h handle ;
- Xdict_obj object ;
- X.LP
- X.ft B
- Xdict_obj <lib>_predecessor( handle, object )
- Xdict_h handle ;
- Xdict_obj object ;
- X.LP
- X.ft B
- Xvoid <lib>_iterate( handle, direction )
- Xdict_h handle ;
- Xenum dict_direction direction ;
- X.LP
- X.ft B
- Xdict_obj <lib>_nextobj( handle )
- Xdict_h handle ;
- X.LP
- X.ft B
- Xextern int dict_errno ;
- X.SH DESCRIPTION
- XThis is a framework for libraries that solve the dictionary problem:
- Xinsertion, location, deletion of objects from a set.
- XEach library uses a unique prefix in place of
- X.I "<lib>_"
- Xthat reflects the way it works.
- XFor example, the
- X.I "binary search tree"
- Xlibrary uses the
- X.I bst_
- Xprefix.
- XA dictionary library provides only structure for the objects stored in it.
- XIt does not provide storage space.
- XTherefore, the
- X.I dict_obj
- Xand
- X.I dict_key
- Xtypes are pointer types (the exact pointer type is implementation-dependent).
- XThere is no copying of keys. The key is part of the object.
- X.LP
- XSome dictionary libraries keep the inserted objects ordered. Others
- Xmay not support ordering. Others still may support either ordered or
- Xunordered objects.
- XWhen a library instance is created, the caller
- Xcan select between ordered and unordered objects depending on the requirements
- Xof the application.
- XA request for ordering will be rejected if the library does not support it,
- Xbut a request for lack of ordering is usually treated as a hint, and it may
- Xnot be rejected.
- X.LP
- X.B <lib>_create
- Xcreates a library instance and returns a handle to it.
- XObject-object comparisons will be required when key uniqueness is requested,
- Xor if the library needs to impose an order on the inserted objects.
- XSuch comparisons are done using the
- X.I oo_compare
- Xfunction.
- XThis function will be called with two arguments of type
- X.I dict_obj,
- Xand it should return an integer less-than/equal-to/greater-than 0
- Xif the first argument is less-than/equal-to/greater-than the second
- Xargument (therefore, it is up to the programmer to define the object ordering).
- XIf the library supports the
- X.B DICT_UNORDERED
- Xflag (which requests that the objects not be ordered), then
- Xproviding an
- X.I oo_compare
- Xfunction is optional.
- X.LP
- XThe
- X.I ko_compare
- Xfunction (also specified at the time of library instance creation) is used by
- X.B <lib>_search()
- Xto locate objects with the specified key value.
- XIt will be called with 2 arguments, the first of type
- X.I dict_key,
- Xand the second of type
- X.I dict_obj,
- Xand it should return an integer less-than/equal-to/greater-than 0
- Xif the specified key (first argument) is less-than/equal-to/greater-than
- Xthe key of the object (second argument). Specifying this function is
- Xoptional, but you should note that use of
- X.B <lib>_search()
- Xwhen this function has not been specified will cause abnormal program
- Xtermination.
- X.LP
- XThe
- X.I flags
- Xargument is formed by ORing one or more of the following constants:
- X.RS
- X.TP
- X.SB DICT_RETURN_ERROR
- XIf a call encounters an error condition, it will return a value that
- Xindicates that an error occurred. The default is to terminate the
- Xprogram with an appropriate error message. The errors that are
- Xhandled this way are usually non-recoverable (for example, lack of
- Xmemory), or they are programmer errors.
- XErrors like searching for an object that is not in the library instance,
- Xor trying to insert an object with a non-unique key value,
- Xdo not terminate the program.
- X.TP
- X.SB DICT_UNIQUE_KEYS
- XObjects with equal keys are allowed unless this flag is specified.
- XIf objects with equal keys are allowed, it is guaranteed that a
- X.B <lib>_search()
- Xoperation will locate one of them, and subsequent
- X.B <lib>_successor()
- Xoperations will return the rest of them.
- X.TP
- X.SB DICT_UNORDERED
- XRequests that inserted objects are not ordered. This request may be
- Xrejected if the library requires object ordering.
- X.TP
- X.SB DICT_ORDERED
- XRequests that inserted objects are ordered. This request may be rejected
- Xif the library does not support object ordering.
- X.RE
- X.LP
- XSome dictionary library implementations support additional flags.
- XSuch flags will be quietly ignored by implementations that don't support them.
- XThe constant
- X.B DICT_NOFLAGS
- Xcan be used to specify no flags.
- XThe
- X.I errnop
- Xargument specifies a location to place error codes when a call fails.
- XIf it is specified as
- X.I "(int *)0,"
- Xthe integer variable
- X.I dict_errno
- Xwill be used for this purpose.
- X.LP
- X.B <lib>_destroy()
- Xdestroys the library instance identified by the
- X.I handle.
- X.LP
- X.B <lib>_insert()
- Xand
- X.B <lib>_insert_uniq()
- Xare used for object insertions, with the latter requiring that the
- Xnew object be unique (in terms of its key).
- XIf the
- X.I objectp
- Xargument of
- X.B <lib>_insert_uniq()
- Xis not
- X.SM NULL
- Xthen if the insertion is successful, it will point to
- X.I object.
- XIf the insertion is not successful because there is already an
- Xobject with an equal key value, then
- X.I objectp
- Xwill point to that object.
- X.LP
- X.B <lib>_delete()
- Xdeletes an object from a library instance.
- XIt is not a programmer error if the object does not exist in the library
- Xinstance (i.e. the program will not be terminated if the
- X.SB DICT_RETURN_ERROR
- Xflag is not specified; an error code will always be returned instead).
- X.LP
- X.B <lib>_search()
- Xlocates objects with a key equal to the specified key.
- X.LP
- XThe action of the
- X.B <lib>_minimum(),
- X.B <lib>_maximum(),
- X.B <lib>_successor(),
- Xand
- X.B <lib>_predecessor()
- Xoperations depends on whether the library orders the objects stored
- Xin it. If it does, then these operations have the meaning denoted by
- Xtheir names (although it should be noted that the order is really
- Xdefined by the
- X.I oo_compare
- Xfunction and may not be intuitive).
- XIf the objects are stored in any order, then the meaning of these
- Xoperations is undefined. However,
- Xit is guaranteed that by starting
- Xat the object identified by
- X.B "<lib>_minimum()"
- Xor
- X.B "<lib>_maximum(),"
- Xand iterating with
- X.B "<lib>_successor()"
- Xor
- X.B "<lib>_predecessor()"
- Xrespectively,
- Xall objects stored in the library instance will be enumerated.
- X.LP
- X.B <lib>_successor()
- Xreturns the object that is the successor of the specified
- X.I object.
- XThe specified object must exist in the library instance
- X(non-existence is considered a programmer error).
- X.LP
- X.B <lib>_predecessor()
- Xreturns the object that is the predecessor of the specified
- X.I object.
- XThe specified object must exist in the library instance
- X(non-existence is considered a programmer error).
- X.LP
- X.B "<lib>_iterate()"
- Xprepares the library instance identified by
- X.I handle
- Xfor an iteration.
- XAssuming a library that orders objects according to non-decreasing key value,
- Xif
- X.I direction
- Xis
- X.I DICT_FROM_START
- Xthen the objects will be iterated according to non-decreasing key value,
- Xwhile if
- X.I direction
- Xis
- X.I DICT_FROM_END
- Xthen the objects will be iterated according to non-increasing key value.
- XIf the library does not provide any ordering, then the
- X.I direction
- Xargument is ignored.
- X.LP
- X.B "<lib>_nextobj()"
- Xreturns the next object.
- XThe reason for providing
- X.B "<lib>_iterate()"
- Xand
- X.B "<lib>_nextobj()"
- Xis that they are more convenient to use when it is desirable
- Xto optionally delete the object returned from
- X.B "<lib>_nextobj()"
- Xand continue iterating.
- X.SH "RETURN VALUES"
- X.LP
- XFunctions returning handles or objects, return
- X.SM NULL
- Xif they fail.
- X.LP
- XFunctions returning \fIint\fRs, return
- X.B DICT_OK
- Xon success, and
- X.B DICT_ERR
- Xon failure.
- XWhen a call fails, it sets the error variable to an appropriate value.
- XThe error variable is either
- X.I dict_errno,
- Xor is the one specified in the call to
- X.B <lib>_create()
- Xwhich created the given library instance.
- X.LP
- X.B <lib>_create()
- Xreturns a library instance handle if it succeeds, or
- X.SM NULL
- Xif it fails.
- X.LP
- X.B <lib>_insert()
- Xreturns
- X.B DICT_OK
- Xif it succeeds, or
- X.B DICT_ERR
- Xif it fails.
- X.LP
- X.B <lib>_insert_uniq()
- Xreturns
- X.B DICT_OK
- Xif it succeeds, or
- X.B DICT_ERR
- Xif it fails.
- X.LP
- X.B <lib>_delete()
- Xreturns
- X.B DICT_OK
- Xif it succeeds, or
- X.B DICT_ERR
- Xif it fails.
- X.LP
- X.B <lib>_search()
- Xreturns an object if it succeeds, or
- X.SM NULL
- Xif it fails (the error variable is not set in this case as
- Xthere is only one explanation for the failure).
- X.LP
- X.B <lib>_minimum()
- Xreturns an object, or
- X.SM NULL
- Xif there are no objects in the particular library instance.
- X.LP
- X.B <lib>_maximum()
- Xreturns an object, or
- X.SM NULL
- Xif there are no objects in the particular library instance.
- X.LP
- X.B <lib>_successor()
- X.B "(<lib>_predecessor())"
- Xreturns an object, or
- X.SM NULL
- Xif the specified object has no successor (predecessor),
- Xor when the specified object does not exist (assuming the
- X.SB DICT_RETURN_ERROR
- Xflag was used when the specific library instance was created).
- XIn order to discriminate between these two cases, in the former case
- Xthe error variable
- X(\fIdict_errno\fP or the one specified when the
- Xspecific library instance was created)
- Xwill be set to
- X.SB DICT_ENOERROR,
- Xand in the latter case it will contain an error code.
- X.LP
- X.B <lib>_nextobj()
- Xreturns an object, or
- X.SM NULL
- Xif there are no more objects.
- X.SH ERRORS
- X.LP
- XThe following error codes are placed in
- X.I dict_errno
- Xor in the user-specified error variable.
- XError codes marked with "*" cause program termination if the
- X.B DICT_RETURN_ERROR
- Xflag is not used.
- X.IP DICT_ENOERROR 20
- XNo error.
- X.IP "DICT_ENOMEM *"
- XOperation failed because of lack of memory.
- X.IP DICT_ENOTFOUND
- XObject not found.
- X.IP "DICT_ENOOOCOMP *"
- XObject-to-object comparator function is missing.
- X.\"
- X.\" .IP "DICT_ENOKOCOMP *"
- X.\" Key-to-object comparator function is missing.
- X.\"
- X.IP "DICT_ENULLOBJECT *"
- XObject is
- X.SM NULL.
- X.IP DICT_EEXISTS
- XObject with equal key exists.
- X.IP "DICT_EBADOBJECT *"
- XThe object used in a
- X.I "<lib>_successor"
- Xor
- X.I "<lib>_predecessor"
- Xoperation does not exist.
- X.IP "DICT_ENOHVFUNC *"
- XThe function to convert a key or object to a hash value is missing.
- X.IP "DICT_EBADORDER *"
- XBoth the
- X.SM DICT_ORDERED
- Xand
- X.SM DICT_UNORDERED
- Xflags were specified.
- X.IP "DICT_EORDER"
- XThe specified order flag is not supported by the particular library
- Ximplementation.
- X.SH EXAMPLE
- XThe following code fragment reads words from standard input and places them
- Xin a set making sure that the set contains no duplicates. At the
- Xend-of-file indication, all the words in the set are listed in
- Xalphanumeric order. A balanced binary search tree is used to maintain
- Xthe set.
- X.RS
- X.sp 1
- X.ft B
- X.nf
- X#include "bst.h"
- X.sp 1
- Xdict_h word_set ;
- Xchar buf[ 80 ] ;
- Xchar *word ;
- Xint strcmp() ;
- X.sp 1
- Xword_set = bst_create( strcmp, strcmp,
- X.RS
- XDICT_UNIQUE_KEYS + DICT_BALANCED_TREE, (int *)0 ) ;
- X.RE
- Xwhile ( gets( buf ) )
- X{
- X.RS
- X/*
- X * We expect one word per line
- X */
- Xword = malloc( strlen( buf ) + 1 ) ;
- X(void) strcpy( word, buf ) ;
- Xif ( bst_insert( word_set, (dict_obj) word ) == DICT_ERR )
- X.RS
- Xfree( word ) ;
- X.RE
- X.RE
- X}
- Xfor ( word = (char *) bst_minimum( word_set ) ; word ;
- X.RS
- X.RS
- Xword = (char *) bst_successor( word_set, word ) )
- X.RE
- X.RE
- X.RS
- Xprintf( "%s\\n", word ) ;
- X.RE
- END_OF_FILE
- if test 11843 -ne `wc -c <'libs/src/dict/dict.3'`; then
- echo shar: \"'libs/src/dict/dict.3'\" unpacked with wrong size!
- fi
- # end of 'libs/src/dict/dict.3'
- fi
- if test -f 'libs/src/timer/ostimer.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'libs/src/timer/ostimer.c'\"
- else
- echo shar: Extracting \"'libs/src/timer/ostimer.c'\" \(11399 characters\)
- sed "s/^X//" >'libs/src/timer/ostimer.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1993 by Panagiotis Tsirigotis
- X * All rights reserved. The file named COPYRIGHT specifies the terms
- X * and conditions for redistribution.
- X */
- X
- Xstatic char RCSid[] = "$Id: ostimer.c,v 5.1 93/11/26 12:15:00 panos Exp $" ;
- X
- X#include <stdio.h>
- X#include <varargs.h>
- X
- Xextern int errno ;
- X
- X#include "timemacros.h"
- X#include "defs.h"
- X#include "impl.h"
- X#include "ostimer.h"
- X
- X#ifdef DEBUG
- X#define DEBUG_REPORT_ERRORS
- X#endif
- X
- X#define OSTIMER_SET( func, otp, itv ) \
- X if ( setitimer( (otp)->ost_systype, &(itv), ITIMERVAL_NULL ) == -1 ) \
- X report( "TIMER %s: setitimer failed. errno = %d\n", func, errno )
- X
- X#define SET_OSTIMER( otp, itv, func ) \
- X if ( TV_ISZERO( (itv).it_value ) ) \
- X report( "TIMER %s: zero interval\n", func ) ; \
- X else \
- X { \
- X OSTIMER_SET( func, otp, itv ) ; \
- X }
- X
- X
- X/* ARGSUSED */
- XPRIVATE void report( fmt, va_alist )
- X char *fmt ;
- X va_dcl
- X{
- X#ifdef DEBUG_REPORT_ERRORS
- X va_list ap ;
- X
- X va_start( ap ) ;
- X (void) vfprintf( stderr, fmt, ap ) ;
- X#ifdef DEBUG
- X abort() ;
- X _exit( 1 ) ;
- X#endif
- X#endif /* DEBUG_REPORT_ERRORS */
- X}
- X
- X
- X/*
- X * Initialize the fields of struct timer that are used by the ostimer code
- X */
- Xint __ostimer_newtimer( tp, type )
- X timer_s *tp ;
- X enum timer_types type ;
- X{
- X ostimer_s *otp = __ostimer_init( tp, type ) ;
- X
- X if ( otp == OSTIMER_NULL )
- X return( TIMER_ERR ) ;
- X
- X tp->t_ostimer = otp ;
- X TV_ZERO( tp->t_expiration ) ;
- X TV_ZERO( tp->t_interval ) ;
- X tp->t_count = 0 ;
- X return( TIMER_OK ) ;
- X}
- X
- X
- X
- X
- X/*
- X * The following variables are used to handle the following scenario:
- X *
- X * 1. INTERRUPT happens ==> ostimer_interrupt called
- X * 2. Timers A and B expire.
- X * 3. The function associated with A is invoked and running
- X * 4. INTERRUPT happens ==> ostimer_interrupt called
- X * 5. Timer C expires.
- X * 6. Function of timer C invoked and returns with a jmp_buf.
- X *
- X * If we longjmp to the jmp_buf returned by the function of timer C the
- X * function of timer B will never be called and the function of timer A
- X * will never finish.
- X * What we do instead is have ostimer_interrupt check the call_level
- X * and if greater than 1, then just save the jmp_buf returned by the
- X * function of timer C (only if there is no other ret_env) and simply return.
- X *
- X * Notice that there can be only one ret_env (since there is only 1 control
- X * flow).
- X *
- X * XXX: this complexity stems from the fact that we allow interrupts while
- X * the timer functions are running. Is there a good reason for this ?
- X * (probably because we have to allow interrupts of other timer types).
- X */
- Xstatic int call_level ;
- Xstatic int have_env ;
- Xstatic jmp_buf ret_env ;
- X
- X#define MAX_EXPIRED 20
- X
- X/*
- X * ostimer_interrupt invokes the functions of the timers that expired.
- X * Since we don't know in advance how many timers expired, we follow a
- X * two-step procedure:
- X *
- X * Step 1: collect all expired timers
- X * Step 2: invoke timer actions
- X *
- X * The expired timers are collected in an array stored on the stack.
- X * If the array overflows, we arrange for another timer interrupt as
- X * soon as possible to service remaining timers. The reason we don't
- X * allocate the array using malloc is that malloc is not guaranteed
- X * to be reentrant and tracking timing-related dynamic memory allocation
- X * problems is guaranteed to be a nightmare.
- X *
- X * Notice that *all* timer interrupts are blocked during step 1.
- X */
- Xvoid __ostimer_interrupt( otp )
- X register ostimer_s *otp ;
- X{
- X struct timeval current_time ;
- X register timer_s *tp ;
- X timer_s *expired_timers[ MAX_EXPIRED ] ;
- X unsigned n_expired = 0 ;
- X int i ;
- X
- X if ( timer_pq_head( otp->ost_timerq.tq_handle ) == TIMER_NULL )
- X return ;
- X
- X call_level++ ;
- X
- X (*otp->ost_get_current_time)( ¤t_time ) ;
- X
- X /*
- X * Get all timers that expired
- X */
- X for ( ;; )
- X {
- X tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
- X
- X if ( tp == TIMER_NULL || TV_GT( tp->t_expiration, current_time ) ||
- X n_expired == MAX_EXPIRED )
- X break ;
- X
- X tp = timer_pq_extract_head( otp->ost_timerq.tq_handle ) ;
- X if ( tp->t_state == TICKING )
- X {
- X tp->t_state = INACTIVE ;
- X
- X tp->t_count++ ;
- X if ( tp->t_blocked )
- X {
- X if ( tp->t_act == IDLE )
- X tp->t_act = PENDING ;
- X else if ( tp->t_act == INVOKED )
- X tp->t_act = SCHEDULED ;
- X }
- X else /* not blocked */
- X {
- X if ( tp->t_act == IDLE || tp->t_act == INVOKED )
- X {
- X tp->t_act = SCHEDULED ;
- X expired_timers[ n_expired++ ] = tp ;
- X }
- X }
- X }
- X }
- X
- X /*
- X * Check which timers have regular expiration intervals
- X */
- X for ( i = 0 ; i < n_expired ; i++ )
- X {
- X tp = expired_timers[ i ] ;
- X
- X if ( ! TV_ISZERO( tp->t_interval ) )
- X {
- X tp->t_state = TICKING ;
- X TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
- X /*
- X * We shouldn't have an insertion problem since we just extracted
- X * the timers from the queue (i.e. there should be enough room)
- X */
- X (void) timer_pq_insert( otp->ost_timerq.tq_handle, tp ) ;
- X }
- X }
- X
- X tp = timer_pq_head( otp->ost_timerq.tq_handle ) ;
- X
- X if ( tp != TIMER_NULL )
- X {
- X struct itimerval itv ;
- X
- X TV_ZERO( itv.it_interval ) ;
- X /*
- X * Check if we had too many expired timers
- X */
- X if ( TV_LE( tp->t_expiration, current_time ) )
- X {
- X itv.it_value.tv_sec = 0 ;
- X itv.it_value.tv_usec = 1 ; /* schedule an interrupt ASAP */
- X /* XXX: this trick will result in another call to
- X * ostimer_interrupt. So why don't we just call it
- X * recursively, instead of taking another timer interrupt ?
- X */
- X }
- X else
- X TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
- X
- X SET_OSTIMER( otp, itv, "ostimer_interrupt" ) ;
- X }
- X
- X#ifdef DEBUG_MSGS
- X printf( "\t\t%d timers expired\n", n_expired ) ;
- X#endif
- X
- X /*
- X * Invoke the functions of all expired timers
- X */
- X for ( i = 0 ; i < n_expired ; i++ )
- X {
- X tp = expired_timers[ i ] ;
- X if ( __timer_invoke( tp ) != DESTROYED &&
- X ! have_env && ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
- X {
- X (void) memcpy( (char *)ret_env,
- X (char *)tp->t_action.ta_env, sizeof( jmp_buf ) ) ;
- X have_env = TRUE ;
- X }
- X }
- X
- X call_level-- ;
- X
- X /*
- X * If this is not a recursive call, and there is a jmp_buf, use it.
- X */
- X if ( call_level == 0 && have_env )
- X {
- X have_env = FALSE ;
- X longjmp( ret_env, 1 ) ;
- X }
- X}
- X
- X
- X/*
- X * Carry out the timer action.
- X * If the call level is 0
- X * AND there is not already an environment to longjmp to
- X * AND this timer has such an environment
- X * then
- X * longjmp to that environment
- X *
- X * Notice that all timer interrupts are blocked while this function is running.
- X * Therefore, none of the global variables checked can change.
- X */
- XPRIVATE void invoke_protocol( tp )
- X timer_s *tp ;
- X{
- X if ( __timer_invoke( tp ) != DESTROYED &&
- X call_level == 0 && ! have_env &&
- X ( tp->t_action.ta_flags & TIMER_LONGJMP ) )
- X longjmp( tp->t_action.ta_env, 1 ) ;
- X}
- X
- X
- X/*
- X * Add a timer to the specified OS timer's queue
- X * We assume that the timer already has a valid state and action
- X * associated with it.
- X * We also assume that no operations (block etc) are applied to the
- X * timer while this function is running.
- X */
- Xint __ostimer_add( otp, tp, itvp, time_type )
- X ostimer_s *otp ;
- X register timer_s *tp ;
- X struct itimerval *itvp ;
- X enum timer_timetypes time_type ;
- X{
- X struct timeval current_time ;
- X int expired ;
- X
- X /*
- X * While this function (__ostimer_add) is running, this will be our
- X * notion of the current time.
- X * In reality, there may be some time skew as this function
- X * is running, possibly because of swapping.
- X */
- X (*otp->ost_get_current_time)( ¤t_time ) ;
- X
- X /*
- X * Since we use absolute time for our calculations,
- X * convert the user-specified time to that, if necessary
- X *
- X * Also check if the timer has already expired. There are 2 possibilities:
- X *
- X * 1. a zero interval for TIMER_RELATIVE
- X * 2. a time before current time for TIMER_ABSOLUTE
- X *
- X * Note that we always calculate t_expiration in case the user has
- X * specified an it_interval.
- X */
- X
- X if ( time_type == TIMER_RELATIVE )
- X {
- X /*
- X * timer_start has verified that it_value is not negative
- X */
- X TV_ADD( tp->t_expiration, current_time, itvp->it_value ) ;
- X expired = TV_ISZERO( itvp->it_value ) ;
- X }
- X else
- X {
- X tp->t_expiration = itvp->it_value ;
- X expired = TV_LE( tp->t_expiration, current_time ) ;
- X }
- X
- X tp->t_interval = itvp->it_interval ;
- X
- X if ( expired )
- X {
- X tp->t_count++ ;
- X tp->t_act = SCHEDULED ;
- X
- X if ( TV_ISZERO( tp->t_interval ) )
- X {
- X invoke_protocol( tp ) ;
- X return( TIMER_OK ) ;
- X }
- X
- X /*
- X * Keep expiring the timer until it exceeds the current time
- X */
- X time_type = TIMER_ABSOLUTE ;
- X for ( ;; )
- X {
- X TV_ADD( tp->t_expiration, tp->t_expiration, tp->t_interval ) ;
- X expired = TV_LE( tp->t_expiration, current_time ) ;
- X if ( ! expired )
- X break ;
- X tp->t_act = SCHEDULED ;
- X tp->t_count++ ;
- X }
- X invoke_protocol( tp ) ;
- X }
- X
- X if ( timer_pq_insert( otp->ost_timerq.tq_handle, tp ) == PQ_ERR )
- X HANDLE_ERROR( tp->t_flags, TIMER_ERR, tp->t_errnop, TIMER_ECANTINSERT,
- X "TIMER __ostimer_add: can't insert timer in priority queue\n" ) ;
- X
- X tp->t_state = TICKING ;
- X
- X /*
- X * Now check if we will need to set the timer again
- X */
- X if ( tp == timer_pq_head( otp->ost_timerq.tq_handle ) )
- X {
- X /*
- X * Check if the user specified relative time.
- X * If so, use the value given (for better accuracy), otherwise compute
- X * a new value.
- X * It is possible that by now the timer that was at the head
- X * of the queue expired and a signal is pending. This can happen
- X * if we are swapped out. The signal handling function will
- X * obviously expire both the new timer and the old one, so our
- X * setting a new timer value may cause a signal at a later time
- X * when the queue is empty. The signal handling function should
- X * be able to deal with an empty queue.
- X */
- X struct itimerval itv ;
- X
- X TV_ZERO( itv.it_interval ) ;
- X if ( time_type == TIMER_RELATIVE )
- X itv.it_value = itvp->it_value ;
- X else
- X TV_SUB( itv.it_value, tp->t_expiration, current_time ) ;
- X SET_OSTIMER( otp, itv, "__ostimer_add" ) ;
- X }
- X
- X return( TIMER_OK ) ;
- X}
- X
- X
- X/*
- X * Remove the specified timer from the OS timer's queue
- X * Timer interrupts should be blocked.
- X */
- Xvoid __ostimer_remove( otp, tp )
- X ostimer_s *otp ;
- X timer_s *tp ;
- X{
- X struct itimerval itv ;
- X struct timeval current_time ;
- X timer_s *new_head_timer, *old_head_timer ;
- X
- X old_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
- X timer_pq_delete( otp->ost_timerq.tq_handle, tp ) ;
- X new_head_timer = timer_pq_head( otp->ost_timerq.tq_handle ) ;
- X
- X if ( old_head_timer != new_head_timer )
- X {
- X int do_setitimer ;
- X
- X if ( new_head_timer != TIMER_NULL )
- X {
- X (*otp->ost_get_current_time)( ¤t_time ) ;
- X
- X /*
- X * If the head_timer is less than or equal to the current time,
- X * the interrupt must be pending, so we leave the OS timer running.
- X * Otherwise, we restart the OS timer.
- X */
- X if ( TV_LE( current_time, new_head_timer->t_expiration ) )
- X do_setitimer = FALSE ;
- X else
- X {
- X do_setitimer = TRUE ;
- X TV_SUB( itv.it_value, new_head_timer->t_expiration, current_time ) ;
- X }
- X }
- X else /* queue is empty */
- X {
- X do_setitimer = TRUE ;
- X TV_ZERO( itv.it_value ) ;
- X }
- X
- X if ( do_setitimer )
- X {
- X TV_ZERO( itv.it_interval ) ;
- X OSTIMER_SET( "__ostimer_remove", otp, itv ) ;
- X }
- X }
- X}
- X
- END_OF_FILE
- if test 11399 -ne `wc -c <'libs/src/timer/ostimer.c'`; then
- echo shar: \"'libs/src/timer/ostimer.c'\" unpacked with wrong size!
- fi
- # end of 'libs/src/timer/ostimer.c'
- fi
- echo shar: End of archive 16 \(of 20\).
- cp /dev/null ark16isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 20 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-