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>