*BSD News Article 58223


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.mel.connect.com.au!munnari.OZ.AU!news.hawaii.edu!ames!taligent!uunet!in1.uu.net!vixie!nnrp.vix.com!vixie
From: vixie@vix.com (Paul A Vixie)
Newsgroups: comp.unix.bsd.bsdi.misc,comp.unix.advocacy
Subject: Re: multiple httpds vs threads vs ... (was BSDI Vs. NT...)
Followup-To: poster
Date: 26 Dec 1995 16:28:27 GMT
Organization: Vixie Enterprises
Lines: 3073
Message-ID: <VIXIE.95Dec26082827@wisdom.vix.com>
References: <taxfree.3.00C439A1@primenet.com>
	<4be592$6tb@madeline.ins.cwru.edu> <4bhfmp$gei@Mars.mcs.com>
	<DK5Crs.I77@metrics.com> <4bmsjp$7lv@elf.bsdi.com>
NNTP-Posting-Host: wisdom.home.vix.com
In-reply-to: torek@elf.bsdi.com's message of 25 Dec 1995 11:04:25 -0800
Xref: euryale.cc.adfa.oz.au comp.unix.bsd.bsdi.misc:1850 comp.unix.advocacy:12670

>There is a third approach---in one way, kind of a compromise between
>these two---and that is to provide a mechanism such as poll() or
>select() by which a process can implement its own `threading' (except
>that these threads can be even lighter-weight than kernel threads).

You mean, like this?  (Feedback would be appreciated -- BIND is switching
to this paradigm soon to avoid running named-xfer or forking at all.)

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1995-09-25 10:29 PDT by <vixie@gw.home.vix.com>.
# Source directory was `/tmp_mnt/wisdom/mnt/files/users/vixie/src/eventlib'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   2235 -r--r--r-- README
#    664 -r--r--r-- CHANGES
#   1687 -r--r--r-- Makefile
#    436 -rw-rw-r-- SysMake
#  10086 -r--r--r-- eventlib.mdoc
#  13118 -rw-rw-r-- eventlib.lpcat
#  25096 -rw-rw-r-- eventlib.pscat
#   3291 -r--r--r-- eventlib.h
#   2694 -r--r--r-- eventlib_p.h
#   8744 -r--r--r-- eventlib.c
#   4959 -r--r--r-- timers.c
#   5896 -r--r--r-- files.c
#   5692 -r--r--r-- signals.c
#   2048 -r--r--r-- testfiles.c
#   2830 -r--r--r-- testtimers.c
#   2176 -r--r--r-- testsignals.c
#    140 -r--r--r-- testtimers.data
#     90 -r--r--r-- testtimers2.data
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
# ============= README ==============
if test -f 'README' && test X"$1" != X"-c"; then
  echo 'x - skipping README (file already exists)'
else
  echo 'x - extracting README (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
$Id: README,v 1.2 1995/09/17 23:12:25 vixie Exp $
X
Paul Vixie <paul@vix.com>
Internet Software Consortium
X
NAME
X     evOpen, evClose, evGetNext, evDispatch, evMainLoop, evConsTimeV,
X     evAddTimeV, evSubTimeV, evCmpTimeV, evSetTimer, evClearTimer, evSelectFD,
X     evDeselectFD, evSetSignal, evClearSignal, evTimerFunc, evUserFunc,
X     evSignalFunc - event handling library
X
DESCRIPTION
X     This library provides multiple outstanding asynchronous timers and I/O to
X     a cooperating application.  The model is similar to that of the X Toolk-
X     it, in that events are registered with the library and the application
X     spends most of its time in the evMainLoop() function.  If an application
X     already has a main loop, it can safely register events with this library
X     as long as it periodically calls the evGetNext() and evDispatch() func-
X     tions.  (Note that evGetNext() has both polling and blocking modes.)
X
NOTES
X
*.lpcat and *.pscat are for users without the BSD 4.4 "mdoc" or "mandoc"
macros.  Don't run "make clobber" or otherwise delete these files unless
you have the means to regenerate them.  *.mdoc are NOT standard man pages.
X
The Makefile supplied with this kit is NOT in the BSD standard.  As much
as I admire Keith Bostic's 4.3-Reno++ system build environment, I think it
was presumptuous of Keith to call it "make."  You will have to edit SysMake
on some systems (if you do, please send me your changes.)
X
COPYRIGHT
X
Copyright (c) 1995 by Internet Software Consortium
X
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
X
THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
SHAR_EOF
  $shar_touch -am 0917161295 'README' &&
  chmod 0444 'README' ||
  echo 'restore of README failed'
  shar_count="`wc -c < 'README'`"
  test 2235 -eq "$shar_count" ||
    echo "README: original size 2235, current size $shar_count"
fi
# ============= CHANGES ==============
if test -f 'CHANGES' && test X"$1" != X"-c"; then
  echo 'x - skipping CHANGES (file already exists)'
else
  echo 'x - extracting CHANGES (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'CHANGES' &&
$Id: CHANGES,v 1.2 1995/09/17 23:12:25 vixie Exp $
X
17Sep95 1600 PDT -- another bind-workers release, in tar form this time.
X
6. strdup() is now provided inside testtimers.c for systems that need it.
5. the test program main()'s are now properly typed and exited.
4. public include file now uses __P and so is pre-ANSI K&R compliant.
3. cleaned up select() setup to allow for non-const timeval pointer
X   and also to make the whole thing cleaner and more explicit.
2. reformatted source code so that ctags and etags will find all functions.
1. moved system-specific definitions from Makefile to SysMake.
X
16Sep95 2030 PDT -- released to bind-workers for comments.
SHAR_EOF
  $shar_touch -am 0917161295 'CHANGES' &&
  chmod 0444 'CHANGES' ||
  echo 'restore of CHANGES failed'
  shar_count="`wc -c < 'CHANGES'`"
  test 664 -eq "$shar_count" ||
    echo "CHANGES: original size 664, current size $shar_count"
fi
# ============= Makefile ==============
if test -f 'Makefile' && test X"$1" != X"-c"; then
  echo 'x - skipping Makefile (file already exists)'
else
  echo 'x - extracting Makefile (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
#(general options - comment out or change as the mood strikes you)
CDEBUG=-g
CPPDEBUG=-DDEBUG
X
###***===--- No consumer-serviceable parts beyond this point ---===***###
X
SHELL = /bin/sh
CFLAGS = $(CDEBUG) $(CPPDEBUG) $(SYSFLAGS)
LIB = libeventlib.a
TAR = eventlib.tar
TARS = $(TAR) $(TAR).Z $(TAR).gz
OBJ = eventlib.o timers.o files.o signals.o
TESTS = testtimers testfiles testsignals
KIT = README CHANGES Makefile SysMake \
X	eventlib.mdoc eventlib.lpcat eventlib.pscat \
X	eventlib.h eventlib_p.h \
X	eventlib.c timers.c files.c signals.c \
X	testfiles.c testtimers.c testsignals.c \
X	testtimers.data testtimers2.data
X
ALL = $(LIB) $(TESTS)
X
all:; $(SHELL) SysMake all
X
all-sys: $(ALL)
X
kit: $(KIT)
X	shar $(KIT) >kit
X
tar: $(KIT)
X	tar cf $(TAR) $(KIT)
X	compress < $(TAR) > $(TAR).Z
X	gzip < $(TAR) > $(TAR).gz
X
FRC:
X
clean: FRC
X	rm -f *.o *.a *.core
X	rm -f $(TESTS) core
X
clobber: clean
X	rm -f kit eventlib.lpcat eventlib.pscat
X	rm -f $(TARS)
X
$(LIB): $(OBJ)
X	ar rv $(LIB) $(OBJ)
X	ranlib $(LIB)
X
eventlib.pscat: eventlib.mdoc
X	groff -mdoc eventlib.mdoc >eventlib.pscat
X
eventlib.lpcat: eventlib.mdoc
X	nroff -mdoc eventlib.mdoc >eventlib.lpcat
X
testtimers: testtimers.o $(LIB)
X	$(CC) -o testtimers testtimers.o $(LIB) $(SYSLIBS)
X
testfiles: testfiles.o $(LIB)
X	$(CC) -o testfiles testfiles.o $(LIB) $(SYSLIBS)
X
testsignals: testsignals.o $(LIB)
X	$(CC) -o testsignals testsignals.o $(LIB) $(SYSLIBS)
X
eventlib.o: eventlib.c eventlib.h eventlib_p.h
timers.o: timers.c eventlib.h eventlib_p.h
files.o: files.c eventlib.h eventlib_p.h
signals.o: signals.c eventlib.h eventlib_p.h
testtimers.o: testtimers.c eventlib.h
testfiles.o: testfiles.c eventlib.h
testsignals.o: testsignals.c eventlib.h
SHAR_EOF
  $shar_touch -am 0917161195 'Makefile' &&
  chmod 0444 'Makefile' ||
  echo 'restore of Makefile failed'
  shar_count="`wc -c < 'Makefile'`"
  test 1687 -eq "$shar_count" ||
    echo "Makefile: original size 1687, current size $shar_count"
fi
# ============= SysMake ==============
if test -f 'SysMake' && test X"$1" != X"-c"; then
  echo 'x - skipping SysMake (file already exists)'
else
  echo 'x - extracting SysMake (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'SysMake' &&
#! /bin/sh
X
# $Id:$
X
TARGET=$1
shift
X
case "`uname -s`" in
BSD/OS)	SYSFLAGS=''
X	SYSLIBS=''
X	;;
OSF1)	SYSFLAGS='-std1'
X	SYSLIBS=''
X	;;
ULTRIX)	SYSFLAGS='-Dconst= -DNEED_STRDUP'
X	SYSLIBS=''
X	;;
A/UX)	SYSFLAGS='-D_POSIX_SOURCE'
X	SYSLIBS='-lposix'
X	;;
*)	echo unsupported system: "`uname -s`"
X	exit 1;
X	;;
esac
X
echo make SYSFLAGS="$SYSFLAGS" SYSLIBS="$SYSLIBS" ${TARGET}-sys
exec make SYSFLAGS="$SYSFLAGS" SYSLIBS="$SYSLIBS" ${TARGET}-sys
SHAR_EOF
  $shar_touch -am 0917161095 'SysMake' &&
  chmod 0664 'SysMake' ||
  echo 'restore of SysMake failed'
  shar_count="`wc -c < 'SysMake'`"
  test 436 -eq "$shar_count" ||
    echo "SysMake: original size 436, current size $shar_count"
fi
# ============= eventlib.mdoc ==============
if test -f 'eventlib.mdoc' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib.mdoc (file already exists)'
else
  echo 'x - extracting eventlib.mdoc (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'eventlib.mdoc' &&
