[PATCH] Change res_init to take (lazilly) effect in all threads
Jakub Jelinek
jakub@redhat.com
Wed Aug 4 21:19:00 GMT 2004
On Wed, Aug 04, 2004 at 10:48:09PM +0200, Andreas Schwab wrote:
> > --- libc/resolv/resolv.h.jj 2004-08-04 14:42:23.000000000 +0200
> > +++ libc/resolv/resolv.h 2004-08-04 14:54:25.568907618 +0200
> > @@ -134,6 +134,12 @@ struct __res_state {
> > u_int16_t nscount6;
> > u_int16_t nsinit;
> > struct sockaddr_in6 *nsaddrs[MAXNS];
> > +#ifdef _LIBC
> > + unsigned long long int initstamp
> > + __attribute__((aligned (sizeof (long))));
> > +#else
> > + unsigned int _initstamp[2];
> > +#endif
>
> You can't decrease alignment with the aligned attribute unless you also
> add packed.
Well, combining packed and aligned attribute doesn't work either
(this is one of the infamous ABI incompatibilities between various
GCC versions).
But __attribute__((packed)) alone seems to DTRT, GCC knows the whole
structure is sizeof (void *) aligned (it contains pointers) and
the immediately preceeding member is a pointer too, so reading
_u._ext.initstamp causes unaligned load on neither 32-bit nor 64-bit
arches. I have checked this resolv.h layout on x86-64, i386, ppc32, ppc64
and ia64 and it looks good.
So here is the updated patch:
2004-08-04 Jakub Jelinek <jakub@redhat.com>
* hesiod/hesiod.c (__hesiod_res_get): Use calloc instead of malloc +
memset.
(__hesiod_res_set): Free nsaddrs.
* include/resolv.h (__res_maybe_init): Add prototype.
* resolv/resolv.h (struct __res_state): Add _u._ext.initstamp field.
* resolv/Versions (libc): Add __res_maybe_init@@GLIBC_PRIVATE.
* resolv/res_libc.c (__res_initstamp, lock): New variables.
(res_init): Increase __res_initstamp.
(__res_maybe_init): New function.
* resolv/res_init.c (__res_vinit): Initialize _u._ext.initstamp.
* hesiod/hesiod.c (__hesiod_res_get): Use __res_maybe_init instead
of RES_INIT check and {res_ninit,__res_ninit,res_init} call.
* sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise.
* resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname2_r,
_nss_dns_gethostbyaddr_r): Likewise.
* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyname_r,
_nss_dns_getnetbyaddr_r): Likewise.
* resolv/gethnamaddr.c (gethostbyname, gethostbyname2,
gethostbyaddr): Likewise.
* resolv/res_data.c (fp_nquery, res_mkquery, res_mkupdate,
res_isourserver, res_sendsigned, res_update, res_search,
res_querydomain): Likewise.
* nss/getXXbyYY_r.c (INTERNAL (REENTRANT_NAME)): Likewise.
* nss/digits_dots.c (__nss_hostname_digits_dots): Likewise.
* nss/getnssent_r.c (__nss_setent, __nss_endent, __nss_getent_r):
Likewise.
--- libc/hesiod/hesiod.c.jj 2004-08-04 14:42:20.000000000 +0200
+++ libc/hesiod/hesiod.c 2004-08-04 14:54:25.000000000 +0200
@@ -448,10 +448,9 @@ __hesiod_res_get(void *context) {
if (!ctx->res) {
struct __res_state *res;
- res = (struct __res_state *)malloc(sizeof *res);
+ res = (struct __res_state *)calloc(1, sizeof *res);
if (res == NULL)
return (NULL);
- memset(res, 0, sizeof *res);
__hesiod_res_set(ctx, res, free);
}
@@ -465,6 +464,12 @@ __hesiod_res_set(void *context, struct _
if (ctx->res && ctx->free_res) {
res_nclose(ctx->res);
+ if ((ctx->res->options & RES_INIT) && ctx->res->nscount > 0) {
+ for (int ns = 0; ns < MAXNS; ns++) {
+ free (ctx->res->_u._ext.nsaddrs[ns]);
+ ctx->res->_u._ext.nsaddrs[ns] = NULL;
+ }
+ }
(*ctx->free_res)(ctx->res);
}
@@ -478,8 +483,7 @@ init(struct hesiod_p *ctx) {
if (!ctx->res && !__hesiod_res_get(ctx))
return (-1);
- if (((ctx->res->options & RES_INIT) == 0) &&
- (res_ninit(ctx->res) == -1))
+ if (__res_maybe_init (ctx->res, 0) == -1)
return (-1);
return (0);
--- libc/sysdeps/posix/getaddrinfo.c.jj 2004-08-04 14:42:26.000000000 +0200
+++ libc/sysdeps/posix/getaddrinfo.c 2004-08-04 14:54:25.563908498 +0200
@@ -661,7 +661,7 @@ gaih_inet (const char *name, const struc
no_more = __nss_database_lookup ("hosts", NULL,
"dns [!UNAVAIL=return] files", &nip);
- if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;
old_res_options = _res.options;
_res.options &= ~RES_USE_INET6;
--- libc/include/resolv.h.jj 2004-08-04 14:42:20.000000000 +0200
+++ libc/include/resolv.h 2004-08-04 14:54:25.564908322 +0200
@@ -31,6 +31,7 @@ extern struct __res_state _res;
/* Now define the internal interfaces. */
extern int __res_vinit (res_state, int);
+extern int __res_maybe_init (res_state, int);
extern void _sethtent (int);
extern void _endhtent (void);
extern struct hostent *_gethtent (void);
@@ -46,6 +47,7 @@ extern void res_send_setrhook (res_send_
extern int res_ourserver_p (const res_state __statp,
const struct sockaddr_in6 *__inp);
libc_hidden_proto (__res_ninit)
+libc_hidden_proto (__res_maybe_init)
libc_hidden_proto (__res_nclose)
libc_hidden_proto (__res_randomid)
libc_hidden_proto (__res_state)
--- libc/resolv/nss_dns/dns-host.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/nss_dns/dns-host.c 2004-08-04 14:54:25.000000000 +0200
@@ -145,7 +145,7 @@ _nss_dns_gethostbyname2_r (const char *n
int olderr = errno;
enum nss_status status;
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
return NSS_STATUS_UNAVAIL;
switch (af) {
@@ -263,7 +263,7 @@ _nss_dns_gethostbyaddr_r (const void *ad
int n, status;
int olderr = errno;
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
return NSS_STATUS_UNAVAIL;
if (af == AF_INET6 && len == IN6ADDRSZ
--- libc/resolv/nss_dns/dns-network.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/nss_dns/dns-network.c 2004-08-04 14:54:25.000000000 +0200
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
@@ -120,7 +121,7 @@ _nss_dns_getnetbyname_r (const char *nam
char *qbuf;
enum nss_status status;
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
return NSS_STATUS_UNAVAIL;
qbuf = strdupa (name);
@@ -171,7 +172,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, i
if (type != AF_INET)
return NSS_STATUS_UNAVAIL;
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
return NSS_STATUS_UNAVAIL;
net2 = (u_int32_t) net;
--- libc/resolv/gethnamaddr.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/gethnamaddr.c 2004-08-04 14:54:25.000000000 +0200
@@ -493,10 +493,10 @@ gethostbyname(name)
{
struct hostent *hp;
- if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
+ if (__res_maybe_init (&_res, 0) == -1) {
__set_h_errno (NETDB_INTERNAL);
return (NULL);
- }
+ }
if (_res.options & RES_USE_INET6) {
hp = gethostbyname2(name, AF_INET6);
if (hp)
@@ -522,7 +522,7 @@ gethostbyname2(name, af)
struct hostent *ret;
extern struct hostent *_gethtbyname2();
- if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
+ if (__res_maybe_init (&_res, 0) == -1) {
__set_h_errno (NETDB_INTERNAL);
return (NULL);
}
@@ -665,7 +665,7 @@ gethostbyaddr(addr, len, af)
#endif /*SUNSECURITY*/
extern struct hostent *_gethtbyaddr();
- if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1) {
+ if (__res_maybe_init (&_res, 0) == -1) {
__set_h_errno (NETDB_INTERNAL);
return (NULL);
}
--- libc/resolv/res_data.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/res_data.c 2004-08-04 14:54:25.000000000 +0200
@@ -141,7 +141,7 @@ fp_query(const u_char *msg, FILE *file)
void
fp_nquery(const u_char *msg, int len, FILE *file) {
- if ((_res.options & RES_INIT) == 0 && __res_ninit(&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
return;
res_pquery(&_res, msg, len, file);
@@ -157,7 +157,7 @@ res_mkquery(int op, /* opcode of query
u_char *buf, /* buffer to put query */
int buflen) /* size of buffer */
{
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
@@ -169,7 +169,7 @@ res_mkquery(int op, /* opcode of query
#ifdef BIND_UPDATE
int
res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
@@ -184,7 +184,7 @@ res_query(const char *name, /* domain na
u_char *answer, /* buffer to put answer */
int anslen) /* size of answer buffer */
{
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
@@ -208,7 +208,7 @@ res_isourserver(const struct sockaddr_in
int
res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
/* errno should have been set by res_init() in this case. */
return (-1);
}
@@ -221,7 +221,7 @@ int
res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
u_char *ans, int anssiz)
{
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
/* errno should have been set by res_init() in this case. */
return (-1);
}
@@ -249,7 +249,7 @@ res_close(void) {
#ifdef BIND_UPDATE
int
res_update(ns_updrec *rrecp_in) {
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
@@ -264,7 +264,7 @@ res_search(const char *name, /* domain n
u_char *answer, /* buffer to put answer */
int anslen) /* size of answer */
{
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
@@ -279,7 +279,7 @@ res_querydomain(const char *name,
u_char *answer, /* buffer to put answer */
int anslen) /* size of answer */
{
- if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+ if (__res_maybe_init (&_res, 1) == -1) {
RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
return (-1);
}
--- libc/resolv/resolv.h.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/resolv.h 2004-08-04 14:54:25.568907618 +0200
@@ -134,6 +134,12 @@ struct __res_state {
u_int16_t nscount6;
u_int16_t nsinit;
struct sockaddr_in6 *nsaddrs[MAXNS];
+#ifdef _LIBC
+ unsigned long long int initstamp
+ __attribute__((packed));
+#else
+ unsigned int _initstamp[2];
+#endif
} _ext;
} _u;
};
--- libc/resolv/res_init.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/res_init.c 2004-08-04 14:54:25.567907794 +0200
@@ -161,6 +161,10 @@ __res_vinit(res_state statp, int preinit
#ifndef RFC1535
int dots;
#endif
+#ifdef _LIBC
+ extern unsigned long long int __res_initstamp attribute_hidden;
+ statp->_u._ext.initstamp = __res_initstamp;
+#endif
if (!preinit) {
statp->retrans = RES_TIMEOUT;
--- libc/resolv/Versions.jj 2004-08-04 14:42:22.000000000 +0200
+++ libc/resolv/Versions 2004-08-04 14:54:25.570907266 +0200
@@ -38,6 +38,8 @@ libc {
# This version is for the TLS symbol, GLIBC_2.0 is the old object symbol.
h_errno; __resp;
%endif
+
+ __res_maybe_init;
}
}
--- libc/resolv/res_libc.c.jj 2004-08-04 14:42:23.000000000 +0200
+++ libc/resolv/res_libc.c 2004-08-04 15:36:12.104626490 +0200
@@ -19,12 +19,16 @@
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
+#include <bits/libc-lock.h>
/* The following bit is copied from res_data.c (where it is #ifdef'ed
out) since res_init() should go into libc.so but the rest of that
file should not. */
+unsigned long long int __res_initstamp attribute_hidden;
+__libc_lock_define_initialized (static, lock);
+
int
res_init(void) {
extern int __res_vinit(res_state, int);
@@ -70,8 +74,45 @@ res_init(void) {
if (!_res.id)
_res.id = res_randomid();
+ __libc_lock_lock (lock);
+ /* Request all threads to re-initialize their resolver states,
+ resolv.conf might have changed. */
+ __res_initstamp++;
+ __libc_lock_unlock (lock);
+
return (__res_vinit(&_res, 1));
}
+
+/* Initialize resp if RES_INIT is not yet set or if res_init in some other
+ thread requested re-initializing. */
+int
+__res_maybe_init (res_state resp, int preinit)
+{
+ if (resp->options & RES_INIT) {
+ if (__res_initstamp != resp->_u._ext.initstamp) {
+ if (resp->nscount > 0) {
+ __res_nclose (resp);
+ for (int ns = 0; ns < MAXNS; ns++) {
+ free (resp->_u._ext.nsaddrs[ns]);
+ resp->_u._ext.nsaddrs[ns] = NULL;
+ }
+ return __res_vinit (resp, 1);
+ }
+ }
+ return 0;
+ } else if (preinit) {
+ if (!resp->retrans)
+ resp->retrans = RES_TIMEOUT;
+ if (!resp->retry)
+ resp->retry = 4;
+ resp->options = RES_DEFAULT;
+ if (!resp->id)
+ resp->id = res_randomid ();
+ return __res_vinit (resp, 1);
+ } else
+ return __res_ninit (resp);
+}
+libc_hidden_def (__res_maybe_init)
/* This needs to be after the use of _res in res_init, above. */
#undef _res
--- libc/nss/getXXbyYY_r.c.jj 2004-08-04 14:42:22.000000000 +0200
+++ libc/nss/getXXbyYY_r.c 2004-08-04 14:54:25.573906738 +0200
@@ -182,7 +182,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
#ifdef NEED__RES
/* The resolver code will really be used so we have to
initialize it. */
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
{
*h_errnop = NETDB_INTERNAL;
*result = NULL;
--- libc/nss/digits_dots.c.jj 2004-08-04 14:42:22.000000000 +0200
+++ libc/nss/digits_dots.c 2004-08-04 14:54:25.571907090 +0200
@@ -43,7 +43,7 @@ __nss_hostname_digits_dots (const char *
/* We have to test for the use of IPv6 which can only be done by
examining `_res'. */
- if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
+ if (__res_maybe_init (&_res, 0) == -1)
{
if (h_errnop)
*h_errnop = NETDB_INTERNAL;
--- libc/nss/getnssent_r.c.jj 2004-08-04 14:42:22.000000000 +0200
+++ libc/nss/getnssent_r.c 2004-08-04 14:54:25.572906914 +0200
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000,02 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -60,8 +60,7 @@ __nss_setent (const char *func_name, db_
} fct;
int no_more;
- if (res && (_res.options & RES_INIT) == 0
- && __res_ninit (&_res) == -1)
+ if (res && __res_maybe_init (&_res, 0) == -1)
{
__set_h_errno (NETDB_INTERNAL);
return;
@@ -104,8 +103,7 @@ __nss_endent (const char *func_name, db_
} fct;
int no_more;
- if (res && (_res.options & RES_INIT) == 0
- && __res_ninit (&_res) == -1)
+ if (res && __res_maybe_init (&_res, 0) == -1)
{
__set_h_errno (NETDB_INTERNAL);
return;
@@ -145,8 +143,7 @@ __nss_getent_r (const char *getent_func_
int no_more;
enum nss_status status;
- if (res && (_res.options & RES_INIT) == 0
- && __res_ninit (&_res) == -1)
+ if (res && __res_maybe_init (&_res, 0) == -1)
{
*h_errnop = NETDB_INTERNAL;
*result = NULL;
Jakub
More information about the Libc-hacker
mailing list