[ntp:hackers] Patches to reinstate rank variable and add end keyword.

Paul Vixie paul at vix.com
Sat Aug 6 21:01:15 UTC 2005


dave, you asked:

# Is this portable to Windows, VMS or Cray?

yes.

(it's ultimately just a wrapper around select, poll, and I/O completion ports.)

# Is it POSIX compliant?

yes.

(it's not part of the POSIX API, but it can be used on pure-POSIX systems.)

# Is it compatible with the copyright statement?

yes.

(you can't remove its copyright statement, and you can't sue ISC, but you can
make copies, modify them or not, distribute them or not, for fee or not... it
is NOT more restraintive than your current license... and if you wish, ISC
will generate a special license for UDel if the one we have doesn't suit you.)

# Does it require prior installation in the system like OpenSSL? That last
# would be a killer if I assigned some NTP as a class project on our campus
# machines.

it's native on freebsd.  otherwise you have to install BIND (8 or 9) first,
or you have to include a copy of it inside NTP.  no big deal either way.  i've
put a copy of the relevant source files at

	http://sa.vix.com/~vixie/isclibs.shar

for your review.

paul

re:

# Paul Vixie wrote:
# 
# > # > I don't care about how to implement an asynchronous resolver and
# > forking
# > # > is fine with me. That's the way the code used to do it and somebody
# > took
# > # > it out.
# > #
# > # Dave, that's not true. That code is still there.
# >
# > then forget my note about popen(), plz, and reenable the old fork()-based
# > asynchronous resolver, and we'll proceed as though this problem was solved
# > (rather than worked around).
# >
# > # The current proposal is to port the ISC's BIND 8 eventlib code (though I
# > # think it originated from somewhere else, Paul can tell you for sure) and
# > # use that to handle the asynchonous resolver issues.
# >
# > that's not the current proposal. the current proposal is to rip select()
# > out of ntpd's mainline and convert all of ntpd to use ISC eventlib so that
# > ntpd's asynchrony can be portable. at which point it's a trivial matter
# > for me to come up with an asynchronous resolver that fits that framework.
# > (an asynchronous resolver needs multiple file descriptors, plus the
# > ability to open tcp sockets and wait for them to complete, plus multiple
# > timers; ISC eventlib provides all of this, portably; ntpd's mainline
# > provides all of this, non-portably.)
# >
# > and ISC eventlib originated with me, not from anywhere else. there's a
# > huge API debt owed by eventlib to MIT-X11-Xt and DEC-SRC-Modula3, but no
# > source code except what i wrote originally, and what bob halley rewrote,
# > and various bug fixes over the years. here's a copy of the freebsd version
# > of the man page for this library. i'll repeat my earlier offer to convert
# > ntpd to this asynchrony framework, assuming that poul henning-kamp will
# > help me.  i'll also repeat my earlier offer to release an asynchronous
# > resolver that lives within this framework, if ntpd is successfully
# > converted to this framework.
# >
# > ---
# >
# > EVENTLIB(3) FreeBSD Library Functions Manual EVENTLIB(3)
# >
# > NAME
# > evConnFunc, evFileFunc, evStreamFunc, evTimerFunc, evWaitFunc, evCreate,
# > evDestroy, evGetNext, evDispatch, evDrop, evMainLoop, evConsTime,
# > evTimeSpec, evTimeVal, evAddTime, evSubTime, evCmpTime, evNowTime,
# > evLastEventTime, evSetTimer, evResetTimer, evClearTimer, evSetIdleTimer,
# > evTouchIdleTimer, evClearIdleTimer, evWaitFor, evDo, evUnwait, evDefer,
# > evSelectFD, evDeselectFD, evWrite, evRead, evCancelRW, evTimeRW,
# > evUntimeRW, evListen, evConnect, evCancelConn, evHold, evUnhold,
# > evTryAccept, evConsIovec, evSetDebug, evPrintf, evInitID, evTestID --
# > event handling library
# >
# > SYNOPSIS
# > #include <isc/eventlib.h>
# >
# > typedef void
# > (*evConnFunc)(evContext ctx, void *uap, int fd, const void *la,
# > int lalen, const void *ra, int ralen);
# >
# > typedef void
# > (*evTimerFunc)(evContext ctx, void *uap, struct timespec due,
# > struct timespec inter);
# >
# > typedef void
# > (*evFileFunc)(evContext ctx, void *uap, int fd, int eventmask);
# >
# > typedef void
# > (*evStreamFunc)(evContext ctx, void *uap, int fd, int bytes);
# >
# > typedef void
# > (*evWaitFunc)(evContext ctx, void *uap, const void *tag);
# >
# > int
# > evCreate(evContext *ctx);
# >
# > int
# > evDestroy(evContext ctx);
# >
# > int
# > evGetNext(evContext ctx, evEvent *ev, int options);
# >
# > int
# > evDispatch(evContext ctx, evEvent ev);
# >
# > void
# > evDrop(evContext ctx, evEvent ev);
# >
# > int
# > evMainLoop(evContext ctx);
# >
# > struct timespec
# > evConsTime(int sec, int usec);
# >
# > struct timespec
# > evTimeSpec(struct timeval tv);
# >
# > struct timeval
# > evTimeVal(struct timespec ts);
# >
# > struct timespec
# > evAddTime(struct timespec addend1, struct timespec addend2);
# >
# > struct timespec
# > evSubTime(struct timespec minuend, struct timespec subtrahend);
# >
# > struct timespec
# > evCmpTime(struct timespec a, struct timespec b);
# >
# > struct timespec
# > evNowTime(void);
# >
# > struct timespec
# > evLastEventTime(evContext opaqueCtx);
# >
# > int
# > evSetTimer(evContext ctx, evTimerFunc func, void *uap,
# > struct timespec due, struct timespec inter, evTimerID *id);
# >
# > int
# > evResetTimer(evContext ctx, evTimerID id, evTimerFunc func, void *uap,
# > struct timespec due, struct timespec inter);
# >
# > int
# > evClearTimer(evContext ctx, evTimerID id);
# >
# > int
# > evSetIdleTimer(evContext opaqueCtx, evTimerFunc func, void *uap,
# > struct timespec max_idle, evTimerID *opaqueID);
# >
# > int
# > evTouchIdleTimer(evContext opaqueCtx, evTimerID id);
# >
# > int
# > evResetIdleTimer(evContext opaqueCtx, evTimerID id, evTimerFunc func,
# > void *uap, struct timespec max_idle);
# >
# > int
# > evClearIdleTimer(evContext opaqueCtx, evTimerID id);
# >
# > int
# > evWaitFor(evContext opaqueCtx, const void *tag, evWaitFunc func,
# > void *uap, evWaitID *id);
# >
# > int
# > evDo(evContext opaqueCtx, const void *tag);
# >
# > int
# > evUnwait(evContext opaqueCtx, evWaitID id);
# >
# > int
# > evDefer(evContext opaqueCtx, evWaitFunc func, void *uap);
# >
# > int
# > evSelectFD(evContext ctx, int fd, int eventmask, evFileFunc func,
# > void *uap, evFileID *id);
# >
# > int
# > evDeselectFD(evContext ctx, evFileID id);
# >
# > struct iovec
# > evConsIovec(void *buf, size_t cnt);
# >
# > int
# > evWrite(evContext ctx, int fd, const struct iovec *iov, int cnt,
# > evStreamFunc func, void *uap, evStreamID *id);
# >
# > int
# > evRead(evContext ctx, int fd, const struct iovec *iov, int cnt,
# > evStreamFunc func, void *uap, evStreamID *id);
# >
# > int
# > evCancelRW(evContext ctx, evStreamID id);
# >
# > int
# > evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer);
# >
# > int
# > evUntimeRW(evContext opaqueCtx, evStreamID id);
# >
# > int
# > evListen(evContext ctx, int fd, int maxconn, evConnFunc func, void *uap,
# > evConnID *id);
# >
# > int
# > evConnect(evContext ctx, int fd, void *ra, int ralen, evConnFunc func,
# > void *uap, evConnID *id);
# >
# > int
# > evCancelConn(evContext ctx, evConnID id);
# >
# > int
# > evHold(evContext ctx, evConnID id);
# >
# > int
# > evUnhold(evContext ctx, evConnID id);
# >
# > int
# > evTryAccept(evContext ctx, evConnID id, int *sys_errno);
# >
# > void
# > evSetDebug(evContext ctx, int level, FILE *output);
# >
# > void
# > evPrintf(const evContext_p *ctx, int level, const char *fmt, ...);
# >
# > void
# > evInitID(*ID);
# >
# > int
# > evTestID(ID);
# >
# > DESCRIPTION
# > This library provides multiple outstanding asynchronous timers and I/O to
# > a cooperating application. The model is similar to that of the X Tool-
# > kit, in that events are registered with the library and the application
# > spends most of its time in the evMainLoop() function. If an application
# > already has a main loop, it can safely register events with this library
# > as long as it periodically calls the evGetNext() and evDispatch() func-
# > tions. (Note that evGetNext() has both polling and blocking modes.)
# >
# > The function evCreate() creates an event context which is needed by all
# > the other functions in this library. All information used internally by
# > this library is bound to this context, rather than to static storage.
# > This makes the library ``thread safe'', and permits other library func-
# > tions to use events without disrupting the application's use of events.
# >
# > The function evDestroy() destroys a context that has been created by
# > evCreate(). All dynamic memory bound to this context will be freed. An
# > implicit evTimerClear() will be done on all timers set in this event con-
# > text. An implicit evDeselectFD() will be done on all file descriptors
# > selected in this event context.
# >
# > The function evGetNext() potentially waits for and then retrieves the
# > next asynchronous event, placing it in the object of the ev pointer argu-
# > ment. The following options are available: EV_POLL, meaning that
# > evGetNext() should not block, but rather return ``-1'' with errno set to
# > EWOULDBLOCK if no events have occurred; EV_WAIT, which tells evGetNext()
# > to block internally until the next event occurs; and EV_NULL, which tells
# > evGetNext() that it should return a special ``no-op'' event, which is
# > ignored by evDispatch() but handled correctly by evDrop(). EV_NULL can
# > be necessary to the correct functioning of a caller-written equivilent to
# > evMainLoop(), wherein perterbations caused by external system events must
# > be polled for, and the default behaviour of internally ignoring such
# > events is undesirable. Note that EV_POLL and EV_WAIT are mutually exclu-
# > sive.
# >
# > The function evDispatch() dispatches an event retrieved by evGetNext().
# > This usually involves calling the function that was associated with the
# > event when the event was registered with evSetTimer(), evResetTimer(), or
# > evSelectFD(). All events retrieved by evGetNext() must be given over to
# > evDispatch() at some point, since there is some dynamic memory associated
# > with each event.
# >
# > The function evDrop() deallocates dynamic memory that has been allocated
# > by evGetNext(). Calling evDispatch() has the side effect of calling
# > evDrop(), but if you are going to drop the event rather than dispatch it,
# > you will have to call evDrop() directly.
# >
# > The function evMainLoop() is just:
# >
# > while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
# > if ((x = evDispatch(opaqueCtx, event)) < 0)
# > break;
# > return (x);
# >
# > In other words, get events and dispatch them until an error occurs. One
# > such error would be that all the events under this context become unreg-
# > istered; in that event, there will be nothing to wait for and evGetNext()
# > becomes an undefined operation.
# >
# > The function evConsTime() is a constructor for ``struct timespec'' which
# > allows these structures to be created and then passed as arguments to
# > other functions without the use of temporary variables. (If C had inline
# > constructors, there would be no need for this function.)
# >
# > The functions evTimeSpec() and evTimeVal() are utilities which allow the
# > caller to convert a ``struct timeval'' to a ``struct timespec'' (the
# > function of evTimeSpec()) or vice versa (the function of evTimeVal()).
# > Note that the name of the function indicates the type of the return
# > value.
# >
# > The function evAddTime() adds two ``struct timespec'' values and returns
# > the result as a ``struct timespec''.
# >
# > The function evSubTime() subtracts its second ``struct timespec'' argu-
# > ment from its first ``struct timespec'' argument and returns the result
# > as a ``struct timespec''.
# >
# > The function evCmpTime() compares its two ``struct timespec'' arguments
# > and returns an ``int'' that is less than zero if the first argument spec-
# > ifies an earlier time than the second, or more than zero if the first
# > argument specifies a later time than the second, or equal to zero if both
# > arguments specify the same time.
# >
# > The function evNowTime() returns a ``struct timespec'' which either
# > describes the current time (using gettimeofday(2)), if successful, or has
# > its fields set to zero, if there is an error. (In the latter case, the
# > caller can check errno, since it will be set by gettimeofday(2).)
# >
# > The function evLastEventTime() returns the ``struct timespec'' which
# > describes the last time that certain events happened to the event context
# > indicated by opaqueCtx. This value is updated by evCreate() and
# > evGetNext() (upon entry and after select(2) returns); it is routinely
# > compared with other times in the internal handling of, e.g., timers.
# >
# > The function evSetTimer() registers a timer event, which will be deliv-
# > ered as a function call to the function specified by the func argument.
# > The event will be delivered at absolute time due, and then if time inter
# > is not equal to ``evConsTime(0, 0)'', subsequently at intervals equal to
# > time inter. As a special case, specifying a due argument equal to
# > ``evConsTime(0, 0)'' means ``due immediately''. The opaqueID argument,
# > if specified as a value other than NULL, will be used to store the
# > resulting ``timer ID'', useful as an argument to evClearTimer(). Note
# > that in a ``one-shot'' timer (which has an inter argument equal to
# > ``evConsTime(0,0)'') the user function func should deallocate any dynamic
# > memory that is uniquely bound to the uap, since no handles to this memory
# > will exist within the event library after a one-shot timer has been
# > delivered.
# >
# > The function evResetTimer() resets the values of the timer specified by
# > id to the given arguments. The arguments are the same as in the descrip-
# > tion of evSetTimer() above.
# >
# > The function evClearTimer() will unregister the timer event specified by
# > id. Note that if the uap specified in the corresponding evSetTimer()
# > call is uniquely bound to any dynamic memory, then that dynamic memory
# > should be freed by the caller before the handle is lost. After a call to
# > evClearTimer(), no handles to this uap will exist within the event
# > library.
# >
# > The function evSetIdleTimer() is similar to (and built on) evSetTimer();
# > it registers an idle timer event which provides for the function call to
# > func to occur. However, for an idle timer, the call will occur after at
# > least ``max_idle'' time has passed since the time the idle timer was
# > ``last touched''; originally, this is set to the time returned by
# > evLastEventTime() (described above) for the event context specified by
# > opaqueCtx. This is a ``one-shot'' timer, but the time at which the func
# > is actually called can be changed by recourse to evTouchIdleTimer()
# > (described below). The pointer to the underlying ``timer ID'' is
# > returned in opaqueID, if it is non-NULL.
# >
# > The evTouchIdleTimer() function updates the idle timer associated with
# > id, setting its idea of the time it was last accessed to the value
# > returned by evLastEventTime() (described above) for the event context
# > specified by opaqueCtx. This means that the idle timer will expire after
# > at least max_idle time has passed since this (possibly new) time, provid-
# > ing a caller mechanism for resetting the call to the func associated with
# > the idle timer. (See the description of evSetIdleTimer(), above, for
# > information about func and max_idle.)
# >
# > The evResetIdleTimer() function reschedules a timer and resets the call-
# > back function and its argument. Note that resetting a timer also
# > ``touches'' it.
# >
# > The evClearIdleTimer() function unregisters the idle timer associated
# > with id. See the discussion under evClearTimer(), above, for information
# > regarding caller handling of the uap associated with the corresponding
# > evSetIdleTimer() call.
# >
# > The function evWaitFor() places the function func on the given event con-
# > text's wait queue with the associated (possibly NULL) ``tag''; if id is
# > non-NULL, then it will contain the ``wait ID'' associated with the cre-
# > ated queue element.
# >
# > The function evDo() marks all of the ``waiting'' functions in the given
# > event context's wait queue with the associated (possibly NULL) ``tag'' as
# > runnable. This places these functions in a ``done'' queue which will be
# > read by evGetNext().
# >
# > The function evUnwait() will search for the ``wait ID'' id in the wait
# > queue of the given event context; if an element with the given id is not
# > found, then the ``done'' queue of that context is searched. If found,
# > the queue element is removed from the appropriate list.
# >
# > The function evDefer() causes a function (specified as func, with argu-
# > ment uap) to be dispatched at some later time. Note that the tag argu-
# > ment to func will always be NULL when dispatched.
# >
# > The function evSelectFD() registers a file I/O event for the file
# > descriptor specified by fd. Bits in the eventmask argument are named
# > EV_READ, EV_WRITE, and EV_EXCEPT. At least one of these bits must be
# > specified. If the id argument is not equal to NULL, it will be used to
# > store a unique ``file event ID'' for this event, which is useful in sub-
# > sequent calls to evDeselectFD(). A file descriptor will be made non-
# > blocking using the O_NONBLOCK flag with fcntl(2) on its first concurrent
# > registration via evSelectFD(). An evSelectFD() remains in effect until
# > cancelled via evDeselectFD().
# >
# > The function evDeselectFD() unregisters the ``file event'' specified by
# > the id argument. If the corresponding uap uniquely points to dynamic
# > memory, that memory should be freed before its handle is lost, since
# > after a call to evDeselectFD(), no handles to this event's uap will
# > remain within the event library. A file descriptor will be taken out of
# > nonblocking mode (see O_NONBLOCK and fcntl(2)) when its last event regis-
# > tration is removed via evDeselectFD(), if it was in blocking mode before
# > the first registration via evSelectFD().
# >
# > The function evConsIovec() is a constructor for a single struct iovec
# > structure, which is useful for evWrite() and evRead().
# >
# > The functions evWrite() and evRead() start asynchronous stream I/O opera-
# > tions on file descriptor fd. The data to be written or read is in the
# > scatter/gather descriptor specified by iov and cnt. The supplied func-
# > tion func will be called with argument uap when the I/O operation is com-
# > plete. If id is not NULL, it will be filled a with the stream event
# > identifier suitable for use with evCancelRW().
# >
# > The function evCancelRW() extinguishes an outstanding evWrite() or
# > evRead() call. System I/O calls cannot always be cancelled, but you are
# > guaranteed that the func function supplied to evWrite() or evRead() will
# > not be called after a call to evCancelRW(). Care should be taken not to
# > deallocate or otherwise reuse the space pointed to by the segment
# > descriptors in iov unless the underlying file descriptor is closed first.
# >
# > The function evTimeRW() sets the stream associated with the given stream
# > ID ``id'' to have the idle timer associated with the timer ID ``timer''.
# >
# > The function evUntimeRW() says that the stream associated with the given
# > stream ID ``id'' should ignore its idle timer, if present.
# >
# > The functions evListen(), evConnect(), and evCancelConn() can be used to
# > manage asynchronous incoming and outgoing socket connections. Sockets to
# > be used with these functions should first be created with socket(2) and
# > given a local name with bind(2). It is extremely unlikely that the same
# > socket will ever be useful for both incoming and outgoing connections.
# > The id argument to evListen() and evConnect() is either NULL or the
# > address of a evFileID variable which can then be used in a subsequent
# > call to evCancelConn().
# >
# > After a call to evListen(), each incoming connection arriving on fd will
# > cause func to be called with uap as one of its arguments. evConnect()
# > initiates an outgoing connection on fd to destination address ra (whose
# > length is ralen). When the connection is complete, func will be called
# > with uap as one of its arguments. The argument fd to (*func)() will be
# > -1 if an error occurred that prevented this connection from completing
# > successfully. In this case errno() will have been set and the socket
# > described by fd will have been closed. The evCancelConn() function will
# > prevent delivery of all pending and subsequent events for the outstanding
# > connection. The evHold() function will suspend the acceptance of new
# > connections on the listener specified by id. Connections will be queued
# > by the protocol stack up to the system's limit. The evUnhold() function
# > will reverse the effects of evHold(), allowing incoming connections to be
# > delivered for listener id. The evTryAccept() function will poll the lis-
# > tener specified by id, accepting a new connection if one is available,
# > and queuing a connection event for later retrieval by evGetNext(). If
# > the connection event queued is an accept error(), sys_errno will contain
# > the error code; otherwise it will be zero. All connection events queued
# > by evTryAccept() will be delivered by evGetNext() before a new select is
# > done on the listener.
# >
# > The function evSetDebug() sets the debugging level and diagnostic output
# > file handle for an event context. Greater numeric levels will result in
# > more verbose output being sent to the output FILE during program execu-
# > tion.
# >
# > The function evPrintf() prints a message with the format ``fmt'' and the
# > following arguments (if any), on the output stream associated with the
# > event context pointed to by ctx. The message is output if the event con-
# > text's debug level is greater than or equal to the indicated level.
# >
# > The function evInitID() will initialize an opaque ``evConn ID'', ``evFile
# > ID'', ``evStream ID'', ``evTimer ID'', ``evWait ID'', ``evContext'', or
# > ``evEvent'', which is passed by reference.
# >
# > The function evTestID() will examine an opaque ID and return ``TRUE''
# > only if it is not in its initialized state.
# >
# > RETURN VALUES
# > All the functions whose return type is ``int'' use the standard conven-
# > tion of returning zero (0) to indicate success, or returning ``-1'' and
# > setting errno to indicate failure.
# >
# > FILE
# > heap.h, which is in the src/lib/isc directory of the current BIND distri-
# > bution.
# >
# > ERRORS
# > The possible values for errno when one of the ``int'' functions in this
# > library returns ``-1'' include those of the Standard C Library and also:
# >
# > [EINVAL] Some function argument has an unreasonable value.
# >
# > [EINVAL] The specified file descriptor has an integer value greater
# > than the default FD_SETSIZE, meaning that the applica-
# > tion's limit is higher than the library's.
# >
# > [ENOENT] The specified ``event ID'' does not exist.
# >
# > [EWOULDBLOCK] No events have occurred and the EV_POLL option was speci-
# > fied.
# >
# > [EBADF] The specified signal was unblocked outside the library.
# >
# > SEE ALSO
# > gettimeofday(2), select(2), fcntl(3), malloc(3), named(8), readv(3),
# > writev(3).
# >
# > BUGS
# > This huge man page needs to be broken up into a handful of smaller ones.
# >
# > HISTORY
# > The eventlib library was designed by Paul Vixie with excellent advice
# > from his friends and with tips 'o the cap to the X Consortium and the
# > implementors of DEC SRC Modula-3.
# >
# > 4th Berkeley Distribution March 6, 1996 4th Berkeley Distribution
# >
# > ---
# 
# 
# _______________________________________________
# hackers mailing list
# hackers at support.ntp.org
# https://support.ntp.org/mailman/listinfo/hackers


More information about the hackers mailing list