X.\" $Id: eventlib.mdoc,v 1.1 1995/09/17 05:30:26 vixie Exp $
X.\"
X.\"Copyright (c) 1995 by Internet Software Consortium
X.\"
X.\"Permission to use, copy, modify, and distribute this software for any
X.\"purpose with or without fee is hereby granted, provided that the above
X.\"copyright notice and this permission notice appear in all copies.
X.\"
X.\"THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X.\"ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X.\"OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X.\"CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X.\"DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X.\"PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X.\"ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X.\"SOFTWARE.
X.\"
X.Dd September 14, 1995
X.Dt EVENTLIB 3
X.Os BSD 4
X.Sh NAME
X.Nm evOpen ,
X.Nm evClose ,
X.Nm evGetNext ,
X.Nm evDispatch ,
X.Nm evMainLoop ,
X.Nm evConsTimeV ,
X.Nm evAddTimeV ,
X.Nm evSubTimeV ,
X.Nm evCmpTimeV ,
X.Nm evSetTimer ,
X.Nm evClearTimer ,
X.Nm evSelectFD ,
X.Nm evDeselectFD ,
X.Nm evSetSignal ,
X.Nm evClearSignal ,
X.Nm evTimerFunc ,
X.Nm evUserFunc ,
X.Nm evSignalFunc
X.Nd event handling library
X.Sh SYNOPSIS
X.Fd #include <eventlib.h>
X.Fn evOpen "evContext *ctx"
X.Fn evClose "evContext ctx"
X.Fn evGetNext "evContext ctx" "evEvent *ev" "int options"
X.Fn evDispatch "evContext ctx" "evEvent ev"
X.Fn evMainLoop "evContext ctx"
X.Ft struct timeval
X.Fn evConsTimeV "int sec" "int usec"
X.Ft struct timeval
X.Fn evAddTimeV "struct timeval addend1" "struct timeval addend2"
X.Ft struct timeval
X.Fn evSubTimeV "struct timeval minuend" "struct timeval subtrahend"
X.Ft struct timeval
X.Fn evCmpTimeV "struct timeval a" "struct timeval b"
X.Fn evSetTimer "evContext ctx" "evTimerFunc func" "void *uap" \
"struct timeval due" "struct timeval inter" "evTimerID *id"
X.Fn evClearTimer "evContext ctx" "evTimerID id"
X.Fn evSelectFD "evContext ctx" "int fd" "int eventmask" \
"evFileFunc func" "void *uap" "evFileID *id"
X.Fn evDeselectFD "evContext ctx" "evFileID id"
X.Fn evSetSignal "evContext ctx" "int sig" "evSignalFunc func" "void *uap" \
"evSignalID *ID"
X.Fn evClearSignal "evContext ctx" "evSignalID ID"
X.Ft typedef void
X.Fn (*evTimerFunc) "evContext ctx" "void *uap" \
"struct timeval due" "struct timeval inter"
X.Ft typedef void
X.Fn (*evFileFunc) "evContext ctx" "void *uap" "int fd" "int eventmask"
X.Ft typedef void
X.Fn (*evSignalFunc) "evContext ctx" "void *uap" "int sig"
X.Sh DESCRIPTION
This library provides multiple outstanding asynchronous timers and I/O
to a cooperating application.  The model is similar to that of the X
Toolkit, in that events are registered with the library and the application
spends most of its time in the
X.Fn 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
X.Fn evGetNext
and
X.Fn evDispatch
functions.  (Note that
X.Fn evGetNext
has both polling and blocking modes.)
X.Pp
The function
X.Fn evOpen
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 functions to use events without
disrupting the application's use of events.
X.Pp
The function
X.Fn evClose
destroys a context that has been created by
X.Fn evOpen .
All dynamic memory bound to this context will be freed.  An implicit
X.Fn evTimerClear
will be done on all timers set in this event context.  An implicit
X.Fn evDeselectFD
will be done on all file descriptors selected in this event context.
X.Pp
The function
X.Fn evGetNext
potentially waits for and then retrieves the next asynchronous event,
placing it in the object of the
X.Fa ev
pointer argument.  Two mutually exclusive
X.Fa options
are available:
X.Fa EV_POLL ,
meaning that
X.Fn evGetNext
should not block, but rather return
X.Dq Fa -1
with
X.Fa errno
set to
X.Fa EWOULDBLOCK
if no events have occurred; and
X.Fa EV_WAIT ,
which tells
X.Fn evGetNext
to block in
X.Xr select 2
until the next event occurs.
X.Pp
The function
X.Fn evDispatch
dispatches an event retrieved by
X.Fn evGetNext .
This usually involves calling the function that was associated with the event
when the event was registered with
X.Fn evSetTimer
or
X.Fn evSelectFD .
All events retrieved by
X.Fn evGetNext
must be given over to
X.Fn evDispatch
at some point, since there is some dynamic memory associated with each event.
X.Pp
The function
X.Fn evMainLoop
is just:
X.Bd -literal -offset indent
while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
X	if ((x = evDispatch(opaqueCtx, event)) < 0)
X		break;
return (x);
X.Ed
X.Pp
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 unregistered; in
that event, there will be nothing to wait for and
X.Fn evGetNext
becomes an undefined operation.
X.Pp
The function
X.Fn evConsTimeV
is a constructor for
X.Dq Fa "struct timeval"
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.)
X.Pp
The function
X.Fn evAddTimeV
adds two
X.Dq Fa "struct timeval"
values and returns the result as a
X.Dq Fa "struct timeval" .
X.Pp
The function
X.Fn evSubTimeV
subtracts its second
X.Dq Fa "struct timeval"
argument from its first
X.Dq Fa "struct timeval"
argument and returns the result as a
X.Dq Fa "struct timeval" .
X.Pp
The function
X.Fn evCmpTimeV
compares its two
X.Dq Fa "struct timeval"
arguments and returns an
X.Dq Fa "int"
that is less than zero if the first argument specifies 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.
X.Pp
The function
X.Fn evSetTimer
registers a timer event, which will be delivered as a function call to the
function specified by the
X.Fa func
argument.  The event will be delivered at time
X.Fa due ,
and then if time
X.Fa inter
is not equal to
X.Dq Fa "evConsTimeV(0,0)" ,
subsequently at intervals equal to time
X.Fa inter .
As a special case, specifying a
X.Fa due
argument equal to
X.Dq Fa "evConsTimeV(0,0)"
means ``due immediately.''  The
X.Fa id
argument, if specified as a value other than
X.Fa NULL ,
will be used to store the resulting ``timer \s-1ID\s+1,'' useful as an
argument to
X.Fn evClearTimer .
Note that in a ``one shot'' timer (which has an
X.Fa inter
argument equal to
X.Dq Fa "evConsTimeV(0,0)"
X.\" putting the ) after the Dq Fa arg did not work well.  --vix
) the user function
X.Fa func
should deallocate any dynamic memory that is uniquely bound to the
X.Fa uap ,
since no handles to this memory will exist within the event library
after a one shot timer has been delivered.
X.Pp
The function
X.Fn evClearTimer
will unregister the timer event specified by
X.Fa id .
Note that if the
X.Fa uap
specified in the corresponding
X.Fn 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
X.Fn evClearTimer ,
no handles to this
X.Fa uap
will exist within the event library.
X.Pp
The function
X.Fn evSelectFD
registers a file I/O event for the file descriptor specified by
X.Fa fd .
Bits in the
X.Fa eventmask
argument are named
X.Fa EV_READ ,
X.Fa EV_WRITE ,
and
X.Fa EV_EXCEPT
(corresponding to the ``readable,'' ``writable,'' and ``exceptional'' masks of
the system's
X.Xr select 2
call.  At least one of these bits must be specified.  If the
X.Fa id
argument is not equal to
X.Fa NULL ,
it will be used to store a unique ``file event \s-1ID\s+1'' for this event,
which is useful in subsequent calls to
X.Fn evDelectFD .
X.Pp
The function
X.Fn evDeselectFD
unregisters the ``file event'' specified by the
X.Fa id
argument.  If the corresponding
X.Fa uap
uniquely points to dynamic memory, that memory should be freed before its
handle is lost, since after a call to
X.Fn evDeselectFD ,
no handles to this event's
X.Fa uap
will remain within the event library.
X.Pp
X.Fn evSetSignal
blocks a signal from delivery and registers the
X.Fa func
to be called when
X.Fn evDispatch
discovers that this signal is pending.  The
X.Fa id
argument, if not
X.Fa NULL ,
will be used to store a unique ``signal \s-1ID\s+1'' for this event,
which is useful in subsequent calls to
X.Fn evClearSignal
X.Pp
The function
X.Fn evClearSignal
deregisters the specified signal
X.Fa id ,
unblocking it if it was unblocked before the corresponding
X.Fn evSetSignal
call.  If the corresponding
X.Fa uap
uniquely points to dynamic memory, that memory should be freed before its
handle is lost, since after a call to
X.Fn evClearSignal ,
no handles on this event's
X.Fa uap
will exist within the event library.
X.Sh RETURN VALUES
All the functions whose return type is
X.Dq Fa "int"
use the standard convention of returning zero (0) to indicate success, or
returning
X.Dq Fa -1
and setting
X.Fa errno
to indicate failure.  Other functions have return values as indicated above.
X.Sh ERRORS
The possible values for
X.Fa errno
when one of the
X.Dq Fa "int"
functions in this library returns
X.Dq Fa -1
include those of the Standard C Library and also:
X.Bl -tag -width EWOULDBLOCKAA
X.It Bq Er EINVAL
Some function argument has an unreasonable value.
X.It Bq Er EINVAL
The specified file descriptor has an integer value greater than the default
X.Fa FD_SETSIZE ,
meaning that the application's limit is higher than the library's.
X.It Bq Er ENOENT
The specified event \s-1ID\s+1 does not exist.
X.It Bq Er EWOULDBLOCK
No events have occurred and the
X.Fa EV_POLL
option was specified.
X.It Bq Er EBADF
The specified signal was unblocked outside the library.
X.El
X.Sh SEE ALSO
X.Xr select 2 ,
X.Xr malloc 3 ,
X.Xr XtMainLoop 3
X.Sh HISTORY
The
X.Nm eventlib
library was designed by Paul Vixie with excellent advice from his friends
and with a tip 'o the cap to the X Consortium.
SHAR_EOF
  $shar_touch -am 0916223095 'eventlib.mdoc' &&
  chmod 0444 'eventlib.mdoc' ||
  echo 'restore of eventlib.mdoc failed'
  shar_count="`wc -c < 'eventlib.mdoc'`"
  test 10086 -eq "$shar_count" ||
    echo "eventlib.mdoc: original size 10086, current size $shar_count"
fi
# ============= eventlib.lpcat ==============
if test -f 'eventlib.lpcat' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib.lpcat (file already exists)'
else
  echo 'x - extracting eventlib.lpcat (binary)'
  sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 eventlib.lpcat
M159%3E1,24(H,RD@("`@("`@("`@("`@("`@($)31"!0<F]G<F%M;65R)W,@
M36%N=6%L("`@("`@("`@("`@("`@($5614Y43$E"*#,I"@I."$Y!"$%-"$U%
M"$4*("`@("!E"&5V"'9/"$]P"'!E"&5N"&XL(&4(978(=D,(0VP(;&\(;W,(
M<V4(92P@90AE=@AV1PA'90AE=`AT3@A.90AE>`AX=`AT+"!E"&5V"'9$"$1I
M"&ES"'-P"'!A"&%T"'1C"&-H"&@L(&4(978(=DT(36$(86D(:6X(;DP(3&\(
M;V\(;W`(<"P@90AE=@AV0PA#;PAO;@AN<PAS5`A4:0AI;0AM90AE5@A6+`H@
M("`@(&4(978(=D$(060(9&0(9%0(5&D(:6T(;64(958(5BP@90AE=@AV4PA3
M=0AU8@AB5`A4:0AI;0AM90AE5@A6+"!E"&5V"'9#"$-M"&UP"'!4"%1I"&EM
M"&UE"&56"%8L(&4(978(=E,(4V4(970(=%0(5&D(:6T(;64(97((<BP@90AE
M=@AV0PA#;`AL90AE80AA<@AR5`A4:0AI;0AM90AE<@AR+"!E"&5V"'93"%-E
M"&5L"&QE"&5C"&-T"'1&"$9$"$0L"B`@("`@90AE=@AV1`A$90AE<PAS90AE
M;`AL90AE8PAC=`AT1@A&1`A$+"!E"&5V"'93"%-E"&5T"'13"%-I"&EG"&=N
M"&YA"&%L"&PL(&4(978(=D,(0VP(;&4(96$(87((<E,(4VD(:6<(9VX(;F$(
M86P(;"P@90AE=@AV5`A4:0AI;0AM90AE<@AR1@A&=0AU;@AN8PAC+"!E"&5V
M"'95"%5S"'-E"&5R"')&"$9U"'5N"&YC"&,L"B`@("`@90AE=@AV4PA3:0AI
M9PAG;@AN80AA;`AL1@A&=0AU;@AN8PAC("T@979E;G0@:&%N9&QI;F<@;&EB
M<F%R>0H*4PA360A93@A.3PA/4`A04PA320A)4PA3"B`@("`@(P@C:0AI;@AN
M8PAC;`AL=0AU9`AD90AE(#P(/&4(978(=F4(96X(;G0(=&P(;&D(:6((8BX(
M+F@(:#X(/@H*("`@("!E"&5V"'9/"$]P"'!E"&5N"&XH7PAE7PAV7PA#7PAO
M7PAN7PAT7PAE7PAX7PAT(%\(*E\(8U\(=%\(>"D["@H@("`@(&4(978(=D,(
M0VP(;&\(;W,(<V4(92A?"&5?"'9?"$-?"&]?"&Y?"'1?"&5?"'A?"'0@7PAC
M7PAT7PAX*3L*"B`@("`@90AE=@AV1PA'90AE=`AT3@A.90AE>`AX=`AT*%\(
M95\(=E\(0U\(;U\(;E\(=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(95\(=E\(
M15\(=E\(95\(;E\(="!?""I?"&5?"'8L(%\(:5\(;E\(="!?"&]?"'!?"'1?
M"&E?"&]?"&Y?"',I.PH*("`@("!E"&5V"'9$"$1I"&ES"'-P"'!A"&%T"'1C
M"&-H"&@H7PAE7PAV7PA#7PAO7PAN7PAT7PAE7PAX7PAT(%\(8U\(=%\(>"P@
M7PAE7PAV7PA%7PAV7PAE7PAN7PAT(%\(95\(=BD["@H@("`@(&4(978(=DT(
M36$(86D(:6X(;DP(3&\(;V\(;W`(<"A?"&5?"'9?"$-?"&]?"&Y?"'1?"&5?
M"'A?"'0@7PAC7PAT7PAX*3L*"B`@("`@7PAS7PAT7PAR7PAU7PAC7PAT(%\(
M=%\(:5\(;5\(95\(=E\(85\(;`H@("`@(&4(978(=D,(0V\(;VX(;G,(<U0(
M5&D(:6T(;64(958(5BA?"&E?"&Y?"'0@7PAS7PAE7PAC+"!?"&E?"&Y?"'0@
M7PAU7PAS7PAE7PAC*3L*"B`@("`@7PAS7PAT7PAR7PAU7PAC7PAT(%\(=%\(
M:5\(;5\(95\(=E\(85\(;`H@("`@(&4(978(=D$(060(9&0(9%0(5&D(:6T(
M;64(958(5BA?"'-?"'1?"')?"'5?"&-?"'0@7PAT7PAI7PAM7PAE7PAV7PAA
M7PAL(%\(85\(9%\(9%\(95\(;E\(9%\(,2P@7PAS7PAT7PAR7PAU7PAC7PAT
M(%\(=%\(:5\(;5\(95\(=E\(85\(;"!?"&%?"&1?"&1?"&5?"&Y?"&1?"#(I
M.PH*("`@("!?"'-?"'1?"')?"'5?"&-?"'0@7PAT7PAI7PAM7PAE7PAV7PAA
M7PAL"B`@("`@90AE=@AV4PA3=0AU8@AB5`A4:0AI;0AM90AE5@A6*%\(<U\(
M=%\(<E\(=5\(8U\(="!?"'1?"&E?"&U?"&5?"'9?"&%?"&P@7PAM7PAI7PAN
M7PAU7PAE7PAN7PAD+"!?"'-?"'1?"')?"'5?"&-?"'0@7PAT7PAI7PAM7PAE
M7PAV7PAA7PAL(%\(<U\(=5\(8E\(=%\(<E\(85\(:%\(95\(;E\(9"D["@H@
M("`@(%\(<U\(=%\(<E\(=5\(8U\(="!?"'1?"&E?"&U?"&5?"'9?"&%?"&P*
M("`@("!E"&5V"'9#"$-M"&UP"'!4"%1I"&EM"&UE"&56"%8H7PAS7PAT7PAR
M7PAU7PAC7PAT(%\(=%\(:5\(;5\(95\(=E\(85\(;"!?"&$L(%\(<U\(=%\(
M<E\(=5\(8U\(="!?"'1?"&E?"&U?"&5?"'9?"&%?"&P@7PAB*3L*"B`@("`@
M90AE=@AV4PA390AE=`AT5`A4:0AI;0AM90AE<@AR*%\(95\(=E\(0U\(;U\(
M;E\(=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(95\(=E\(5%\(:5\(;5\(95\(
M<E\(1E\(=5\(;E\(8R!?"&9?"'5?"&Y?"&,L(%\(=E\(;U\(:5\(9"!?""I?
M"'5?"&%?"'`L"B`@("`@("`@("`@("!?"'-?"'1?"')?"'5?"&-?"'0@7PAT
M7PAI7PAM7PAE7PAV7PAA7PAL(%\(9%\(=5\(92P@7PAS7PAT7PAR7PAU7PAC
M7PAT(%\(=%\(:5\(;5\(95\(=E\(85\(;"!?"&E?"&Y?"'1?"&5?"'(L(%\(
M95\(=E\(5%\(:5\(;5\(95\(<E\(25\(1"!?""I?"&E?"&0I.PH*("`@("!E
M"&5V"'9#"$-L"&QE"&5A"&%R"')4"%1I"&EM"&UE"&5R"'(H7PAE7PAV7PA#
M7PAO7PAN7PAT7PAE7PAX7PAT(%\(8U\(=%\(>"P@7PAE7PAV7PA47PAI7PAM
M7PAE7PAR7PA)7PA$(%\(:5\(9"D["@H@("`@(&4(978(=E,(4V4(96P(;&4(
M96,(8W0(=$8(1D0(1"A?"&5?"'9?"$-?"&]?"&Y?"'1?"&5?"'A?"'0@7PAC
M7PAT7PAX+"!?"&E?"&Y?"'0@7PAF7PAD+"!?"&E?"&Y?"'0@7PAE7PAV7PAE
M7PAN7PAT7PAM7PAA7PAS7PAK+"!?"&5?"'9?"$9?"&E?"&Q?"&5?"$9?"'5?
M"&Y?"&,@7PAF7PAU7PAN7PAC+`H@("`@("`@("`@("`@7PAV7PAO7PAI7PAD
M(%\(*E\(=5\(85\(<"P@7PAE7PAV7PA&7PAI7PAL7PAE7PA)7PA$(%\(*E\(
M:5\(9"D["@H@("`@(&4(978(=D0(1&4(97,(<V4(96P(;&4(96,(8W0(=$8(
M1D0(1"A?"&5?"'9?"$-?"&]?"&Y?"'1?"&5?"'A?"'0@7PAC7PAT7PAX+"!?
M"&5?"'9?"$9?"&E?"&Q?"&5?"$E?"$0@7PAI7PAD*3L*"B`@("`@90AE=@AV
M4PA390AE=`AT4PA3:0AI9PAG;@AN80AA;`AL*%\(95\(=E\(0U\(;U\(;E\(
M=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(:5\(;E\(="!?"'-?"&E?"&<L(%\(
M95\(=E\(4U\(:5\(9U\(;E\(85\(;%\(1E\(=5\(;E\(8R!?"&9?"'5?"&Y?
M"&,L(%\(=E\(;U\(:5\(9"!?""I?"'5?"&%?"'`L"B`@("`@("`@("`@("!?
M"&5?"'9?"%-?"&E?"&=?"&Y?"&%?"&Q?"$E?"$0@7P@J7PA)7PA$*3L*"B`@
M("`@90AE=@AV0PA#;`AL90AE80AA<@AR4PA3:0AI9PAG;@AN80AA;`AL*%\(
M95\(=E\(0U\(;U\(;E\(=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(95\(=E\(
M4U\(:5\(9U\(;E\(85\(;%\(25\(1"!?"$E?"$0I.PH*("`@("!?"'1?"'E?
M"'!?"&5?"&1?"&5?"&8@7PAV7PAO7PAI7PAD"B`@("`@*`@H*@@J90AE=@AV
M5`A4:0AI;0AM90AE<@AR1@A&=0AU;@AN8PAC*0@I*%\(95\(=E\(0U\(;U\(
M;E\(=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(=E\(;U\(:5\(9"!?""I?"'5?
M"&%?"'`L(%\(<U\(=%\(<E\(=5\(8U\(="!?"'1?"&E?"&U?"&5?"'9?"&%?
M"&P@7PAD7PAU7PAE+`H@("`@("`@("`@("`@7PAS7PAT7PAR7PAU7PAC7PAT
M(%\(=%\(:5\(;5\(95\(=E\(85\(;"!?"&E?"&Y?"'1?"&5?"'(I.PH*("`@
M("!?"'1?"'E?"'!?"&5?"&1?"&5?"&8@7PAV7PAO7PAI7PAD"B`@("`@*`@H
M*@@J90AE=@AV1@A&:0AI;`AL90AE1@A&=0AU;@AN8PAC*0@I*%\(95\(=E\(
M0U\(;U\(;E\(=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(=E\(;U\(:5\(9"!?
M""I?"'5?"&%?"'`L(%\(:5\(;E\(="!?"&9?"&0L(%\(:5\(;E\(="!?"&5?
M"'9?"&5?"&Y?"'1?"&U?"&%?"'-?"&LI.PH*("`@("!?"'1?"'E?"'!?"&5?
M"&1?"&5?"&8@7PAV7PAO7PAI7PAD"B`@("`@*`@H*@@J90AE=@AV4PA3:0AI
M9PAG;@AN80AA;`AL1@A&=0AU;@AN8PAC*0@I*%\(95\(=E\(0U\(;U\(;E\(
M=%\(95\(>%\(="!?"&-?"'1?"'@L(%\(=E\(;U\(:5\(9"!?""I?"'5?"&%?
M"'`L(%\(:5\(;E\(="!?"'-?"&E?"&<I.PH*1`A$10A%4PA30PA#4@A220A)
M4`A05`A420A)3PA/3@A."B`@("`@5&AI<R!L:6)R87)Y('!R;W9I9&5S(&UU
M;'1I<&QE(&]U='-T86YD:6YG(&%S>6YC:')O;F]U<R!T:6UE<G,@86YD($DO
M3R!T;PH@("`@(&$@8V]O<&5R871I;F<@87!P;&EC871I;VXN("!4:&4@;6]D
M96P@:7,@<VEM:6QA<B!T;R!T:&%T(&]F('1H92!8(%1O;VQK+0H@("`@(&ET
M+"!I;B!T:&%T(&5V96YT<R!A<F4@<F5G:7-T97)E9"!W:71H('1H92!L:6)R
M87)Y(&%N9"!T:&4@87!P;&EC871I;VX*("`@("!S<&5N9',@;6]S="!O9B!I
M=',@=&EM92!I;B!T:&4@90AE=@AV30A-80AA:0AI;@AN3`A,;PAO;PAO<`AP
M*"D@9G5N8W1I;VXN("!)9B!A;B!A<'!L:6-A=&EO;@H@("`@(&%L<F5A9'D@
M:&%S(&$@;6%I;B!L;V]P+"!I="!C86X@<V%F96QY(')E9VES=&5R(&5V96YT
M<R!W:71H('1H:7,@;&EB<F%R>0H@("`@(&%S(&QO;F<@87,@:70@<&5R:6]D
M:6-A;&QY(&-A;&QS('1H92!E"&5V"'9'"$=E"&5T"'1."$YE"&5X"'AT"'0H
M*2!A;F0@90AE=@AV1`A$:0AI<PAS<`AP80AA=`AT8PAC:`AH*"D@9G5N8RT*
M("`@("!T:6]N<RX@("A.;W1E('1H870@90AE=@AV1PA'90AE=`AT3@A.90AE
M>`AX=`AT*"D@:&%S(&)O=&@@<&]L;&EN9R!A;F0@8FQO8VMI;F<@;6]D97,N
M*0H*("`@("!4:&4@9G5N8W1I;VX@90AE=@AV3PA/<`AP90AE;@AN*"D@8W)E
M871E<R!A;B!E=F5N="!C;VYT97AT('=H:6-H(&ES(&YE961E9"!B>2!A;&P@
M=&AE"B`@("`@;W1H97(@9G5N8W1I;VYS(&EN('1H:7,@;&EB<F%R>2X@($%L
M;"!I;F9O<FUA=&EO;B!U<V5D(&EN=&5R;F%L;'D@8GD@=&AI<PH@("`@(&QI
M8G)A<GD@:7,@8F]U;F0@=&\@=&AI<R!C;VYT97AT+"!R871H97(@=&AA;B!T
M;R!S=&%T:6,@<W1O<F%G92X@(%1H:7,*("`@("!M86ME<R!T:&4@;&EB<F%R
M>2!@8'1H<F5A9"!S869E+"<G(&%N9"!P97)M:71S(&]T:&5R(&QI8G)A<GD@
M9G5N8W1I;VYS('1O"B`@("`@=7-E(&5V96YT<R!W:71H;W5T(&1I<W)U<'1I
M;F<@=&AE(&%P<&QI8V%T:6]N)W,@=7-E(&]F(&5V96YT<RX*"B`@("`@5&AE
M(&9U;F-T:6]N(&4(978(=D,(0VP(;&\(;W,(<V4(92@I(&1E<W1R;WES(&$@
M8V]N=&5X="!T:&%T(&AA<R!B965N(&-R96%T960@8GD*("`@("!E"&5V"'9/
M"$]P"'!E"&5N"&XH*2X@($%L;"!D>6YA;6EC(&UE;6]R>2!B;W5N9"!T;R!T
M:&ES(&-O;G1E>'0@=VEL;"!B92!F<F5E9"X@($%N"B`@("`@:6UP;&EC:70@
M90AE=@AV5`A4:0AI;0AM90AE<@AR0PA#;`AL90AE80AA<@AR*"D@=VEL;"!B
M92!D;VYE(&]N(&%L;"!T:6UE<G,@<V5T(&EN('1H:7,@979E;G0@8V]N+0H@
M("`@('1E>'0N("!!;B!I;7!L:6-I="!E"&5V"'9$"$1E"&5S"'-E"&5L"&QE
M"&5C"&-T"'1&"$9$"$0H*2!W:6QL(&)E(&1O;F4@;VX@86QL(&9I;&4@9&5S
M8W)I<'1O<G,*("`@("!S96QE8W1E9"!I;B!T:&ES(&5V96YT(&-O;G1E>'0N
M"@H@("`@(%1H92!F=6YC=&EO;B!E"&5V"'9'"$=E"&5T"'1."$YE"&5X"'AT
M"'0H*2!P;W1E;G1I86QL>2!W86ET<R!F;W(@86YD('1H96X@<F5T<FEE=F5S
M('1H90H@("`@(&YE>'0@87-Y;F-H<F]N;W5S(&5V96YT+"!P;&%C:6YG(&ET
M(&EN('1H92!O8FIE8W0@;V8@=&AE(%\(95\(=B!P;VEN=&5R(&%R9W4M"B`@
M("`@;65N="X@(%1W;R!M=71U86QL>2!E>&-L=7-I=F4@7PAO7PAP7PAT7PAI
M7PAO7PAN7PAS(&%R92!A=F%I;&%B;&4Z(%\(15\(5E\(7U\(4%\(3U\(3%\(
M3"P@;65A;FEN9PH@("`@('1H870@90AE=@AV1PA'90AE=`AT3@A.90AE>`AX
M=`AT*"D@<VAO=6QD(&YO="!B;&]C:RP@8G5T(')A=&AE<B!R971U<FX@8&!?
M""U?"#$G)R!W:71H(%\(95\(<E\(<E\(;E\(;PH@("`@('-E="!T;R!?"$5?
M"%=?"$]?"%5?"$Q?"$1?"$)?"$Q?"$]?"$-?"$L@:68@;F\@979E;G1S(&AA
M=F4@;V-C=7)R960[(&%N9"!?"$5?"%9?"%]?"%=?"$%?"$E?"%0L('=H:6-H
M('1E;&QS"B`@("`@90AE=@AV1PA'90AE=`AT3@A.90AE>`AX=`AT*"D@=&\@
M8FQO8VL@:6X@<V5L96-T*#(I('5N=&EL('1H92!N97AT(&5V96YT(&]C8W5R
M<RX*"B`@("`@5&AE(&9U;F-T:6]N(&4(978(=D0(1&D(:7,(<W`(<&$(870(
M=&,(8V@(:"@I(&1I<W!A=&-H97,@86X@979E;G0@<F5T<FEE=F5D(&)Y(&4(
M978(=D<(1V4(970(=$X(3F4(97@(>'0(="@I+@H@("`@(%1H:7,@=7-U86QL
M>2!I;G9O;'9E<R!C86QL:6YG('1H92!F=6YC=&EO;B!T:&%T('=A<R!A<W-O
M8VEA=&5D('=I=&@@=&AE"B`@("`@979E;G0@=VAE;B!T:&4@979E;G0@=V%S
M(')E9VES=&5R960@=VET:"!E"&5V"'93"%-E"&5T"'14"%1I"&EM"&UE"&5R
M"'(H*2!O<B!E"&5V"'93"%-E"&5L"&QE"&5C"&-T"'1&"$9$"$0H*2X*("`@
M("!!;&P@979E;G1S(')E=')I979E9"!B>2!E"&5V"'9'"$=E"&5T"'1."$YE
M"&5X"'AT"'0H*2!M=7-T(&)E(&=I=F5N(&]V97(@=&\@90AE=@AV1`A$:0AI
M<PAS<`AP80AA=`AT8PAC:`AH*"D@870*("`@("!S;VUE('!O:6YT+"!S:6YC
M92!T:&5R92!I<R!S;VUE(&1Y;F%M:6,@;65M;W)Y(&%S<V]C:6%T960@=VET
M:"!E86-H"B`@("`@979E;G0N"@H@("`@(%1H92!F=6YC=&EO;B!E"&5V"'9-
M"$UA"&%I"&EN"&Y,"$QO"&]O"&]P"'`H*2!I<R!J=7-T.@H*("`@("`@("`@
M("!W:&EL92`H*'@@/2!E=D=E=$YE>'0H;W!A<75E0W1X+"`F979E;G0L($56
M7U=!250I*2`]/2`P*0H@("`@("`@("`@("`@("`@("`@:68@*"AX(#T@979$
M:7-P871C:"AO<&%Q=65#='@L(&5V96YT*2D@/"`P*0H@("`@("`@("`@("`@
M("`@("`@("`@("`@("!B<F5A:SL*("`@("`@("`@("!R971U<FX@*'@I.PH*
M("`@("!);B!O=&AE<B!W;W)D<RP@9V5T(&5V96YT<R!A;F0@9&ES<&%T8V@@
M=&AE;2!U;G1I;"!A;B!E<G)O<B!O8V-U<G,N("!/;F4*("`@("!S=6-H(&5R
M<F]R('=O=6QD(&)E('1H870@86QL('1H92!E=F5N=',@=6YD97(@=&AI<R!C
M;VYT97AT(&)E8V]M92!U;G)E9RT*("`@("!I<W1E<F5D.R!I;B!T:&%T(&5V
M96YT+"!T:&5R92!W:6QL(&)E(&YO=&AI;F<@=&\@=V%I="!F;W(@86YD(&4(
M978(=D<(1V4(970(=$X(3F4(97@(>'0(="@I"B`@("`@8F5C;VUE<R!A;B!U
M;F1E9FEN960@;W!E<F%T:6]N+@H*("`@("!4:&4@9G5N8W1I;VX@90AE=@AV
M0PA#;PAO;@AN<PAS5`A4:0AI;0AM90AE5@A6*"D@:7,@82!C;VYS=')U8W1O
M<B!F;W(@8&!?"'-?"'1?"')?"'5?"&-?"'0@7PAT7PAI7PAM7PAE7PAV7PAA
M7PAL)R<@=VAI8V@*("`@("!A;&QO=W,@=&AE<V4@<W1R=6-T=7)E<R!T;R!B
M92!C<F5A=&5D(&%N9"!T:&5N('!A<W-E9"!A<R!A<F=U;65N=',@=&\*("`@
M("!O=&AE<B!F=6YC=&EO;G,@=VET:&]U="!T:&4@=7-E(&]F('1E;7!O<F%R
M>2!V87)I86)L97,N("`H268@0R!H860@:6YL:6YE"B`@("`@8V]N<W1R=6-T
M;W)S+"!T:&5R92!W;W5L9"!B92!N;R!N965D(&9O<B!T:&ES(&9U;F-T:6]N
M+BD*"B`@("`@5&AE(&9U;F-T:6]N(&4(978(=D$(060(9&0(9%0(5&D(:6T(
M;64(958(5B@I(&%D9',@='=O(&!@7PAS7PAT7PAR7PAU7PAC7PAT(%\(=%\(
M:5\(;5\(95\(=E\(85\(;"<G('9A;'5E<R!A;F0@<F5T=7)N<PH@("`@('1H
M92!R97-U;'0@87,@82!@8%\(<U\(=%\(<E\(=5\(8U\(="!?"'1?"&E?"&U?
M"&5?"'9?"&%?"&PG)RX*"B`@("`@5&AE(&9U;F-T:6]N(&4(978(=E,(4W4(
M=6((8E0(5&D(:6T(;64(958(5B@I('-U8G1R86-T<R!I=',@<V5C;VYD(&!@
M7PAS7PAT7PAR7PAU7PAC7PAT(%\(=%\(:5\(;5\(95\(=E\(85\(;"<G(&%R
M9W4M"B`@("`@;65N="!F<F]M(&ET<R!F:7)S="!@8%\(<U\(=%\(<E\(=5\(
M8U\(="!?"'1?"&E?"&U?"&5?"'9?"&%?"&PG)R!A<F=U;65N="!A;F0@<F5T
M=7)N<R!T:&4@<F5S=6QT(&%S"B`@("`@82!@8%\(<U\(=%\(<E\(=5\(8U\(
M="!?"'1?"&E?"&U?"&5?"'9?"&%?"&PG)RX*"B`@("`@5&AE(&9U;F-T:6]N
M(&4(978(=D,(0VT(;7`(<%0(5&D(:6T(;64(958(5B@I(&-O;7!A<F5S(&ET
M<R!T=V\@8&!?"'-?"'1?"')?"'5?"&-?"'0@7PAT7PAI7PAM7PAE7PAV7PAA
M7PAL)R<@87)G=6UE;G1S"B`@("`@86YD(')E='5R;G,@86X@8&!?"&E?"&Y?
M"'0G)R!T:&%T(&ES(&QE<W,@=&AA;B!Z97)O(&EF('1H92!F:7)S="!A<F=U
M;65N="!S<&5C+0H@("`@(&EF:65S(&%N(&5A<FQI97(@=&EM92!T:&%N('1H
M92!S96-O;F0L(&]R(&UO<F4@=&AA;B!Z97)O(&EF('1H92!F:7)S="!A<BT*
M("`@("!G=6UE;G0@<W!E8VEF:65S(&$@;&%T97(@=&EM92!T:&%N('1H92!S
M96-O;F0L(&]R(&5Q=6%L('1O('IE<F\@:68@8F]T:`H@("`@(&%R9W5M96YT
M<R!S<&5C:69Y('1H92!S86UE('1I;64N"@H@("`@(%1H92!F=6YC=&EO;B!E
M"&5V"'93"%-E"&5T"'14"%1I"&EM"&UE"&5R"'(H*2!R96=I<W1E<G,@82!T
M:6UE<B!E=F5N="P@=VAI8V@@=VEL;"!B92!D96QI=BT*("`@("!E<F5D(&%S
M(&$@9G5N8W1I;VX@8V%L;"!T;R!T:&4@9G5N8W1I;VX@<W!E8VEF:65D(&)Y
M('1H92!?"&9?"'5?"&Y?"&,@87)G=6UE;G0N"B`@("`@5&AE(&5V96YT('=I
M;&P@8F4@9&5L:79E<F5D(&%T('1I;64@7PAD7PAU7PAE+"!A;F0@=&AE;B!I
M9B!T:6UE(%\(:5\(;E\(=%\(95\(<B!I<R!N;W0*("`@("!E<75A;"!T;R!@
M8%\(95\(=E\(0U\(;U\(;E\(<U\(5%\(:5\(;5\(95\(5E\(*%\(,%\(+%\(
M,%\(*2<G+"!S=6)S97%U96YT;'D@870@:6YT97)V86QS(&5Q=6%L('1O('1I
M;64*("`@("!?"&E?"&Y?"'1?"&5?"'(N($%S(&$@<W!E8VEA;"!C87-E+"!S
M<&5C:69Y:6YG(&$@7PAD7PAU7PAE(&%R9W5M96YT(&5Q=6%L('1O"B`@("`@
M8&!?"&5?"'9?"$-?"&]?"&Y?"'-?"%1?"&E?"&U?"&5?"%9?""A?"#!?""Q?
M"#!?""DG)R!M96%N<R!@8&1U92!I;6UE9&EA=&5L>2XG)R`@5&AE(%\(:5\(
M9"!A<F=U;65N="P@:68*("`@("!S<&5C:69I960@87,@82!V86QU92!O=&AE
M<B!T:&%N(%\(3E\(55\(3%\(3"P@=VEL;"!B92!U<V5D('1O('-T;W)E('1H
M92!R97-U;'1I;F<*("`@("!@8'1I;65R($E$+"<G('5S969U;"!A<R!A;B!A
M<F=U;65N="!T;R!E"&5V"'9#"$-L"&QE"&5A"&%R"')4"%1I"&EM"&UE"&5R
M"'(H*2X@($YO=&4@=&AA="!I;B!A"B`@("`@8&!O;F4@<VAO="<G('1I;65R
M("AW:&EC:"!H87,@86X@7PAI7PAN7PAT7PAE7PAR(&%R9W5M96YT(&5Q=6%L
M('1O"B`@("`@8&!?"&5?"'9?"$-?"&]?"&Y?"'-?"%1?"&E?"&U?"&5?"%9?
M""A?"#!?""Q?"#!?""DG)R`I('1H92!U<V5R(&9U;F-T:6]N(%\(9E\(=5\(
M;E\(8R!S:&]U;&0@9&5A;&QO8V%T92!A;GD@9'DM"B`@("`@;F%M:6,@;65M
M;W)Y('1H870@:7,@=6YI<75E;'D@8F]U;F0@=&\@=&AE(%\(=5\(85\(<"P@
M<VEN8V4@;F\@:&%N9&QE<R!T;R!T:&ES"B`@("`@;65M;W)Y('=I;&P@97AI
M<W0@=VET:&EN('1H92!E=F5N="!L:6)R87)Y(&%F=&5R(&$@;VYE('-H;W0@
M=&EM97(@:&%S"B`@("`@8F5E;B!D96QI=F5R960N"@H@("`@(%1H92!F=6YC
M=&EO;B!E"&5V"'9#"$-L"&QE"&5A"&%R"')4"%1I"&EM"&UE"&5R"'(H*2!W
M:6QL('5N<F5G:7-T97(@=&AE('1I;65R(&5V96YT('-P96-I9FEE9"!B>0H@
M("`@(%\(:5\(9"X@3F]T92!T:&%T(&EF('1H92!?"'5?"&%?"'`@<W!E8VEF
M:65D(&EN('1H92!C;W)R97-P;VYD:6YG(&4(978(=E,(4V4(970(=%0(5&D(
M:6T(;64(97((<B@I(&-A;&P*("`@("!I<R!U;FEQ=65L>2!B;W5N9"!T;R!A
M;GD@9'EN86UI8R!M96UO<GDL('1H96X@=&AA="!D>6YA;6EC(&UE;6]R>2!S
M:&]U;&0*("`@("!B92!F<F5E9"!B>2!T:&4@8V%L;&5R(&)E9F]R92!T:&4@
M:&%N9&QE(&ES(&QO<W0N("!!9G1E<B!A(&-A;&P@=&\*("`@("!E"&5V"'9#
M"$-L"&QE"&5A"&%R"')4"%1I"&EM"&UE"&5R"'(H*2P@;F\@:&%N9&QE<R!T
M;R!T:&ES(%\(=5\(85\(<"!W:6QL(&5X:7-T('=I=&AI;B!T:&4@979E;G0@
M;&DM"B`@("`@8G)A<GDN"@H@("`@(%1H92!F=6YC=&EO;B!E"&5V"'93"%-E
M"&5L"&QE"&5C"&-T"'1&"$9$"$0H*2!R96=I<W1E<G,@82!F:6QE($DO3R!E
M=F5N="!F;W(@=&AE(&9I;&4@9&4M"B`@("`@<V-R:7!T;W(@<W!E8VEF:65D
M(&)Y(%\(9E\(9"X@0FET<R!I;B!T:&4@7PAE7PAV7PAE7PAN7PAT7PAM7PAA
M7PAS7PAK(&%R9W5M96YT(&%R92!N86UE9`H@("`@(%\(15\(5E\(7U\(4E\(
M15\(05\(1"P@7PA%7PA67PA?7PA77PA27PA)7PA47PA%+"!A;F0@7PA%7PA6
M7PA?7PA%7PA87PA#7PA%7PA07PA4("AC;W)R97-P;VYD:6YG('1O('1H92!@
M8')E861A8FQE+"<G"B`@("`@8&!W<FET86)L92PG)R!A;F0@8&!E>&-E<'1I
M;VYA;"<G(&UA<VMS(&]F('1H92!S>7-T96TG<R!S96QE8W0H,BD@8V%L;"X*
M("`@("!!="!L96%S="!O;F4@;V8@=&AE<V4@8FET<R!M=7-T(&)E('-P96-I
M9FEE9"X@($EF('1H92!?"&E?"&0@87)G=6UE;G0@:7,@;F]T"B`@("`@97%U
M86P@=&\@7PA.7PA57PA,7PA,+"!I="!W:6QL(&)E('5S960@=&\@<W1O<F4@
M82!U;FEQ=64@8&!F:6QE(&5V96YT($E$)R<@9F]R"B`@("`@=&AI<R!E=F5N
M="P@=VAI8V@@:7,@=7-E9G5L(&EN('-U8G-E<75E;G0@8V%L;',@=&\@90AE
M=@AV1`A$90AE;`AL90AE8PAC=`AT1@A&1`A$*"DN"@H@("`@(%1H92!F=6YC
M=&EO;B!E"&5V"'9$"$1E"&5S"'-E"&5L"&QE"&5C"&-T"'1&"$9$"$0H*2!U
M;G)E9VES=&5R<R!T:&4@8&!F:6QE(&5V96YT)R<@<W!E8VEF:65D(&)Y"B`@
M("`@=&AE(%\(:5\(9"!A<F=U;65N="X@($EF('1H92!C;W)R97-P;VYD:6YG
M(%\(=5\(85\(<"!U;FEQ=65L>2!P;VEN=',@=&\@9'EN86UI8PH@("`@(&UE
M;6]R>2P@=&AA="!M96UO<GD@<VAO=6QD(&)E(&9R965D(&)E9F]R92!I=',@
M:&%N9&QE(&ES(&QO<W0L('-I;F-E(&%F+0H@("`@('1E<B!A(&-A;&P@=&\@
M90AE=@AV1`A$90AE<PAS90AE;`AL90AE8PAC=`AT1@A&1`A$*"DL(&YO(&AA
M;F1L97,@=&\@=&AI<R!E=F5N="=S(%\(=5\(85\(<"!W:6QL(')E;6%I;@H@
M("`@('=I=&AI;B!T:&4@979E;G0@;&EB<F%R>2X*"B`@("`@90AE=@AV4PA3
M90AE=`AT4PA3:0AI9PAG;@AN80AA;`AL*"D@8FQO8VMS(&$@<VEG;F%L(&9R
M;VT@9&5L:79E<GD@86YD(')E9VES=&5R<R!T:&4@7PAF7PAU7PAN7PAC('1O
M(&)E"B`@("`@8V%L;&5D('=H96X@90AE=@AV1`A$:0AI<PAS<`AP80AA=`AT
M8PAC:`AH*"D@9&ES8V]V97)S('1H870@=&AI<R!S:6=N86P@:7,@<&5N9&EN
M9RX@(%1H92!?"&E?"&0*("`@("!A<F=U;65N="P@:68@;F]T(%\(3E\(55\(
M3%\(3"P@=VEL;"!B92!U<V5D('1O('-T;W)E(&$@=6YI<75E(&!@<VEG;F%L
M($E$)R<@9F]R"B`@("`@=&AI<R!E=F5N="P@=VAI8V@@:7,@=7-E9G5L(&EN
M('-U8G-E<75E;G0@8V%L;',@=&\@90AE=@AV0PA#;`AL90AE80AA<@AR4PA3
M:0AI9PAG;@AN80AA;`AL*"D*"B`@("`@5&AE(&9U;F-T:6]N(&4(978(=D,(
M0VP(;&4(96$(87((<E,(4VD(:6<(9VX(;F$(86P(;"@I(&1E<F5G:7-T97)S
M('1H92!S<&5C:69I960@<VEG;F%L(%\(:5\(9"P@=6XM"B`@("`@8FQO8VMI
M;F<@:70@:68@:70@=V%S('5N8FQO8VME9"!B969O<F4@=&AE(&-O<G)E<W!O
M;F1I;F<@90AE=@AV4PA390AE=`AT4PA3:0AI9PAG;@AN80AA;`AL*"D*("`@
M("!C86QL+B`@268@=&AE(&-O<G)E<W!O;F1I;F<@7PAU7PAA7PAP('5N:7%U
M96QY('!O:6YT<R!T;R!D>6YA;6EC(&UE;6]R>2P@=&AA=`H@("`@(&UE;6]R
M>2!S:&]U;&0@8F4@9G)E960@8F5F;W)E(&ET<R!H86YD;&4@:7,@;&]S="P@
M<VEN8V4@869T97(@82!C86QL('1O"B`@("`@90AE=@AV0PA#;`AL90AE80AA
M<@AR4PA3:0AI9PAG;@AN80AA;`AL*"DL(&YO(&AA;F1L97,@;VX@=&AI<R!E
M=F5N="=S(%\(=5\(85\(<"!W:6QL(&5X:7-T('=I=&AI;B!T:&4*("`@("!E
M=F5N="!L:6)R87)Y+@H*4@A210A%5`A450A54@A23@A.(%8(5D$(04P(3%4(
M544(15,(4PH@("`@($%L;"!T:&4@9G5N8W1I;VYS('=H;W-E(')E='5R;B!T
M>7!E(&ES(&!@7PAI7PAN7PAT)R<@=7-E('1H92!S=&%N9&%R9"!C;VYV96XM
M"B`@("`@=&EO;B!O9B!R971U<FYI;F<@>F5R;R`H,"D@=&\@:6YD:6-A=&4@
M<W5C8V5S<RP@;W(@<F5T=7)N:6YG(&!@7P@M7P@Q)R<@86YD"B`@("`@<V5T
M=&EN9R!?"&5?"')?"')?"&Y?"&\@=&\@:6YD:6-A=&4@9F%I;'5R92X@($]T
M:&5R(&9U;F-T:6]N<R!H879E(')E='5R;B!V86QU97,@87,*("`@("!I;F1I
M8V%T960@86)O=F4N"@I%"$52"%)2"%)/"$]2"%)3"%,*("`@("!4:&4@<&]S
M<VEB;&4@=F%L=65S(&9O<B!?"&5?"')?"')?"&Y?"&\@=VAE;B!O;F4@;V8@
M=&AE(&!@7PAI7PAN7PAT)R<@9G5N8W1I;VYS(&EN('1H:7,*("`@("!L:6)R
M87)Y(')E='5R;G,@8&!?""U?"#$G)R!I;F-L=61E('1H;W-E(&]F('1H92!3
M=&%N9&%R9"!#($QI8G)A<GD@86YD(&%L<V\Z"@H@("`@(%M%24Y604Q=("`@
M("`@(%-O;64@9G5N8W1I;VX@87)G=6UE;G0@:&%S(&%N('5N<F5A<V]N86)L
M92!V86QU92X*"B`@("`@6T5)3E9!3%T@("`@("`@5&AE('-P96-I9FEE9"!F
M:6QE(&1E<V-R:7!T;W(@:&%S(&%N(&EN=&5G97(@=F%L=64@9W)E871E<@H@
M("`@("`@("`@("`@("`@("`@('1H86X@=&AE(&1E9F%U;'0@7PA&7PA$7PA?
M7PA37PA%7PA47PA37PA)7PA:7PA%+"!M96%N:6YG('1H870@=&AE(&%P<&QI
M8V$M"B`@("`@("`@("`@("`@("`@("`@=&EO;B=S(&QI;6ET(&ES(&AI9VAE
M<B!T:&%N('1H92!L:6)R87)Y)W,N"@H@("`@(%M%3D]%3E1=("`@("`@(%1H
M92!S<&5C:69I960@979E;G0@240@9&]E<R!N;W0@97AI<W0N"@H@("`@(%M%
M5T]53$1"3$]#2UT@($YO(&5V96YT<R!H879E(&]C8W5R<F5D(&%N9"!T:&4@
M7PA%7PA67PA?7PA07PA/7PA,7PA,(&]P=&EO;B!W87,@<W!E8VDM"B`@("`@
M("`@("`@("`@("`@("`@9FEE9"X*"B`@("`@6T5"041&72`@("`@("`@5&AE
M('-P96-I9FEE9"!S:6=N86P@=V%S('5N8FQO8VME9"!O=71S:61E('1H92!L
M:6)R87)Y+@H*4PA310A%10A%($$(04P(3%,(4T\(3PH@("`@('-E;&5C="@R
M*2P@(&UA;&QO8R@S*2P@(%AT36%I;DQO;W`H,RD*"D@(2$D(25,(4U0(5$\(
M3U((4ED(60H@("`@(%1H92!E"&5V"'9E"&5N"&YT"'1L"&QI"&EB"&(@;&EB
M<F%R>2!W87,@9&5S:6=N960@8GD@4&%U;"!6:7AI92!W:71H(&5X8V5L;&5N
M="!A9'9I8V4*("`@("!F<F]M(&AI<R!F<FEE;F1S(&%N9"!W:71H(&$@=&EP
M("=O('1H92!C87`@=&\@=&AE(%@@0V]N<V]R=&EU;2X*"C1T:"!"97)K96QE
M>2!$:7-T<FEB=71I;VX@("`@(%-E<'1E;6)E<B`Q-"P@,3DY-2`@("`@("`@
7("`@("`@("`@("`@("`@("`@("`@-`IE
`
end
SHAR_EOF
  $shar_touch -am 0917161295 'eventlib.lpcat' &&
  chmod 0664 'eventlib.lpcat' ||
  echo 'restore of eventlib.lpcat failed'
  shar_count="`wc -c < 'eventlib.lpcat'`"
  test 13118 -eq "$shar_count" ||
    echo "eventlib.lpcat: original size 13118, current size $shar_count"
fi
# ============= eventlib.pscat ==============
if test -f 'eventlib.pscat' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib.pscat (file already exists)'
else
  echo 'x - extracting eventlib.pscat (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'eventlib.pscat' &&
%!PS-Adobe-3.0
%%Creator: groff version 1.09
%%CreationDate: Sun Sep 17 16:12:39 1995
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Courier-Bold
%%+ font Courier-Oblique
%%+ font Symbol
%%+ font Courier
%%DocumentSuppliedResources: procset grops 1.09 0
%%Pages: 3
%%PageOrder: Ascend
%%Orientation: Portrait
%%EndComments
%%BeginProlog
%%BeginResource: procset grops 1.09 0
/setpacking where{
pop
currentpacking
true setpacking
}if
/grops 120 dict dup begin
/SC 32 def
/A/show load def
/B{0 SC 3 -1 roll widthshow}bind def
/C{0 exch ashow}bind def
/D{0 exch 0 SC 5 2 roll awidthshow}bind def
/E{0 rmoveto show}bind def
/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
/G{0 rmoveto 0 exch ashow}bind def
/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/I{0 exch rmoveto show}bind def
/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
/K{0 exch rmoveto 0 exch ashow}bind def
/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/M{rmoveto show}bind def
/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
/O{rmoveto 0 exch ashow}bind def
/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/Q{moveto show}bind def
/R{moveto 0 SC 3 -1 roll widthshow}bind def
/S{moveto 0 exch ashow}bind def
/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/SF{
findfont exch
[exch dup 0 exch 0 exch neg 0 0]makefont
dup setfont
[exch/setfont cvx]cvx bind def
}bind def
/MF{
findfont
[5 2 roll
0 3 1 roll 
neg 0 0]makefont
dup setfont
[exch/setfont cvx]cvx bind def
}bind def
/level0 0 def
/RES 0 def
/PL 0 def
/LS 0 def
/PLG{
gsave newpath clippath pathbbox grestore
exch pop add exch pop
}bind def
/BP{
/level0 save def
1 setlinecap
1 setlinejoin
72 RES div dup scale
LS{
90 rotate
}{
0 PL translate
}ifelse
1 -1 scale
}bind def
/EP{
level0 restore
showpage
}bind def
/DA{
newpath arcn stroke
}bind def
/SN{
transform
X.25 sub exch .25 sub exch
round .25 add exch round .25 add exch
itransform
}bind def
/DL{
SN
moveto
SN
lineto stroke
}bind def
/DC{
newpath 0 360 arc closepath
}bind def
/TM matrix def
/DE{
TM currentmatrix pop
translate scale newpath 0 0 .5 0 360 arc closepath
TM setmatrix
}bind def
/RC/rcurveto load def
/RL/rlineto load def
/ST/stroke load def
/MT/moveto load def
/CL/closepath load def
/FL{
currentgray exch setgray fill setgray
}bind def
/BL/fill load def
/LW/setlinewidth load def
/RE{
findfont
dup maxlength 1 index/FontName known not{1 add}if dict begin
{
1 index/FID ne{def}{pop pop}ifelse
}forall
/Encoding exch def
dup/FontName exch def
currentdict end definefont pop
}bind def
/DEFS 0 def
/EBEGIN{
moveto
DEFS begin
}bind def
/EEND/end load def
/CNT 0 def
/level1 0 def
/PBEGIN{
/level1 save def
translate
div 3 1 roll div exch scale
neg exch neg exch translate
0 setgray
0 setlinecap
1 setlinewidth
0 setlinejoin
10 setmiterlimit
[]0 setdash
/setstrokeadjust where{
pop
false setstrokeadjust
}if
/setoverprint where{
pop
false setoverprint
}if
newpath
/CNT countdictstack def
userdict begin
/showpage{}def
}bind def
/PEND{
clear
countdictstack CNT sub{end}repeat
level1 restore
}bind def
end def
/setpacking where{
pop
setpacking
}if
%%EndResource
%%IncludeResource: font Times-Roman
%%IncludeResource: font Times-Bold
%%IncludeResource: font Courier-Bold
%%IncludeResource: font Courier-Oblique
%%IncludeResource: font Symbol
%%IncludeResource: font Courier
grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
/Courier@0 ENC0/Courier RE/Courier-Oblique@0 ENC0/Courier-Oblique RE
/Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE
/Times-Roman@0 ENC0/Times-Roman RE
%%EndProlog
%%Page: 1 1
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF -.834(EVENTLIB \( 3 \))72 48 R(BSD Programmer')
112.632 E 2.5(sM)-.55 G 110.132(anual EVENTLIB)-2.5 F 1.666(\(3\))1.666
G/F1 10/Times-Bold@0 SF -.2(NA)72 108 S(ME).2 E/F2 10/Courier-Bold@0 SF
(evOpen)102 120 Q F0(,)A F2(evClose)7.084 E F0(,)A F2(evGetNext)7.084 E
F0(,)A F2(evDispatch)7.083 E F0(,)A F2(evMainLoop)7.083 E F0(,)A F2
(evConsTimeV)7.083 E F0(,)A F2(evAddTimeV)7.083 E F0(,)A F2(evSubTimeV)
102 132 Q F0(,)A F2(evCmpTimeV)7.8 E F0(,)A F2(evSetTimer)7.8 E F0(,)A
F2(evClearTimer)7.8 E F0(,)A F2(evSelectFD)7.8 E F0(,)A F2(evDeselectFD)
7.8 E F0(,)A F2(evSetSignal)102 144 Q F0(,)A F2(evClearSignal)3.443 E F0
(,)A F2(evTimerFunc)3.443 E F0(,)A F2(evUserFunc)3.443 E F0(,)A F2
(evSignalFunc)3.443 E F0 3.443<ad65>3.443 G -.15(ve)-3.693 G .942
(nt handling).15 F(library)102 156 Q F1(SYNOPSIS)72 180 Q F2
(#include <eventlib.h>)102 192 Q(evOpen)102 210 Q F0(\()A/F3 10
/Courier-Oblique@0 SF(evContext)A/F4 10/Symbol SF(*)6 E F3(ctx)A F0(\);)
A F2(evClose)102 228 Q F0(\()A F3(evContext ctx)A F0(\);)A F2(evGetNext)
102 246 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E F3(evEvent)4.166 E F4
(*)6 E F3(ev)A F0(,)1.666 E F3(int options)4.166 E F0(\);)A F2
(evDispatch)102 264 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E F3
(evEvent ev)4.166 E F0(\);)A F2(evMainLoop)102 282 Q F0(\()A F3
(evContext ctx)A F0(\);)A F3(struct timeval)102 300 Q F2(evConsTimeV)102
312 Q F0(\()A F3(int sec)A F0(,)1.666 E F3(int usec)4.166 E F0(\);)A F3
(struct timeval)102 330 Q F2(evAddTimeV)102 342 Q F0(\()A F3
(struct timeval addend1)A F0(,)1.666 E F3(struct timeval addend2)4.166 E
F0(\);)A F3(struct timeval)102 360 Q F2(evSubTimeV)102 372 Q F0(\()A F3
(struct timeval minuend)A F0(,)1.666 E F3(struct timeval subtrahend)
4.166 E F0(\);)A F3(struct timeval)102 390 Q F2(evCmpTimeV)102 402 Q F0
(\()A F3(struct timeval a)A F0(,)1.666 E F3(struct timeval b)4.166 E F0
(\);)A F2(evSetTimer)102 420 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E
F3(evTimerFunc func)4.166 E F0(,)1.666 E F3(void)4.166 E F4(*)6 E F3
(uap)A F0(,)1.666 E F3(struct timeval due)4.166 E F0(,)1.666 E F3
(struct timeval inter)151.666 432 Q F0(,)1.666 E F3(evTimerID)4.166 E F4
(*)6 E F3(id)A F0(\);)A F2(evClearTimer)102 450 Q F0(\()A F3
(evContext ctx)A F0(,)1.666 E F3(evTimerID id)4.166 E F0(\);)A F2
(evSelectFD)102 468 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E F3(int fd)
4.166 E F0(,)1.666 E F3(int eventmask)4.166 E F0(,)1.666 E F3
(evFileFunc func)4.166 E F0(,)1.666 E F3(void)4.166 E F4(*)6 E F3(uap)A
F0(,)1.666 E F3(evFileID)151.666 480 Q F4(*)6 E F3(id)A F0(\);)A F2
(evDeselectFD)102 498 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E F3
(evFileID id)4.166 E F0(\);)A F2(evSetSignal)102 516 Q F0(\()A F3
(evContext ctx)A F0(,)1.666 E F3(int sig)4.166 E F0(,)1.666 E F3
(evSignalFunc func)4.166 E F0(,)1.666 E F3(void)4.166 E F4(*)6 E F3(uap)
A F0(,)1.666 E F3(evSignalID)151.666 528 Q F4(*)6 E F3(ID)A F0(\);)A F2
(evClearSignal)102 546 Q F0(\()A F3(evContext ctx)A F0(,)1.666 E F3
(evSignalID ID)4.166 E F0(\);)A F3(typedef void)102 564 Q F2(\()102 576
Q F4(*)A F2(evTimerFunc\))A F0(\()A F3(evContext ctx)A F0(,)1.666 E F3
(void)4.166 E F4(*)6 E F3(uap)A F0(,)1.666 E F3(struct timeval due)4.166
E F0(,)1.666 E F3(struct timeval inter)151.666 588 Q F0(\);)A F3
(typedef void)102 606 Q F2(\()102 618 Q F4(*)A F2(evFileFunc\))A F0(\()A
F3(evContext ctx)A F0(,)1.666 E F3(void)4.166 E F4(*)6 E F3(uap)A F0(,)
1.666 E F3(int fd)4.166 E F0(,)1.666 E F3(int eventmask)4.166 E F0(\);)A
F3(typedef void)102 636 Q F2(\()102 648 Q F4(*)A F2(evSignalFunc\))A F0
(\()A F3(evContext ctx)A F0(,)1.666 E F3(void)4.166 E F4(*)6 E F3(uap)A
F0(,)1.666 E F3(int sig)4.166 E F0(\);)A F1(DESCRIPTION)72 672 Q F0
1.121(This library pro)102 684 R 1.122(vides multiple outstanding async\
hronous timers and I/O to a cooperating application.)-.15 F(The)6.122 E
1.167(model is similar to that of the X T)102 696 R 1.167
(oolkit, in that e)-.8 F -.15(ve)-.25 G 1.167(nts are re).15 F 1.167
(gistered with the library and the application)-.15 F .925
(spends most of its time in the)102 708 R F2(evMainLoop)3.425 E F0
-2.407 1.666(\(\) f)D 3.425(unction. If)-1.666 F .925
(an application already has a main loop, it can)3.425 F(4th Berk)72 756
Q(ele)-.1 E 2.5(yD)-.15 G(istrib)-2.5 E 89.595(ution September)-.2 F
(14, 1995)2.5 E(1)188.865 E EP
%%Page: 2 2
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF -.834(EVENTLIB \( 3 \))72 48 R(BSD Programmer')
112.632 E 2.5(sM)-.55 G 110.132(anual EVENTLIB)-2.5 F 1.666(\(3\))1.666
G 5.011(safely re)102 96 R 5.011(gister e)-.15 F -.15(ve)-.25 G 5.011
(nts with this library as long as it periodically calls the).15 F/F1 10
/Courier-Bold@0 SF(evGetNext)7.511 E F0 1.679 1.666(\(\) a)D(nd)-1.666 E
F1(evDispatch)102 108 Q F0 -3.332 1.666(\(\) f)D 2.5(unctions. \(Note)
-1.666 F(that)2.5 E F1(evGetNext)2.5 E F0 -3.332 1.666(\(\) h)D
(as both polling and blocking modes.\))-1.666 E .846(The function)102
126 R F1(evOpen)3.346 E F0 -2.486 1.666(\(\) c)D .846(reates an e)-1.666
F -.15(ve)-.25 G .846(nt conte).15 F .846
(xt which is needed by all the other functions in this library)-.15 F(.)
-.65 E 1.233
(All information used internally by this library is bound to this conte)
102 138 R 1.232(xt, rather than to static storage.)-.15 F(This)6.232 E
(mak)102 150 Q .481(es the library `)-.1 F .481(`thread safe,)-.74 F
1.961 -.74('' a)-.7 H .481(nd permits other library functions to use e)
X.74 F -.15(ve)-.25 G .482(nts without disrupting the ap-).15 F
(plication')102 162 Q 2.5(su)-.55 G(se of e)-2.5 E -.15(ve)-.25 G(nts.)
X.15 E 1.611(The function)102 180 R F1(evClose)4.111 E F0 -1.721 1.666
(\(\) d)D(estro)-1.666 E 1.611(ys a conte)-.1 F 1.61
(xt that has been created by)-.15 F F1(evOpen)4.11 E F0 4.11(\(\). All)B
1.61(dynamic memory)4.11 F 1.083(bound to this conte)102 192 R 1.083
(xt will be freed.)-.15 F 1.083(An implicit)6.083 F F1(evTimerClear)
3.583 E F0 -2.249 1.666(\(\) w)D 1.083
(ill be done on all timers set in this)-1.666 F -2.15 -.25(ev e)102 204
T .264(nt conte).25 F 2.764(xt. An)-.15 F(implicit)2.764 E F1
(evDeselectFD)2.764 E F0 -3.068 1.666(\(\) w)D .263
(ill be done on all \214le descriptors selected in this e)-1.666 F -.15
(ve)-.25 G .263(nt con-).15 F(te)102 216 Q(xt.)-.15 E .543(The function)
102 234 R F1(evGetNext)3.043 E F0 -2.788 1.666(\(\) p)D .544
(otentially w)-1.666 F .544(aits for and then retrie)-.1 F -.15(ve)-.25
G 3.044(st).15 G .544(he ne)-3.044 F .544(xt asynchronous e)-.15 F -.15
(ve)-.25 G .544(nt, placing it).15 F .017(in the object of the)102 246 R
/F2 10/Courier-Oblique@0 SF(ev)2.517 E F0 .017(pointer ar)2.517 F 2.517
(gument. T)-.18 F .217 -.1(wo m)-.8 H .017(utually e).1 F(xclusi)-.15 E
-.15(ve)-.25 G F2(options)2.666 E F0 .016(are a)2.516 F -.25(va)-.2 G
(ilable:).25 E F2(EV_POLL)2.516 E F0 2.516(,m)C(ean-)-2.516 E .707
(ing that)102 258 R F1(evGetNext)3.207 E F0 -2.625 1.666(\(\) s)D .708
(hould not block, b)-1.666 F .708(ut rather return `)-.2 F(`)-.74 E F2
(-1)A F0 2.188 -.74('' w)D(ith).74 E F2(errno)3.208 E F0 .708(set to)
3.208 F F2(EWOULDBLOCK)3.208 E F0 .708(if no)3.208 F -2.15 -.25(ev e)102
270 T .157(nts ha).25 F .457 -.15(ve o)-.2 H .157(ccurred; and).15 F F2
(EV_WAIT)2.657 E F0 2.657(,w)C .157(hich tells)-2.657 F F1(evGetNext)
2.657 E F0 -3.175 1.666(\(\) t)D 2.657(ob)-1.666 G .157(lock in)-2.657 F
/F3 10/Courier@0 SF(select)2.657 E F0 .157(\(2\) until the ne)B .156
(xt e)-.15 F -.15(ve)-.25 G(nt).15 E(occurs.)102 282 Q .05(The function)
102 300 R F1(evDispatch)2.55 E F0 -3.282 1.666(\(\) d)D .05
(ispatches an e)-1.666 F -.15(ve)-.25 G .05(nt retrie).15 F -.15(ve)-.25
G 2.55(db).15 G(y)-2.55 E F1(evGetNext)2.55 E F0 2.551(\(\). This)B .051
(usually in)2.551 F -.2(vo)-.4 G(lv).2 E .051(es calling)-.15 F .084
(the function that w)102 312 R .084(as associated with the e)-.1 F -.15
(ve)-.25 G .083(nt when the e).15 F -.15(ve)-.25 G .083(nt w).15 F .083
(as re)-.1 F .083(gistered with)-.15 F F1(evSetTimer)2.583 E F0 -3.249
1.666(\(\) o)D(r)-1.666 E F1(evS-)2.583 E(electFD)102 324 Q F0 3.09
(\(\). All)B -2.15 -.25(ev e)3.09 H .59(nts retrie).25 F -.15(ve)-.25 G
3.09(db).15 G(y)-3.09 E F1(evGetNext)3.09 E F0 -2.742 1.666(\(\) m)D
X.591(ust be gi)-1.666 F -.15(ve)-.25 G 3.091(no).15 G -.15(ve)-3.241 G
3.091(rt).15 G(o)-3.091 E F1(evDispatch)3.091 E F0 -2.741 1.666(\(\) a)D
3.091(ts)-1.666 G .591(ome point,)-3.091 F
(since there is some dynamic memory associated with each e)102 336 Q
-.15(ve)-.25 G(nt.).15 E(The function)102 354 Q F1(evMainLoop)2.5 E F0
-3.332 1.666(\(\) i)D 2.5(sj)-1.666 G(ust:)-2.5 E F3
(while \(\(x = evGetNext\(opaqueCtx, &event, EV_WAIT\)\) == 0\))132 372
Q(if \(\(x = evDispatch\(opaqueCtx, event\)\) < 0\))177 384 Q(break;)222
396 Q(return \(x\);)132 408 Q F0 1.335(In other w)102 426 R 1.335
(ords, get e)-.1 F -.15(ve)-.25 G 1.334
(nts and dispatch them until an error occurs.).15 F 1.334
(One such error w)6.334 F 1.334(ould be that all the)-.1 F -2.15 -.25
(ev e)102 438 T 3.13(nts under this conte).25 F 3.13(xt become unre)-.15
F 3.131(gistered; in that e)-.15 F -.15(ve)-.25 G 3.131
(nt, there will be nothing to w).15 F 3.131(ait for and)-.1 F F1
(evGetNext)102 450 Q F0 -3.332 1.666(\(\) b)D
(ecomes an unde\214ned operation.)-1.666 E .284(The function)102 468 R
F1(evConsTimeV)2.784 E F0 -3.048 1.666(\(\) i)D 2.784(sac)-1.666 G .283
(onstructor for `)-2.784 F(`)-.74 E F2 .283(struct timeval)B F0 1.763
-.74('' w)D .283(hich allo).74 F .283(ws these structures to)-.25 F .195
(be created and then passed as ar)102 480 R .196
(guments to other functions without the use of temporary v)-.18 F 2.696
(ariables. \(If)-.25 F 2.696(Ch)2.696 G(ad)-2.696 E
(inline constructors, there w)102 492 Q
(ould be no need for this function.\))-.1 E .185(The function)102 510 R
F1(evAddTimeV)2.685 E F0 -3.147 1.666(\(\) a)D .185(dds tw)-1.666 F
2.685(o`)-.1 G(`)-3.425 E F2 .185(struct timeval)B F0 1.665 -.74('' v)D
X.184(alues and returns the result as a `).49 F(`)-.74 E F2(struct)A
(timeval)102 522 Q F0 -.74('')C(.).74 E .06(The function)102 540 R F1
(evSubTimeV)2.56 E F0 -3.272 1.666(\(\) s)D .06(ubtracts its second `)
-1.666 F(`)-.74 E F2 .06(struct timeval)B F0 1.54 -.74('' a)D -.18(rg)
X.74 G .061(ument from its \214rst `).18 F(`)-.74 E F2(struct)A(timeval)
102 552 Q F0 1.48 -.74('' a)D -.18(rg).74 G
(ument and returns the result as a `).18 E(`)-.74 E F2(struct timeval)A
F0 -.74('')C(.).74 E .985(The function)102 570 R F1(evCmpTimeV)3.485 E
F0 -2.347 1.666(\(\) c)D .985(ompares its tw)-1.666 F 3.485(o`)-.1 G(`)
-4.225 E F2 .984(struct timeval)B F0 2.464 -.74('' a)D -.18(rg).74 G
X.984(uments and returns an `).18 F(`)-.74 E F2(int)A F0 -.74('')C .684
(that is less than zero if the \214rst ar)102 582 R .684(gument speci\
\214es an earlier time than the second, or more than zero if the)-.18 F
X.049(\214rst ar)102 594 R .049(gument speci\214es a later time than the\
X second, or equal to zero if both ar)-.18 F .049
(guments specify the same time.)-.18 F .433(The function)102 612 R F1
(evSetTimer)2.933 E F0 -2.899 1.666(\(\) r)D -.15(eg)-1.666 G .433
(isters a timer e).15 F -.15(ve)-.25 G .433(nt, which will be deli).15 F
-.15(ve)-.25 G .433(red as a function call to the func-).15 F .75
(tion speci\214ed by the)102 624 R F2(func)3.25 E F0(ar)3.25 E 3.25
(gument. The)-.18 F -2.15 -.25(ev e)3.25 H .75(nt will be deli).25 F
-.15(ve)-.25 G .749(red at time).15 F F2(due)3.249 E F0 3.249(,a)C .749
(nd then if time)-3.249 F F2(inter)3.249 E F0(is)3.249 E 1.004
(not equal to `)102 636 R(`)-.74 E F2(evConsTimeV\(0,0\))A F0 -.74('')C
3.504(,s).74 G 1.004(ubsequently at interv)-3.504 F 1.004
(als equal to time)-.25 F F2(inter)3.504 E F0 3.505(.A)C 3.505(sas)
-3.505 G 1.005(pecial case,)-3.505 F 1.257(specifying a)102 648 R F2
(due)3.757 E F0(ar)3.757 E 1.257(gument equal to `)-.18 F(`)-.74 E F2
(evConsTimeV\(0,0\))A F0 2.737 -.74('' m)D 1.257(eans `).74 F 1.256
(`due immediately)-.74 F -.7(.')-.65 G 6.256('T)-.04 G(he)-6.256 E F2
(id)3.756 E F0(ar)3.756 E(gu-)-.18 E .369(ment, if speci\214ed as a v)
102 660 R .37(alue other than)-.25 F F2(NULL)2.87 E F0 2.87(,w)C .37
(ill be used to store the resulting `)-2.87 F(`timer)-.74 E/F4 9
/Times-Roman@0 SF(ID)2.87 E F0 -.7(,')C 2.87('u)-.04 G .37
(seful as an ar)-2.87 F(-)-.2 E 1.142(gument to)102 672 R F1
(evClearTimer)3.642 E F0 3.642(\(\). Note)B 1.142(that in a `)3.642 F
1.142(`one shot')-.74 F 3.642('t)-.74 G 1.142(imer \(which has an)-3.642
F F2(inter)3.642 E F0(ar)3.642 E 1.141(gument equal to)-.18 F -.74(``)
102 684 S F2(evConsTimeV\(0,0\)).74 E F0 1.647 -.74('' \) t)D .167
(he user function).74 F F2(func)2.668 E F0 .168(should deallocate an)
2.668 F 2.668(yd)-.15 G .168(ynamic memory that is uniquely)-2.668 F
X.543(bound to the)102 696 R F2(uap)3.043 E F0 3.043(,s)C .543
(ince no handles to this memory will e)-3.043 F .543(xist within the e)
-.15 F -.15(ve)-.25 G .543(nt library after a one shot timer).15 F
(has been deli)102 708 Q -.15(ve)-.25 G(red.).15 E(4th Berk)72 756 Q
(ele)-.1 E 2.5(yD)-.15 G(istrib)-2.5 E 89.595(ution September)-.2 F
(14, 1995)2.5 E(2)188.865 E EP
%%Page: 3 3
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF -.834(EVENTLIB \( 3 \))72 48 R(BSD Programmer')
112.632 E 2.5(sM)-.55 G 110.132(anual EVENTLIB)-2.5 F 1.666(\(3\))1.666
G .256(The function)102 96 R/F1 10/Courier-Bold@0 SF(evClearTimer)2.756
E F0 -3.076 1.666(\(\) w)D .256(ill unre)-1.666 F .256
(gister the timer e)-.15 F -.15(ve)-.25 G .256(nt speci\214ed by).15 F
/F2 10/Courier-Oblique@0 SF(id)2.757 E F0 2.757(.N)C .257
(ote that if the)-2.757 F F2(uap)2.757 E F0(speci-)2.757 E .034
(\214ed in the corresponding)102 108 R F1(evSetTimer)2.534 E F0 -3.298
1.666(\(\) c)D .034(all is uniquely bound to an)-1.666 F 2.533(yd)-.15 G
X.033(ynamic memory)-2.533 F 2.533(,t)-.65 G .033(hen that dynamic)-2.533
F .631(memory should be freed by the caller before the handle is lost.)
102 120 R .631(After a call to)5.631 F F1(evClearTimer)3.131 E F0 .632
(\(\), no han-)B(dles to this)102 132 Q F2(uap)2.5 E F0(will e)2.5 E
(xist within the e)-.15 E -.15(ve)-.25 G(nt library).15 E(.)-.65 E 1.173
(The function)102 150 R F1(evSelectFD)3.673 E F0 -2.159 1.666(\(\) r)D
-.15(eg)-1.666 G 1.173(isters a \214le I/O e).15 F -.15(ve)-.25 G 1.173
(nt for the \214le descriptor speci\214ed by).15 F F2(fd)3.672 E F0
3.672(.B)C 1.172(its in the)-3.672 F F2(eventmask)102 162 Q F0(ar)3.372
E .872(gument are named)-.18 F F2(EV_READ)3.373 E F0(,)A F2(EV_WRITE)
3.373 E F0 3.373(,a)C(nd)-3.373 E F2(EV_EXCEPT)3.373 E F0 .873
(\(corresponding to the `)3.373 F(`read-)-.74 E(able,)102 174 Q 1.626
-.74('' ``)-.7 H(writable,).74 E 1.626 -.74('' a)-.7 H .146(nd `).74 F
(`e)-.74 E(xceptional')-.15 E 2.646('m)-.74 G .146(asks of the system')
-2.646 F(s)-.55 E/F3 10/Courier@0 SF(select)2.646 E F0 .146(\(2\) call.)
B .145(At least one of these bits must)5.146 F .652(be speci\214ed.)102
186 R .652(If the)5.652 F F2(id)3.152 E F0(ar)3.152 E .652
(gument is not equal to)-.18 F F2(NULL)3.152 E F0 3.152(,i)C 3.152(tw)
-3.152 G .652(ill be used to store a unique `)-3.152 F .652(`\214le e)
-.74 F -.15(ve)-.25 G(nt).15 E/F4 9/Times-Roman@0 SF(ID)3.152 E F0 2.133
-.74('' f)D(or).74 E(this e)102 198 Q -.15(ve)-.25 G
(nt, which is useful in subsequent calls to).15 E F1(evDelectFD)2.5 E F0
(\(\).)A 1.204(The function)102 216 R F1(evDeselectFD)3.704 E F0 -2.128
1.666(\(\) u)D(nre)-1.666 E 1.204(gisters the `)-.15 F 1.204(`\214le e)
-.74 F -.15(ve)-.25 G(nt').15 E 3.704('s)-.74 G 1.204(peci\214ed by the)
-3.704 F F2(id)3.704 E F0(ar)3.704 E 3.704(gument. If)-.18 F 1.203
(the corre-)3.703 F(sponding)102 228 Q F2(uap)3.514 E F0 1.014
(uniquely points to dynamic memory)3.514 F 3.514(,t)-.65 G 1.015
(hat memory should be freed before its handle is lost,)-3.514 F
(since after a call to)102 240 Q F1(evDeselectFD)2.5 E F0
(\(\), no handles to this e)A -.15(ve)-.25 G(nt').15 E(s)-.55 E F2(uap)
2.5 E F0(will remain within the e)2.5 E -.15(ve)-.25 G(nt library).15 E
(.)-.65 E F1(evSetSignal)102 258 Q F0 -2.835 1.666(\(\) b)D .497
(locks a signal from deli)-1.666 F -.15(ve)-.25 G .496(ry and re).15 F
X.496(gisters the)-.15 F F2(func)2.996 E F0 .496(to be called when)2.996
F F1(evDispatch)2.996 E F0 1.666(\(\))C(disco)102 270 Q -.15(ve)-.15 G
X.565(rs that this signal is pending.).15 F(The)5.566 E F2(id)3.066 E F0
(ar)3.066 E .566(gument, if not)-.18 F F2(NULL)3.066 E F0 3.066(,w)C
X.566(ill be used to store a unique `)-3.066 F(`signal)-.74 E F4(ID)102
282 Q F0 1.48 -.74('' f)D(or this e).74 E -.15(ve)-.25 G
(nt, which is useful in subsequent calls to).15 E F1(evClearSignal)2.5 E
F0 1.666(\(\))C .461(The function)102 300 R F1(evClearSignal)2.961 E F0
-2.871 1.666(\(\) d)D(ere)-1.666 E .461(gisters the speci\214ed signal)
-.15 F F2(id)2.961 E F0 2.961(,u)C .461(nblocking it if it w)-2.961 F
X.461(as unblock)-.1 F .461(ed be-)-.1 F .162(fore the corresponding)102
312 R F1(evSetSignal)2.662 E F0 -3.17 1.666(\(\) c)D 2.662(all. If)
-1.666 F .163(the corresponding)2.663 F F2(uap)2.663 E F0 .163
(uniquely points to dynamic memo-)2.663 F(ry)102 324 Q 3.173(,t)-.65 G
X.673(hat memory should be freed before its handle is lost, since after \
a call to)-3.173 F F1(evClearSignal)3.172 E F0 .672(\(\), no han-)B
(dles on this e)102 336 Q -.15(ve)-.25 G(nt').15 E(s)-.55 E F2(uap)2.5 E
F0(will e)2.5 E(xist within the e)-.15 E -.15(ve)-.25 G(nt library).15 E
(.)-.65 E/F5 10/Times-Bold@0 SF 1.666(RETURN V)72 360 R(ALUES)-1.35 E F0
X.794(All the functions whose return type is `)102 372 R(`)-.74 E F2(int)
A F0 2.274 -.74('' u)D .794(se the standard con).74 F -.15(ve)-.4 G .794
(ntion of returning zero \(0\) to indicate).15 F .014
(success, or returning `)102 384 R(`)-.74 E F2(-1)A F0 1.493 -.74('' a)D
X.013(nd setting).74 F F2(errno)2.513 E F0 .013(to indicate f)2.513 F
2.513(ailure. Other)-.1 F .013(functions ha)2.513 F .313 -.15(ve r)-.2 H
X.013(eturn v).15 F .013(alues as indi-)-.25 F(cated abo)102 396 Q -.15
(ve)-.15 G(.).15 E F5(ERR)72 420 Q(ORS)-.3 E F0 .32(The possible v)102
432 R .32(alues for)-.25 F F2(errno)2.82 E F0 .32(when one of the `)2.82
F(`)-.74 E F2(int)A F0 1.801 -.74('' f)D .321
(unctions in this library returns `).74 F(`)-.74 E F2(-1)A F0 1.801 -.74
('' i)D .321(nclude those).74 F(of the Standard C Library and also:)102
444 Q([)102.833 462 Q F3(EINVAL).833 E F0 37.841(]S).833 G
(ome function ar)-37.841 E(gument has an unreasonable v)-.18 E(alue.)
-.25 E([)102.833 480 Q F3(EINVAL).833 E F0 37.841(]T).833 G .164
(he speci\214ed \214le descriptor has an inte)-37.841 F .163(ger v)-.15
F .163(alue greater than the def)-.25 F(ault)-.1 E F2(FD_SETSIZE)2.663 E
F0(,)A(meaning that the application')185 492 Q 2.5(sl)-.55 G
(imit is higher than the library')-2.5 E(s.)-.55 E([)102.833 510 Q F3
(ENOENT).833 E F0 37.841(]T).833 G(he speci\214ed e)-37.841 E -.15(ve)
-.25 G(nt).15 E F4(ID)2.5 E F0(does not e)2.5 E(xist.)-.15 E([)102.833
528 Q F3(EWOULDBLOCK).833 E F0 7.841(]N).833 G 2.5(oe)-7.841 G -.15(ve)
-2.75 G(nts ha).15 E .3 -.15(ve o)-.2 H(ccurred and the).15 E F2
(EV_POLL)2.5 E F0(option w)2.5 E(as speci\214ed.)-.1 E([)102.833 546 Q
F3(EBADF).833 E F0 43.841(]T).833 G(he speci\214ed signal w)-43.841 E
(as unblock)-.1 E(ed outside the library)-.1 E(.)-.65 E F5 1.666
(SEE ALSO)72 570 R F3(select)102 582 Q F0(\(2\),)A F3(malloc)5 E F0
(\(3\),)A F3(XtMainLoop)5 E F0(\(3\))A F5(HIST)72 606 Q(OR)-.18 E(Y)-.35
E F0(The)102 618 Q F1(eventlib)2.96 E F0 .46(library w)2.96 F .46
(as designed by P)-.1 F .46(aul V)-.15 F .46(ixie with e)-.6 F .46
(xcellent advice from his friends and with a tip 'o)-.15 F
(the cap to the X Consortium.)102 630 Q(4th Berk)72 750 Q(ele)-.1 E 2.5
(yD)-.15 G(istrib)-2.5 E 89.595(ution September)-.2 F(14, 1995)2.5 E(3)
188.865 E EP
%%Trailer
end
%%EOF
SHAR_EOF
  $shar_touch -am 0917161295 'eventlib.pscat' &&
  chmod 0664 'eventlib.pscat' ||
  echo 'restore of eventlib.pscat failed'
  shar_count="`wc -c < 'eventlib.pscat'`"
  test 25096 -eq "$shar_count" ||
    echo "eventlib.pscat: original size 25096, current size $shar_count"
fi
# ============= eventlib.h ==============
if test -f 'eventlib.h' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib.h (file already exists)'
else
  echo 'x - extracting eventlib.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'eventlib.h' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* eventlib.h - exported interfaces for eventlib
X * vix 09sep95 [initial]
X *
X * $Id: eventlib.h,v 1.2 1995/09/17 23:12:25 vixie Exp $
X */
X
#ifndef _EVENTLIB_H
#define _EVENTLIB_H
X
#include <sys/time.h>
X
#ifndef __P
# ifdef __STDC__
#  define __P(x) x
# else
#  define __P(x)
# endif
#endif
X
/* In the absence of branded types... */
typedef struct { void *opaque; } evTimerID;
typedef struct { void *opaque; } evFileID;
typedef struct { void *opaque; } evSignalID;
typedef struct { void *opaque; } evContext;
typedef struct { void *opaque; } evEvent;
X
typedef void (*evTimerFunc)__P((evContext ctx, void *uap,
X				struct timeval due, struct timeval inter));
typedef void (*evFileFunc)__P((evContext ctx, void *uap, int fd, int evmask));
typedef void (*evSignalFunc)__P((evContext ctx, void *uap, int sig));
X
#define	EV_POLL		1
#define	EV_WAIT		2
X
#define	EV_READ		1
#define	EV_WRITE	2
#define	EV_EXCEPT	4
X
/* eventlib.c */
#define evOpen		__evOpen
#define evClose		__evClose
#define evGetNext	__evGetNext
#define evDispatch	__evDispatch
#define evMainLoop	__evMainLoop
X
int evOpen __P((evContext *ctx));
int evClose __P((evContext ctx));
int evGetNext __P((evContext ctx, evEvent *ev, int options));
int evDispatch __P((evContext ctx, evEvent ev));
int evMainLoop __P((evContext ctx));
X
/* timers.c */
#define evConsTimeV	__evConsTimeV
#define evAddTimeV	__evAddTimeV
#define evSubTimeV	__evSubTimeV
#define evCmpTimeV	__evCmpTimeV
#define evSetTimer	__evSetTimer
#define evClearTimer	__evClearTimer
X
struct timeval evConsTimeV __P((int sec, int usec));
struct timeval evAddTimeV __P((struct timeval add1, struct timeval add2));
struct timeval evSubTimeV __P((struct timeval minu, struct timeval subtra));
int evCmpTimeV __P((struct timeval a, struct timeval b));
int evSetTimer __P((evContext ctx, evTimerFunc func, void *uap,
X		    struct timeval due, struct timeval inter,
X		    evTimerID *id));
int evClearTimer __P((evContext ctx, evTimerID id));
X
/* files.c */
#define evSelectFD	__evSelectFD
#define evDeselectFD	__evDeselectFD
X
int evSelectFD __P((evContext ctx, int fd, int eventmask,
X		    evFileFunc func, void *uap, evFileID *id));
int evDeselectFD __P((evContext ctx, evFileID id));
X
/* signals.c */
#define evSetSignal	__evSetSignal
#define evClearSignal	__evClearSignal
X
int evSetSignal __P((evContext ctx, int sig, evSignalFunc func, void *uap,
X		     evSignalID *ID));
int evClearSignal __P((evContext ctx, evSignalID ID));
X
#endif /*_EVENTLIB_H*/
SHAR_EOF
  $shar_touch -am 0917161295 'eventlib.h' &&
  chmod 0444 'eventlib.h' ||
  echo 'restore of eventlib.h failed'
  shar_count="`wc -c < 'eventlib.h'`"
  test 3291 -eq "$shar_count" ||
    echo "eventlib.h: original size 3291, current size $shar_count"
fi
# ============= eventlib_p.h ==============
if test -f 'eventlib_p.h' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib_p.h (file already exists)'
else
  echo 'x - extracting eventlib_p.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'eventlib_p.h' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* eventlib_p.h - private interfaces for eventlib
X * vix 09sep95 [initial]
X *
X * $Id: eventlib_p.h,v 1.1 1995/09/17 05:30:26 vixie Exp $
X */
X
#ifndef _EVENTLIB_P_H
#define _EVENTLIB_P_H
X
#include <sys/param.h>
#include <sys/types.h>
X
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
X
#include "eventlib_p.h"
X
#ifdef DEBUG
extern int evDebugLev;
#define	DPRINTF(l,a)	if (l <= evDebugLev) printf a
#else
#define DPRINTF(l,a)
#endif
X
#define ERR(e)		for (;;) { errno = (e); return (-1); }
#define OK(x)		if ((x) < 0) ERR(errno) else NULL;
#define	NEW(p)		if (((p) = malloc(sizeof *(p))) != NULL) \
X				memset((p), 0xF5, sizeof *(p));
#define OKNEW(p)	if (!((p) = malloc(sizeof *(p)))) { \
X				errno = ENOMEM; \
X				return (-1); \
X			} else \
X				memset((p), 0xF5, sizeof *(p));
X
typedef struct evTimer {
X	evTimerFunc	func;
X	void		*uap;
X	struct timeval	due, inter;
X	struct evTimer	*next;
} evTimer;
X
typedef struct evFile {
X	evFileFunc	func;
X	void		*uap;
X	int		fd;
X	int		eventmask;
X	struct evFile	*next;
} evFile;
X
typedef struct evSignal {
X	evSignalFunc	func;
X	void		*uap;
X	int		sig;
X	struct sigaction oact;
X	struct evSignal *next;
} evSignal;
X
typedef struct {
X	/* Timers. */
X	evTimer		*timers;
X	/* Files. */
X	evFile	*files, *fdNext;
X	fd_set		rdLast, rdNext;
X	fd_set		wrLast, wrNext;
X	fd_set		exLast, exNext;
X	fd_set		nonblockBefore;
X	int		fdMax, fdCount;
X	/* Signals. */
X	evSignal	*signals;
X	sigset_t	blockedBefore;
} evContext_p;
X
typedef struct {
X	enum {Timer, File, Signal} type;
X	union {
X		struct {
X			evTimer		*this;
X		} timer;
X		struct {
X			evFile		*this;
X			int		eventmask;
X		} file;
X		struct {
X			evSignal	*this;
X		} signal;
X	} u;
} evEvent_p;
X
/* timers.c */
#define evRelinkTimers __evRelinkTimers
int evRelinkTimers(evContext_p *ctx, evTimer *del, evTimer *add);
X
#endif /*_EVENTLIB_P_H*/
SHAR_EOF
  $shar_touch -am 0916223095 'eventlib_p.h' &&
  chmod 0444 'eventlib_p.h' ||
  echo 'restore of eventlib_p.h failed'
  shar_count="`wc -c < 'eventlib_p.h'`"
  test 2694 -eq "$shar_count" ||
    echo "eventlib_p.h: original size 2694, current size $shar_count"
fi
# ============= eventlib.c ==============
if test -f 'eventlib.c' && test X"$1" != X"-c"; then
  echo 'x - skipping eventlib.c (file already exists)'
else
  echo 'x - extracting eventlib.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'eventlib.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* eventlib.c - implement clue for the eventlib
X * vix 09sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: eventlib.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include <assert.h>
X
#include "eventlib.h"
#include "eventlib_p.h"
X
static evEvent_p *GetSignal(evContext_p *ctx);
static const struct timeval NoTime = {0, 0};
static const struct timeval ShortTime = {1, 500000};
X
int
evOpen(evContext *opaqueCtx) {
X	evContext_p *ctx;
X
X	OKNEW(ctx);
X
X	/* Timers. */
X	ctx->timers = NULL;
X
X	/* Files. */
X	ctx->files = NULL;
X	FD_ZERO(&ctx->rdNext);
X	FD_ZERO(&ctx->wrNext);
X	FD_ZERO(&ctx->exNext);
X	FD_ZERO(&ctx->nonblockBefore);
X	ctx->fdMax = -1;
X	ctx->fdNext = NULL;
X	ctx->fdCount = 0;	/* Invalidate {rd,wr,ex}Last. */
X
X	/* Signals. */
X	ctx->signals = NULL;
X	sigemptyset(&ctx->blockedBefore);
X
X	opaqueCtx->opaque = ctx;
X	return (0);
}
X
int
evClose(evContext opaqueCtx) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	int revs = 424242;	/* Doug Adams. */
X
X	/* Timers. */
X	while (revs-- > 0 && ctx->timers != NULL) {
X		evTimerID timer;
X
X		timer.opaque = ctx->timers;
X		(void) evClearTimer(opaqueCtx, timer);
X	}
X
X	/* Files. */
X	while (revs-- > 0 && ctx->files != NULL) {
X		evFileID file;
X
X		file.opaque = ctx->files;
X		(void) evDeselectFD(opaqueCtx, file);
X	}
X
X	/* Signals. */
X	while (revs-- > 0 && ctx->signals != NULL) {
X		evSignalID sig;
X
X		sig.opaque = ctx->signals;
X		(void) evClearSignal(opaqueCtx, sig);
X	}
X
X	free(ctx);
X	return(0);
}
X
int
evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	struct timeval now, nextTime;
X	evTimer *nextTimer;
X	evEvent_p *new;
X	int x, timerPast;
X
X	/* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
X	x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
X	if (x != 1)
X		ERR(EINVAL);
X
X	/* Give signals top priority. */
X	if ((new = GetSignal(ctx)) != NULL) {
X		opaqueEv->opaque = new;
X		return (0);
X	}
X
X	/* Get the time of day.  We'll do this again after select() blocks. */
X	OK(gettimeofday(&now, NULL));
X
X	/* Get the status and content of the next timer. */
X	if ((nextTimer = ctx->timers) != NULL) {
X		nextTime = nextTimer->due;
X		timerPast = (evCmpTimeV(nextTime, now) <= 0);
X	}
X
X again:
X	DPRINTF(9, ("evGetNext: again: fdCount %d\n", ctx->fdCount));
X	if (!ctx->fdCount) {
X		enum { JustPoll, ShortPoll, Block, Timer } m;
X		struct timeval t, *tp;
X
X		/* Are there any events at all? */
X		if ((options & EV_WAIT) && !nextTimer && ctx->fdMax == -1 &&
X		    !ctx->signals)
X			ERR(ENOENT);
X
X		/* Figure out what select()'s timeout parameter should be. */
X		if (options & EV_POLL) {
X			m = JustPoll;
X			t = NoTime;
X			tp = &t;
X		} else if (! nextTimer) {
X			if (ctx->signals) {
X				m = ShortPoll;
X				t = ShortTime;
X				tp = &t;
X			} else {
X				m = Block;
X				/* ``t'' unused. */
X				tp = NULL;
X			}
X		} else if (timerPast) {
X			m = JustPoll;
X			t = NoTime;
X			tp = &t;
X		} else {
X			m = Timer;
X			/* ``t'' filled in later. */
X			tp = &t;
X		}
X
X		do {
X			/* We do these here due to possible EINTR. */
X			ctx->rdLast = ctx->rdNext;
X			ctx->wrLast = ctx->wrNext;
X			ctx->exLast = ctx->exNext;
X
X			/* We do this here due to possible EINTR. */
X			if (m == Timer) {
X				assert(tp == &t);
X				t = evSubTimeV(nextTime, now);
X				/* Do we need to ensure periodic sig polls? */
X				if (ctx->signals != NULL &&
X				    evCmpTimeV(t, ShortTime) > 0)
X					t = ShortTime;
X			}
X
X			DPRINTF(4, ("select(%d, %#x, %#x, %#x, %d.%06d)\n",
X				    ctx->fdMax+1,
X				    &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
X				    tp ? tp->tv_sec : -1,
X				    tp ? tp->tv_usec : -1));
X
X			x = select(ctx->fdMax+1,
X				   &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
X				   tp);
X
X			/* Did any signals come in during select()? */
X			if ((new = GetSignal(ctx)) != NULL) {
X				opaqueEv->opaque = new;
X				return (0);
X			}
X
X			/* Anything but a poll can change the time. */
X			if (m != JustPoll)
X				OK(gettimeofday(&now, NULL));
X
X			/* Select() likes to finish about 10ms early. */
X			if (x == 0 && m == Timer &&
X			    evCmpTimeV(now, nextTime) < 0) {
X				/* Simulate EINTR, go back, select() again. */
X				x = -1;
X				errno = EINTR;
X			}
X
X			/* Are we polling for a signal? */
X			if (x == 0 && m == ShortPoll && ctx->signals) {
X				/* Simulate EINTR, go back, select() again. */
X				x = -1;
X				errno = EINTR;
X			}
X		} while (x < 0 && errno == EINTR);
X		if (x < 0)
X			ERR(errno);
X		if (x == 0 && !timerPast && (options & EV_POLL))
X			ERR(EWOULDBLOCK);
X		ctx->fdCount = x;
X	}
X	assert(nextTimer || ctx->fdCount);
X
X	/* Timers go first since we'd like them to be accurate. */
X	if (nextTimer && !timerPast) {
X		/* Has anything happened since we blocked? */
X		timerPast = (evCmpTimeV(nextTime, now) <= 0);
X	}
X	if (nextTimer && timerPast) {
X		OKNEW(new);
X		new->type = Timer;
X		new->u.timer.this = nextTimer;
X		opaqueEv->opaque = new;
X		return (0);
X	}
X
X	/* No timers, so there must be a ready file descriptor. */
X	while (ctx->fdCount) {
X		register evFile *fid;
X		register int fd, eventmask;
X
X		if (!ctx->fdNext)
X			ctx->fdNext = ctx->files;
X		fid = ctx->fdNext;
X		ctx->fdNext = fid->next;
X
X		fd = fid->fd;
X		eventmask = 0;
X		if (FD_ISSET(fd, &ctx->rdLast))
X			eventmask |= EV_READ;
X		if (FD_ISSET(fd, &ctx->wrLast))
X			eventmask |= EV_WRITE;
X		if (FD_ISSET(fd, &ctx->exLast))
X			eventmask |= EV_EXCEPT;
X		if (eventmask != 0) {
X			ctx->fdCount--;
X			OKNEW(new);
X			new->type = File;
X			new->u.file.this = fid;
X			new->u.file.eventmask = eventmask;
X			opaqueEv->opaque = new;
X			return (0);
X		}
X	}
X
X	/* We get here if the caller deselect()'s an FD. Gag me with a goto. */
X	goto again;
}
X
static evEvent_p *
GetSignal(evContext_p *ctx) {
X	evEvent_p *new;
X	evSignal *cur;
X	sigset_t set;
X
X	if (sigpending(&set) < 0)
X		return (NULL);
X	for (cur = ctx->signals; cur; cur = cur->next)
X		if (sigismember(&set, cur->sig))
X			break;
X	if (!cur)
X		return (NULL);
X
X	/*
X	 * Briefly unblock and then reblock the signal.  According to
X	 * IEEE Std1003.1-1988 ("POSIX") 3.3.5.1, at least one signal
X	 * will be delivered before a return from an unblocking call
X	 * to setprocmask().  Since we're only unblocking one signal,
X	 * and it's one that sigpending() says is pending (see above),
X	 * this ought to clear the signal (and the sigpending().)  We
X	 * immediately turn around and reblock this signal afterward.
X	 */
X	sigemptyset(&set);
X	sigaddset(&set, cur->sig);
X	(void) sigprocmask(SIG_UNBLOCK, &set, NULL);
X	(void) sigpending(&set);
X	assert(sigismember(&set, cur->sig) <= 0);
X	sigemptyset(&set);
X	sigaddset(&set, cur->sig);
X	(void) sigprocmask(SIG_BLOCK, &set, NULL);
X
X	NEW(new);
X	if (!new) {
X		/* Note: we're silently losing a signal in this case. */
X		errno = ENOMEM;
X		return (NULL);
X	}
X	new->type = Signal;
X	new->u.signal.this = cur;
X	return (new);
}
X
int
evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evEvent_p *ev = opaqueEv.opaque;
X
X	switch (ev->type) {
X	    case Timer: {
X		evTimer *this = ev->u.timer.this;
X
X		(this->func)(opaqueCtx, this->uap, this->due, this->inter);
X		if (this->inter.tv_sec == 0 && this->inter.tv_usec == 0) {
X			evTimerID opaque;
X
X			opaque.opaque = this;			
X			(void) evClearTimer(opaqueCtx, opaque);
X		} else {
X			this->due = evAddTimeV(this->due, this->inter);
X			/* XXX a signal that called evSetTimer() would hurt. */
X			evRelinkTimers(ctx, this, this);
X		}
X		break;
X	    }
X	    case File: {
X		evFile *this = ev->u.file.this;
X		int eventmask = ev->u.file.eventmask;
X
X		(this->func)(opaqueCtx, this->uap, this->fd, eventmask);
X		break;
X	    }
X	    case Signal: {
X		evSignal *this = ev->u.signal.this;
X
X		(this->func)(opaqueCtx, this->uap, this->sig);
X		break;
X	    }
X	    default: {
X		abort();
X	    }
X	}
X	return (0);
}
X
int
evMainLoop(evContext opaqueCtx) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evEvent event;
X	int x;
X
X	while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
X		if ((x = evDispatch(opaqueCtx, event)) < 0)
X			break;
X	return (x);
}
X
SHAR_EOF
  $shar_touch -am 0917161295 'eventlib.c' &&
  chmod 0444 'eventlib.c' ||
  echo 'restore of eventlib.c failed'
  shar_count="`wc -c < 'eventlib.c'`"
  test 8744 -eq "$shar_count" ||
    echo "eventlib.c: original size 8744, current size $shar_count"
fi
# ============= timers.c ==============
if test -f 'timers.c' && test X"$1" != X"-c"; then
  echo 'x - skipping timers.c (file already exists)'
else
  echo 'x - extracting timers.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'timers.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* timers.c - implement timers for the eventlib
X * vix 09sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: timers.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include "eventlib.h"
#include "eventlib_p.h"
X
static void LinkTimer(evContext_p *ctx, evTimer *old, evTimer *add);
static void UnlinkTimer(evContext_p *ctx, evTimer *old, evTimer *cur);
X
#ifdef DEBUG
static void PrintTimers(const evContext_p *ctx, char *label);
#else
#define PrintTimers(ctx,label)
#endif
X
struct timeval
evConsTimeV(int sec, int usec) {
X	struct timeval x;
X
X	x.tv_sec = sec;
X	x.tv_usec = usec;
X	return (x);
}
X
struct timeval
evAddTimeV(struct timeval addend1, struct timeval addend2) {
X	struct timeval x;
X
X	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
X	x.tv_usec = addend1.tv_usec + addend2.tv_usec;
X	if (x.tv_usec >= 1000000) {
X		x.tv_sec++;
X		x.tv_usec -= 1000000;
X	}
X	return (x);
}
X
struct timeval
evSubTimeV(struct timeval minuend, struct timeval subtrahend) {
X	struct timeval x;
X
X	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
X	if (minuend.tv_usec >= subtrahend.tv_usec) {
X		x.tv_usec = minuend.tv_usec - subtrahend.tv_usec;
X	} else {
X		x.tv_usec = 1000000 - subtrahend.tv_usec + minuend.tv_usec;
X		x.tv_sec--;
X	}
X	return (x);
}
X
int
evCmpTimeV(struct timeval a, struct timeval b) {
X	int x = a.tv_sec - b.tv_sec;
X
X	if (! x)
X		x = a.tv_usec - b.tv_usec;
X	DPRINTF(99, ("evCmpTimeV(%d.%06d, %d.%06d) -> %d\n",
X		    a.tv_sec, a.tv_usec, b.tv_sec, b.tv_usec, x));
X	return (x);
}
X
int
evSetTimer(evContext opaqueCtx,
X	   evTimerFunc func,
X	   void *uap,
X	   struct timeval due,
X	   struct timeval inter,
X	   evTimerID *opaqueID
) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evTimer *id;
X
X	DPRINTF(1, (
"evSetTimer(ctx %#x, func %#x, uap %#x, due %d.%06d, inter %d.%06d)\n",
X		    ctx, func, uap,
X		    due.tv_sec, due.tv_usec,
X		    inter.tv_sec, inter.tv_usec));
X
X	/* due={0,0} is a magic cookie meaning "now." */
X	if (due.tv_sec == 0 && due.tv_usec == 0)
X		OK(gettimeofday(&due, NULL));
X
X	/* Allocate and fill. */
X	OKNEW(id);
X	id->func = func;
X	id->uap = uap;
X	id->due = due;
X	id->inter = inter;
X
X	/* Insert in ``due'' order. */
X	(void) evRelinkTimers(ctx, /*harmless*/id, id);
X
X	/* Remember the ID if the caller provided us a place for it. */
X	if (opaqueID)
X		opaqueID->opaque = id;
X
X	return (0);
}
X
int
evClearTimer(evContext opaqueCtx, evTimerID id) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evTimer *del = id.opaque, *old, *cur;
X
X	/* Find element whose ID matches caller's. */
X	for (old = NULL, cur = ctx->timers;
X	     cur != NULL && cur != del;
X	     old = cur, cur = cur->next)
X		NULL;
X	if (! cur)
X		ERR(ENOENT);
X
X	UnlinkTimer(ctx, old, cur);
X	(void) free(cur);
X	return (0);
}
X
int
evRelinkTimers(evContext_p *ctx, evTimer *del, evTimer *add) {
X	evTimer *old, *cur;
X
X	/* In one pass, delete ``del'' and insert ``add'' in time-due order. */
X	for (old = NULL, cur = ctx->timers;
X	     cur != NULL && (del != NULL || add != NULL);
X	     cur = cur->next) {
X		if (cur == del) {
X			UnlinkTimer(ctx, old, cur);
X			del = NULL;
X			continue;
X		}
X		if (add && evCmpTimeV(cur->due, add->due) > 0) {
X			LinkTimer(ctx, old, add);
X			cur = add;
X			add = NULL;
X		}
X		old = cur;
X	}
X	if (add)
X		LinkTimer(ctx, old, add);
X	if (del)
X		ERR(ENOENT);
X	PrintTimers(ctx, "after relink");
X	return (0);
}
X
static void
LinkTimer(evContext_p *ctx, evTimer *old, evTimer *add) {
X	if (! old) {
X		add->next = ctx->timers;
X		ctx->timers = add;
X	} else {
X		add->next = old->next;
X		old->next = add;
X	}
X	PrintTimers(ctx, "after link");
}
X
static void
UnlinkTimer(evContext_p *ctx, evTimer *old, evTimer *cur) {
X	if (! old)
X		ctx->timers = cur->next;
X	else
X		old->next = cur->next;
X	PrintTimers(ctx, "after unlink");
}
X
#ifdef DEBUG
static void PrintTimers(const evContext_p *ctx, char *label) {
X	const evTimer *cur;
X
X	DPRINTF(2, ("PrintTimers [%s]:\n", label));
X	for (cur = ctx->timers; cur; cur = cur->next)
X		DPRINTF(2, (
"\tfunc %#x, uap %#x, due %d.%06d, inter %d.%06d, next %#x\n",
X			    cur->func, cur->uap,
X			    cur->due.tv_sec, cur->due.tv_usec,
X			    cur->inter.tv_sec, cur->inter.tv_usec,
X			    cur->next));
}
#endif
SHAR_EOF
  $shar_touch -am 0917161295 'timers.c' &&
  chmod 0444 'timers.c' ||
  echo 'restore of timers.c failed'
  shar_count="`wc -c < 'timers.c'`"
  test 4959 -eq "$shar_count" ||
    echo "timers.c: original size 4959, current size $shar_count"
fi
# ============= files.c ==============
if test -f 'files.c' && test X"$1" != X"-c"; then
  echo 'x - skipping files.c (file already exists)'
else
  echo 'x - extracting files.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'files.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* files.c - implement asynch file IO for the eventlib
X * vix 11sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: files.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include "eventlib.h"
#include "eventlib_p.h"
X
static evFile *FindFD(const evContext_p *ctx, int fd);
X
int
evSelectFD(evContext opaqueCtx,
X	   int fd,
X	   int eventmask,
X	   evFileFunc func,
X	   void *uap,
X	   evFileID *opaqueID
) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evFile *id;
X	int mode;
X
X	DPRINTF(1,("evSelectFD(ctx %#x, fd %d, mask 0x%x, func %#x, uap %#x)\n",
X		   ctx, fd, eventmask, func, uap));
X	if (!eventmask || (eventmask & ~(EV_READ|EV_WRITE|EV_EXCEPT)))
X		ERR(EINVAL);
X	if (fd >= FD_SETSIZE)
X		ERR(EINVAL);
X	OK(mode = fcntl(fd, F_GETFL, NULL));	/* side effect: validate fd. */
X
X	/*
X	 * The first time we touch a file descriptor, we need to check to see
X	 * if the application already had it in O_NONBLOCK mode and if so, all
X	 * of our deselect()'s have to leave it in O_NONBLOCK.  If not, then
X	 * all but our last deselect() has to leave it in O_NONBLOCK.
X	 */
X	if (! (id = FindFD(ctx, fd))) {
X		if (mode & O_NONBLOCK)
X			FD_SET(fd, &ctx->nonblockBefore);
X		else {
X			OK(fcntl(fd, F_SETFL, mode | O_NONBLOCK));
X			FD_CLR(fd, &ctx->nonblockBefore);
X		}
X	}
X
X	/* Allocate and fill. */
X	OKNEW(id);
X	id->func = func;
X	id->uap = uap;
X	id->fd = fd;
X	id->eventmask = eventmask;
X
X	/*
X	 * Insert at head.  Order could be important for performance if we
X	 * believe that evGetNext()'s accesses to the fd_sets will be more
X	 * serial and therefore more cache-lucky if the list is ordered by
X	 * ``fd.''  We do not believe these things, so we don't do it.
X	 *
X	 * The interesting sequence is where GetNext() has cached a select()
X	 * result and the caller decides to evSelectFD() on some descriptor.
X	 * Since GetNext() starts at the head, it can miss new entries we add
X	 * at the head.  This is not a serious problem since the event being
X	 * evSelectFD()'d for has to occur before evSelectFD() is called for
X	 * the file event to be considered "missed" -- a real corner case.
X	 * Maintaining a "tail" pointer for ctx->files would fix this, but I'm
X	 * not sure it would be ``more correct.''
X	 */
X	id->next = ctx->files;
X	ctx->files = id;
X
X	/* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */
X	if (eventmask & EV_READ)
X		FD_SET(fd, &ctx->rdNext);
X	if (eventmask & EV_WRITE)
X		FD_SET(fd, &ctx->wrNext);
X	if (eventmask & EV_EXCEPT)
X		FD_SET(fd, &ctx->exNext);
X
X	/* Update fdMax. */
X	if (fd > ctx->fdMax)
X		ctx->fdMax = fd;
X
X	/* Remember the ID if the caller provided us a place for it. */
X	if (opaqueID)
X		opaqueID->opaque = id;
X
X	return (0);
}
X
int
evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evFile *del = opaqueID.opaque;
X	evFile *old, *cur;
X	int mode, eventmask;
X
X	/* Get the mode.  Unless the file has been closed, errors are bad. */
X	mode = fcntl(del->fd, F_GETFL, NULL);
X	if (mode == -1 && errno != EBADF)
X		ERR(errno);
X
X	/* Remove this ID.  Its absense is an ENOENT error. */
X	for (old = NULL, cur = ctx->files;
X	     cur != NULL && cur != del;
X	     old = cur, cur = cur->next)
X		NULL;
X	if (! cur)
X		ERR(ENOENT);
X	if (! old)
X		ctx->files = del->next;
X	else
X		old->next = del->next;
X
X	/*
X	 * If the file descriptor does not appear in any other select() entry,
X	 * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode
X	 * earlier, then: restore the fd to blocking status.
X	 */
X	if (!(cur = FindFD(ctx, del->fd)) &&
X	    FD_ISSET(del->fd, &ctx->nonblockBefore) &&
X	    mode != -1) {
X		/*
X		 * Note that we won't return an error status to the caller if
X		 * this fcntl() fails since (a) we've already done the work
X		 * and (b) the caller didn't ask us anything about O_NONBLOCK.
X		 */
X		(void) fcntl(del->fd, F_SETFL, mode & ~O_NONBLOCK);
X	}
X
X	/*
X	 * We saved the position of the next use of this FD in the select list,
X	 * and if there is any such, we need to search the remainder of the
X	 * list OR'ing all the eventmasks for this fd together so that we don't
X	 * turn off {rd,wr,ex}Next bits that some other select is using.
X	 */
X	eventmask = 0;
X	for (; cur; cur = cur->next)
X		if (cur->fd == del->fd)
X			eventmask |= cur->eventmask;
X
X	/* OK, now we know which bits we can clear out. */
X	if (eventmask & EV_READ)
X		FD_CLR(del->fd, &ctx->rdNext);
X	if (eventmask & EV_WRITE)
X		FD_CLR(del->fd, &ctx->wrNext);
X	if (eventmask & EV_EXCEPT)
X		FD_CLR(del->fd, &ctx->exNext);
X
X	/* If this was the maxFD, find the new one. */
X	if (del->fd == ctx->fdMax) {
X		ctx->fdMax = -1;
X		for (cur = ctx->files; cur; cur = cur->next)
X			if (cur->fd > ctx->fdMax)
X				ctx->fdMax = cur->fd;
X	}
X
X	/* If this was the fdNext, cycle that to the next entry. */
X	if (del == ctx->fdNext)
X		ctx->fdNext = del->next;
X
X	/* Couldn't free it before now since we were using fields out of it. */
X	(void) free(del);
X
X	return (0);
}
X
static evFile *
FindFD(const evContext_p *ctx, int fd) {
X	evFile *id;
X
X	for (id = ctx->files; id != NULL && id->fd != fd; id = id->next)
X		NULL;
X	return (id);
}
SHAR_EOF
  $shar_touch -am 0917161295 'files.c' &&
  chmod 0444 'files.c' ||
  echo 'restore of files.c failed'
  shar_count="`wc -c < 'files.c'`"
  test 5896 -eq "$shar_count" ||
    echo "files.c: original size 5896, current size $shar_count"
fi
# ============= signals.c ==============
if test -f 'signals.c' && test X"$1" != X"-c"; then
  echo 'x - skipping signals.c (file already exists)'
else
  echo 'x - extracting signals.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'signals.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* signals.c - implement asynch signals for the eventlib
X * vix 16sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: signals.c,v 1.1 1995/09/17 05:30:26 vixie Exp $";
#endif
X
#include "eventlib.h"
#include "eventlib_p.h"
X
static evSignal *FindSig(const evContext_p *ctx, int sig);
static void EatMe(int mystery);
X
int
evSetSignal(evContext opaqueCtx, int sig,
X	    evSignalFunc func, void *uap,
X	    evSignalID *opaqueID
) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evSignal *old, *new;
X	struct sigaction act, oact;
X	sigset_t set, oset;
X	int save;
X
X	/*
X	 * POSIX gives us no way to validate the signal number, since there's
X	 * no requirement that sigaddset() return (-1) if given a bad signal
X	 * (and BSD's sigaddset() macro doesn't do so in any case.)  So we'll
X	 * try a sigaddset(), check it for errors, and then check its results.
X	 */
X	OK(sigemptyset(&set));
X	OK(sigaddset(&set, sig));
X	if (sigismember(&set, sig) <= 0)
X		ERR(EINVAL);
X
X	/*
X	 * If we already have something in the signal list for this signal,
X	 * then we want its ``oact,'' elsewise we need to get the ``oact''
X	 * from the system.
X	 */
X	old = FindSig(ctx, sig);
X
X	/*
X	 * Block the signal.  If it wasn't previously blocked and we had the
X	 * signal on the list, exit now.  If it was previously blocked and we
X	 * didn't have it on the list, remember the blockedness so that we
X	 * leave it blocked after evClearSignal().  Note that we block the
X	 * signal even if it's already on our signal list, since this gives
X	 * us a chance to blue chunks if it's not in fact blocked any more.
X	 *
X	 * Note that blocking the signal has the effect that our select() in
X	 * evGetNext() will not return with -1 and errno==EINTR when a signal
X	 * occurs.  We would rather not have that happen, but to fix it we
X	 * would have to let the signal call a handler, and that handler would
X	 * either have to have static global storage (to remember that the
X	 * signal had occured -- had for thread safety!).  We prefer polling,
X	 * while noting that POSIX should have defined a signal "uap" argument.
X	 */
X	OK(sigprocmask(SIG_BLOCK, &set, &oset));
X	if (!old) {
X		/* First catch of this signal.  Make blockedBefore right. */
X
X		if (sigismember(&oset, sig) > 0) {
X			/* Note that an error below doesn't need any fixups. */
X			OK(sigaddset(&ctx->blockedBefore, sig));
X		} else {
X			if (sigismember(&ctx->blockedBefore, sig) > 0)
X				OK(sigdelset(&ctx->blockedBefore, sig));
X		}
X
X		/*
X		 * Install a signal handler.  We don't do anything in the
X		 * handler, but the POSIX docs are unclear as to whether
X		 * SIG_IGN will preclude the sigpending() mask from ever
X		 * showing that the signal happened.  Since we rely on the
X		 * (obscure) POSIX semantics of sigprocmask() (see the
X		 * comments in evGetNext for more details), we want to make
X		 * sure that the kernel has no excuse not to set our
X		 * sigpending() mask bit.
X		 */
X		sigemptyset(&set);
X		act.sa_handler = EatMe;
X		act.sa_mask = set;
X		act.sa_flags = 0;
X		if (sigaction(sig, &act, &oact) < 0) {
X			save = errno;
X			(void) sigprocmask(SIG_SETMASK, &oset, NULL);/*Fixup.*/
X			ERR(errno);
X		}
X	} else {
X		/* This signal is already being caught.  Make sure, though. */
X
X		if (sigismember(&oset, sig) <= 0) {
X			(void) sigprocmask(SIG_SETMASK, &oset, NULL);/*Fixup.*/
X			ERR(EBADF);
X		}
X		oact = old->oact;
X	}
X
X	/* Allocate, fill, link. */
X	NEW(new);
X	if (!new) {
X		(void) sigprocmask(SIG_SETMASK, &oset, NULL);   /* Fixup. */
X		if (!old)
X			(void) sigaction(sig, &oact, NULL);
X		ERR(ENOMEM);
X	}
X	new->func = func;
X	new->uap = uap;
X	new->sig = sig;
X	new->oact = oact;
X	new->next = ctx->signals;
X	ctx->signals = new;
X
X	/* Save handle if we've been given one. */
X	if (opaqueID)
X		opaqueID->opaque = new;
X
X	return (0);
}
X
int
evClearSignal(evContext opaqueCtx, evSignalID opaqueID) {
X	evContext_p *ctx = opaqueCtx.opaque;
X	evSignal *del = opaqueID.opaque;
X	evSignal *old, *cur;
X
X	/* Unlink. */
X	for (old = NULL, cur = ctx->signals;
X	     cur != NULL && cur != del;
X	     old = cur, cur = cur->next)
X		NULL;
X	if (! cur)
X		ERR(ENOENT);
X	if (! old)
X		ctx->signals = del->next;
X	else
X		old->next = del->next;
X
X	/*
X	 * Was the signal caught elsewise?  If not, we should restore the
X	 * signal handler and blocking status to whatever it used to be.
X	 */
X	if (!(cur = FindSig(ctx, del->sig))) {
X		if (sigismember(&ctx->blockedBefore, del->sig) <= 0) {
X			sigset_t set;
X
X			(void) sigemptyset(&set);
X			(void) sigaddset(&set, del->sig);
X			(void) sigprocmask(SIG_UNBLOCK, &set, NULL);
X		}
X		(void) sigaction(del->sig, &del->oact, NULL);
X	}
X
X	/* Deallocate and get out. */
X	free(del);
X	return (0);
}
X
static evSignal *
FindSig(const evContext_p *ctx, int sig) {
X	register evSignal *cur;
X
X	for (cur = ctx->signals; cur && cur->sig != sig; cur = cur->next)
X		NULL;
X	return (cur);
}
X
static void
EatMe(int mystery) {
X	NULL;
}
SHAR_EOF
  $shar_touch -am 0916223095 'signals.c' &&
  chmod 0444 'signals.c' ||
  echo 'restore of signals.c failed'
  shar_count="`wc -c < 'signals.c'`"
  test 5692 -eq "$shar_count" ||
    echo "signals.c: original size 5692, current size $shar_count"
fi
# ============= testfiles.c ==============
if test -f 'testfiles.c' && test X"$1" != X"-c"; then
  echo 'x - skipping testfiles.c (file already exists)'
else
  echo 'x - extracting testfiles.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testfiles.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* testfiles - a really slow version of "cat" that tests file I/O events
X * vix 13sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: testfiles.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
X
#include "eventlib.h"
X
#ifdef DEBUG
int evDebugLev = 10;
#endif
X
struct closure {
X	int otherFD;
X	evFileID id;
};
X
void
myCopyFunc(evContext ctx, void *uap, int fd, int eventmask) {
X	struct closure *c = uap;
X	char buf[BUFSIZ];
X	int len;
X
X	len = read(fd, buf, sizeof buf);
X	if (len <= 0) {
X		evDeselectFD(ctx, c->id);
X		free(uap);
X	} else
X		write(c->otherFD, buf, len);
}
X
int
main(int argc, char *argv[]) {
X	evContext ev;
X	struct closure *c;
X
X	puts("This is a really slow version of ``cat''.  Type something.");
X	evOpen(&ev);
X	if (!(c = malloc(sizeof *c))) {
X		printf("out of memory?\n");
X		exit(1);
X	}
X	c->otherFD = STDOUT_FILENO;
X	if (evSelectFD(ev, STDIN_FILENO, EV_READ, myCopyFunc, c, &c->id) < 0) {
X		perror("evSelectFD");
X		exit(1);
X	}
X
X	assert(evMainLoop(ev) == -1);
X	if (errno != ENOENT)
X		perror("evMainLoop");
X	evClose(ev);
X	exit(0);
X	/*NOTREACHED*/
}
SHAR_EOF
  $shar_touch -am 0917161295 'testfiles.c' &&
  chmod 0444 'testfiles.c' ||
  echo 'restore of testfiles.c failed'
  shar_count="`wc -c < 'testfiles.c'`"
  test 2048 -eq "$shar_count" ||
    echo "testfiles.c: original size 2048, current size $shar_count"
fi
# ============= testtimers.c ==============
if test -f 'testtimers.c' && test X"$1" != X"-c"; then
  echo 'x - skipping testtimers.c (file already exists)'
else
  echo 'x - extracting testtimers.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testtimers.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* testtimers - a test jig to let programmers test the timer events
X * vix 13sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: testtimers.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
X
#ifdef NEED_STRDUP
static char *strdup(char *str);
#endif
X
#include "eventlib.h"
X
#ifdef DEBUG
int evDebugLev = 10;
#endif
X
struct closure {
X	char *name;
X	evTimerID id;
};
X
void
myTimerFunc(evContext ctx, void *uap,
X	    struct timeval due,
X	    struct timeval inter
) {
X	struct timeval now;
X	struct closure *c = uap;
X	int reissue = inter.tv_sec || inter.tv_sec;
X
X	printf("myTimerFunc: due %d.%06d [ctx %#x, uap %#x(%s)]\n",
X	       due.tv_sec, due.tv_usec, ctx, c, c->name);
X	(void) gettimeofday(&now, NULL);
X	printf("myTimerFunc: now %d.%06d [inter %d.%06d, reissue: %d]\n",
X	       now.tv_sec, now.tv_usec, inter.tv_sec, inter.tv_usec, reissue);
X	if (!reissue)
X		free(uap);
}
X
int
main(int argc, char *argv[]) {
X	char buf[1000];
X	evContext ev;
X	struct timeval now;
X
X	puts("Read the source to figure out what this does.");
X	evOpen(&ev);
X	gettimeofday(&now, NULL);
X	while (gets(buf)) {
X		char name[100];
X		struct timeval due, inter;
X		struct closure *c;
X		int x;
X
X		x = sscanf(buf, "%d.%d %d.%d %s\n",
X			   &due.tv_sec, &due.tv_usec,
X			   &inter.tv_sec, &inter.tv_usec,
X			   name);
X		if (x != 5 && x != 4 && x != 2) {
X			printf("bong!  usage:  due inter name\n");
X			continue;
X		}
X		if (x < 5)
X			strcpy(name, "default");
X		if (x < 4)
X			inter = evConsTimeV(0,0);
X		if (!(c = malloc(sizeof *c))) {
X			printf("out of memory?\n");
X			exit(1);
X		}
X		c->name = strdup(name);
X		x = evSetTimer(ev, myTimerFunc, c,
X			       evAddTimeV(due, now), inter,
X			       &c->id);
X		printf("---> %d\n", x);
X	}
X	evMainLoop(ev);
X	perror("evMainLoop");
X	evClose(ev);
X	exit(0);
X	/*NOTREACHED*/
}
X
#ifdef NEED_STRDUP
static char *
strdup(char *str) {
X	char *x = malloc(strlen(str) + 1);
X
X	return (strcpy(x, str));
}
#endif
SHAR_EOF
  $shar_touch -am 0917161295 'testtimers.c' &&
  chmod 0444 'testtimers.c' ||
  echo 'restore of testtimers.c failed'
  shar_count="`wc -c < 'testtimers.c'`"
  test 2830 -eq "$shar_count" ||
    echo "testtimers.c: original size 2830, current size $shar_count"
fi
# ============= testsignals.c ==============
if test -f 'testsignals.c' && test X"$1" != X"-c"; then
  echo 'x - skipping testsignals.c (file already exists)'
else
  echo 'x - extracting testsignals.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testsignals.c' &&
/* Copyright (c) 1995 by Internet Software Consortium
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
/* testsignals - test jig allowing programmers to test the eventlib signals
X * vix 16sep95 [initial]
X */
X
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: testsignals.c,v 1.2 1995/09/17 23:12:25 vixie Exp $";
#endif
X
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
X
#include "eventlib.h"
X
#ifdef DEBUG
int evDebugLev = 10;
#endif
X
void
mySignalFunc(evContext ctx, void *uap, int sig) {
X	char *name = uap;
X
X	printf("mySignalFunc(ctx %#x, uap %#x(%s), sig %d)\n",
X	       ctx, uap, name, sig);
X	if (sig == SIGINT) {
X		evClose(ctx);
X		exit(0);
X	}
X	if (sig == SIGALRM) {
X		time_t now = time(NULL);
X
X		printf("	...time now %s", ctime(&now));
X		alarm(5);
X	}
}
X
int
main(int argc, char *argv[]) {
X	evContext ev;
X	struct closure *c;
X
X	puts("You should get some output every six seconds, and you should");
X	puts("get a slightly delayed exit from a SIGINT (^C).");
X	evOpen(&ev);
X	if (evSetSignal(ev, SIGINT, mySignalFunc, "interrupt", NULL) < 0) {
X		perror("evSetSignal");
X		exit(1);
X	}
X	if (evSetSignal(ev, SIGALRM, mySignalFunc, "alarm", NULL) < 0) {
X		perror("evSetSignal");
X		exit(1);
X	}
X	alarm(5);
X
X	assert(evMainLoop(ev) == -1);
X	if (errno != ENOENT)
X		perror("evMainLoop");
X	evClose(ev);
X	exit(0);
X	/*NOTREACHED*/
}
SHAR_EOF
  $shar_touch -am 0917161295 'testsignals.c' &&
  chmod 0444 'testsignals.c' ||
  echo 'restore of testsignals.c failed'
  shar_count="`wc -c < 'testsignals.c'`"
  test 2176 -eq "$shar_count" ||
    echo "testsignals.c: original size 2176, current size $shar_count"
fi
# ============= testtimers.data ==============
if test -f 'testtimers.data' && test X"$1" != X"-c"; then
  echo 'x - skipping testtimers.data (file already exists)'
else
  echo 'x - extracting testtimers.data (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testtimers.data' &&
10.500000 ten
9.000000 nine
8.100000 eight
7.250000 seven
6.666666 six
5.050505 five
4.110000 four
3.314159 three
2.718281 two
1.414213 one
SHAR_EOF
  $shar_touch -am 0911170595 'testtimers.data' &&
  chmod 0444 'testtimers.data' ||
  echo 'restore of testtimers.data failed'
  shar_count="`wc -c < 'testtimers.data'`"
  test 140 -eq "$shar_count" ||
    echo "testtimers.data: original size 140, current size $shar_count"
fi
# ============= testtimers2.data ==============
if test -f 'testtimers2.data' && test X"$1" != X"-c"; then
  echo 'x - skipping testtimers2.data (file already exists)'
else
  echo 'x - extracting testtimers2.data (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'testtimers2.data' &&
10.0 ten
9.0 nine
8.0 eight
7.0 seven
6.0 six
5.0 five
4.0 four
3.0 three
2.0 two
1.0 one
SHAR_EOF
  $shar_touch -am 0911171095 'testtimers2.data' &&
  chmod 0444 'testtimers2.data' ||
  echo 'restore of testtimers2.data failed'
  shar_count="`wc -c < 'testtimers2.data'`"
  test 90 -eq "$shar_count" ||
    echo "testtimers2.data: original size 90, current size $shar_count"
fi
exit 0
-- 
Paul Vixie
La Honda, CA			"Illegitimibus non carborundum."
<paul@vix.com>
pacbell!vixie!paul