Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Sep 2000 15:21:24 -0700
From:      "Ronald F. Guilmette" <rfg@monkeys.com>
To:        freebsd-questions@freebsd.org, freebsd-net@freebsd.org
Subject:   An (simple) example multi-client server using kqueue/kevent.
Message-ID:  <24597.970093284@monkeys.com>

next in thread | raw e-mail | index | archive | help

[[This message doesn't contain a question, so maybe I shouldn't be cross-
  posting it to freebsd-questions, but I hope that this info may help some
  folks who have questions about usage of the new kqueue/kevent stuff.]]

Recently, I became interested in using the new kqueue/kevent kernel
primitives for a multi-client server I wanted to build.  I started
reading up on these new kernel functions and found that not only are
they likely to be vastly more efficient than the alternatives (i.e.
poll(2) and select(2)) but also, that they allow for a cleaner program
design, due to the availability of an extra data field (udata) in each
kqueue structure that can be used (by the application programmer) as a
hook to get you vectored off to some appropriate handler routine when
some specific event you are monitoring occurs.

The only drawback seemed to be that I could find no good and/or complete
working example of a multi-client server which used these new kernel
functions or which clarified, in concrete terms, exactly what proper
usage of these functions would look like.

Fortunately, the fellow who designed and implemented a lot (all?) of this
kqueue/kevent stuff in the kernel, Jonathan Lemon <jlemon@flugsvamp.com>,
was kind enough to converse with me, at length, via e-mail, about correct
usage, so now I feel that I have a pretty good handle on how to use this
stuff.

Just to be sure of that however, I wrote up a trivial example multi-client
network server... i.e. an ``echo'' server... and asked Jonathan to take
a look at it and to send me a critique, which he obligingly did.  He
suggested some minor changes to the code, which I then implemented.

For those of you who may be interested, the resulting example echo server
may be viewed at:

	http://www.monkeys.com/kqueue/echo.c

Some notes about the program:

    o	I ran it and it actually seemed to work and to do what was intended.
	(Surprisingly, it did so the first time I actually ran it!)

    o	Please be aware that I write code in a style which is mostly the
	GNU/Stallman coding style, except that I write declarations in a
	funny way, i.e. with const and volatile modifiers always placed as
	far to the right in a declaration as possible while maintaining
	the same semantic intent.  Whereas most C coders will write
	`const int *', I write `int const *' instead.  Both are legal C
	and both are semantically equivalent, but I like the former style
	because it allows me to read declarations right-to-left and get
	something that makes sense, even in English, e.g "pointer to
	constant integer".  My apologies if my style confuses you.

    o	The `struct ecb' type, defined in the program, is my ``event
	control block''.  It just contains the read and write function
	pointers associated with some specific client of the server,
	along with some ancillary data, specifically, a pointer to the
	base of, and the length of a currently pending output buffer.
	Pointers to a given `ecb' thingy are used, within this server 
	as the `udata' field of two different kevent structures, i.e.
	one which asks for monitoring of readability of the relevant
	socket, and another which asks for monitoring of writability
	of that same socket.

   o	Within my event loop, I never check for either of the conditions
	EV_ERROR or EV_EOF.  Rather, I allow the primitive socket read
	and write handler functions check for error and EOF conditions
	themselves.  According to Jonathan, this approach may be sub-
	optimal and it would probably be better to check for EV_ERROR
	within the event loop (but checking for EOF in the read/write
	functions is entirely sensible).

   o	Even after talking to Johnathan about this, it still isn't 100%
	clear whether it is better to EV_DELETE a filter that is monitor-
	ing a condition that you do not wish to pay attention to right
	now or if it is better to instead just EV_DISABLE it.  In my example
	echo server, I use EV_DISABLE.

Please send comments or critiques of the echo.c server to <rfg@monkeys.com>.

Some notes about kevent/kqueue in general:

    o	There doesn't seem to be any way, at present, to ask to be alerted
	ONLY when you can immediately write N bytes to some specified file
	descriptor *without blocking*.  I have mentioned this to Johnathan,
	and he seemed to agree that this is a problem, and one which may
	require some small extension to the existing kqueue/kevent semantics
	in order to provide this additional functionality.

    o	It is somewhat unfortunate that the name of the data structure used
	by these primitives (struct kevent) is the same as the name of one
	of the functions provided by the interface.  The implication is that
        you can write:

                typedef struct kevent kevent;

        in your own code, if you want to be able to refer to the type tersely,
        but if you do that, you will thereafter get compile-time syntax errors
        where you attempt to call the kevent *function*.

    o   If one is REALLY obeying all rules of the ANSI/ISO C standard, then
        one MAY NOT assign a pointer to any function to the `udata' field of
        the kevent structure.  According to strict ANSI/ISO C rules (which
        will be applied by gcc when/if you use the -pedant-errors option)
        pointers to functions and pointers to data may NEVER be mixed in any
        way.  I've mentioned this to Johanathan and suggested that he change
        the type of `udata' to be some union type that can hold either a
        pointer to some data item or a pointer to some function.



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?24597.970093284>