Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Sep 1997 10:11:45 +0100 (BST)
From:      Niall Smart <nsmart@iona.com>
To:        Terry Lambert <tlambert@primenet.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Thread safe libc
Message-ID:  <Pine.SOL.3.96.970918093149.16878H-100000@ultra>
In-Reply-To: <199709180023.RAA19855@usr04.primenet.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 18 Sep 1997, Terry Lambert wrote:

> I would definitely prefer that the user supply the buffers to an *_r()
> routine (I think these routines should replace the standard ones, since
> the standard ones are obviously defective, so they don't have the dumb
> "_r" appendage), and the scoping of data in threads be forthright and
> obvious to anyone reading the code.

I agree, it seems to me that the introduction of thread specific data
is due to programmers prefering the older, simpler (and broken)
interfaces.  Memory management with multiple threads is necessarily
more complex than a single threaded process, thread specific data isn't
a "silver bullet" that will allow us to continue using the old naive
interfaces.  Also, the internal functions of a multithreaded program
will usually follow the policy "pass me a pointer to the buffer where I
should put the data" (otherwise we would see a proliferation of
confusing tsd), library functions should be consistent with this
model.

The POSIX _r style functions aren't all that bad, you can choose
between 100% correct code like this:

int
fn(const char *hostname)
{
        int                     i;
	int                     buflen;
	int                     err;
	char*                   buf;
	char*                   oldbuf;
	struct hostent          he;

	buflen = 0;
	buf = NULL;
	errno = 0;

	do {
		oldbuf = buf;
		buflen += 1024;
		if ((buf = realloc(oldbuf, buflen)) == NULL) {
			free(oldbuf);
                        die("out of memory");
                }
	} while (gethostbyname_r(hostname, &he, buf, buflen, &err) == NULL && errno == ERANGE);

        if (errno != 0) {
              /* blah blah blah... */
        }

        /* blah blah blah ... */
}

Or you can settle for this:

int fn(const char* hostname)
{
	struct hostent		he;
	char			buf[1024];
	int			err;
	
	if (gethostbyname_r(hostname, &he, buf, sizeof(buf), &err) == NULL) {
		if (errno == ERANGE) {
			die("static buffer too small");
		} else {
			/* blah blah blah ... */	
		}
	}
	
	/* blah blah blah ... */
}

In any case, its the programmers choice, other people might use the
version that mallocs the right amount of memory when the static buffer
turns out to be too small (at runtime) and others might use wrappers
and a langauge like C++ that makes memory management for built in types
less of a pain in the ass, and others might even decide to use wrapper
functions which implement the old interface using thread specific data!
:)

Regards,

--
Niall Smart
Customer Engineering,
IONA Technologies. (www.iona.com)




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.SOL.3.96.970918093149.16878H-100000>