[5] in Pthreads mailing list archive

home help back first fref pref prev next nref lref last post

netdb interfaces

daemon@ATHENA.MIT.EDU (Greg Hudson)
Fri Jun 9 13:49:11 1995

Date: Fri, 9 Jun 1995 13:25:37 -0400
From: Greg Hudson <ghudson@MIT.EDU>
To: pthreads@MIT.EDU


For the second time, I started to convert the pthreads netdb
interfaces from the current calling convention (using struct
hostent_answer, netent_answer, etc.) to the Solaris convention (using
char *buffer and int buflen).  The first time, I changed my mind after
I found out that getservent_r() and friends use a locked global file,
i.e. the code

	setservent(0);
	while (getservent_r(&servent, buf, buflen))
		do_stuff();
	endservent();

is intrinsically non-thread-safe, and there's no interface where you
can pass in a file pointer to make it really reentrant.

This time, I decided I could get around this problem by providing a
third set of interfaces, setservent_rf(), getservent_rf(), and
endservent_rf() which would take a FILE ** argument for real
reentrancy.

This time, I changed my mind when I disocvered that there's no way to
implement getservent_rf() in ANSI C (or getservent_r() in ANSI C plus
mutexes).  Since struct servent has a list of aliases represented as a
NULL-terminated vector of character pointers, the "result structure,
buffer, and length" approach to netdb reentrancy means that the
internals of the library have to know what the alignment restrictions
are on character pointers, and how to take a possibly unaligned
pointer and round it up to the nearest acceptable aligned pointer for
storing a character pointer.

So I guess I will leave the current netdb interfaces alone, and the
world will be stuck with two sets of _r() netdb routines with
different interfaces.

Of course, the current pthreads interfaces aren't perfect either.
They merely take the static data from the netdb routines and stuff it
into an _answer structure.  So they suffer from the same arbitrary
limits as the old routines, and now your compiled binaries depend on
the size of the _answer structures, so those buffers can't change size
across versions of the implementation without breaking binary
compatibility.

I suppose the "real" answer is to provide a reentrant interface in
which the caller provides properly-typed pointers and lengths for all
the bits of variable-length data.  But I really don't want to do this
with, say, gethostbyname(), since you would require three separate
vectors (one for the name, one for the aliases, and one for the
address list).  Declaring a hostent_answer structure and passing it in
as an argument to make your program thread-safe is pretty convenient;
allocating three variable-sized buffers to pass in and trying to
decide which one was too short when you got a NULL result is
ridiculous.

I want garbage collection, dammit.


home help back first fref pref prev next nref lref last post