diff --git a/CHANGES b/CHANGES index ae5945b4a8..1ce035673d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2285. [func] Test framework for client memory context management. + [RT #17377] + 2284. [bug] Memory leak in UPDATE prerequisite processing. [RT #17377] diff --git a/bin/named/client.c b/bin/named/client.c index df98201cc8..b209af1068 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.250 2007/11/26 04:47:17 marka Exp $ */ +/* $Id: client.c,v 1.251 2008/01/02 05:03:07 marka Exp $ */ #include @@ -463,6 +463,8 @@ exit_check(ns_client_t *client) { if (client->state == client->newstate) { client->newstate = NS_CLIENTSTATE_MAX; + if (client->needshutdown) + isc_task_shutdown(client->task); goto unlock; } } @@ -519,6 +521,14 @@ exit_check(ns_client_t *client) { CTRACE("free"); client->magic = 0; + /* + * Check that there are no other external references to + * the memory context. + */ + if (ns_g_clienttest && isc_mem_references(client->mctx) != 1) { + isc_mem_stats(client->mctx, stderr); + INSIST(0); + } isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); goto unlock; @@ -592,6 +602,7 @@ client_shutdown(isc_task_t *task, isc_event_t *event) { } client->newstate = NS_CLIENTSTATE_FREED; + client->needshutdown = ISC_FALSE; (void)exit_check(client); } @@ -644,7 +655,7 @@ ns_client_checkactive(ns_client_t *client) { * keep it active to make up for the shortage. */ isc_boolean_t need_another_client = ISC_FALSE; - if (TCP_CLIENT(client)) { + if (TCP_CLIENT(client) && !ns_g_clienttest) { LOCK(&client->interface->lock); if (client->interface->ntcpcurrent < client->interface->ntcptarget) @@ -1844,6 +1855,8 @@ get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { /* * Caller must be holding the manager lock. */ + if (ns_g_clienttest) + return (isc_mem_create(0, 0, mctxp)); #if NMCTXS > 0 INSIST(manager->nextmctx < NMCTXS); clientmctx = manager->mctxpool[manager->nextmctx]; @@ -1999,6 +2012,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { if (result != ISC_R_SUCCESS) goto cleanup_query; + client->needshutdown = ns_g_clienttest; + CTRACE("create"); *clientp = client; @@ -2420,7 +2435,9 @@ ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, * Allocate a client. First try to get a recycled one; * if that fails, make a new one. */ - client = ISC_LIST_HEAD(manager->inactive); + client = NULL; + if (!ns_g_clienttest) + client = ISC_LIST_HEAD(manager->inactive); if (client != NULL) { MTRACE("recycle"); ISC_LIST_UNLINK(manager->inactive, client, link); diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index 44c800d174..8316930fbe 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.h,v 1.82 2007/06/18 23:47:19 tbox Exp $ */ +/* $Id: client.h,v 1.83 2008/01/02 05:03:07 marka Exp $ */ #ifndef NAMED_CLIENT_H #define NAMED_CLIENT_H 1 @@ -97,6 +97,13 @@ struct ns_client { int nupdates; int nctls; int references; + isc_boolean_t needshutdown; /* + * Used by clienttest to get + * the client to go from + * inactive to free state + * by shutting down the + * client's task. + */ unsigned int attributes; isc_task_t * task; dns_view_t * view; diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index de0c084fb3..3adef247a8 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: globals.h,v 1.73 2007/09/26 03:22:43 marka Exp $ */ +/* $Id: globals.h,v 1.74 2008/01/02 05:03:07 marka Exp $ */ #ifndef NAMED_GLOBALS_H #define NAMED_GLOBALS_H 1 @@ -115,6 +115,7 @@ EXTERN const char * ns_g_username INIT(NULL); EXTERN int ns_g_listen INIT(3); EXTERN isc_time_t ns_g_boottime; EXTERN isc_boolean_t ns_g_memstatistics INIT(ISC_FALSE); +EXTERN isc_boolean_t ns_g_clienttest INIT(ISC_FALSE); #undef EXTERN #undef INIT diff --git a/bin/named/main.c b/bin/named/main.c index f2a3e74a8c..e943f620b0 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.158 2007/09/26 03:22:43 marka Exp $ */ +/* $Id: main.c,v 1.159 2008/01/02 05:03:07 marka Exp $ */ /*! \file */ @@ -356,7 +356,7 @@ parse_command_line(int argc, char *argv[]) { isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:")) != -1) { + "46c:C:d:fgi:lm:n:N:p:P:st:T:u:vx:")) != -1) { switch (ch) { case '4': if (disable4) @@ -439,6 +439,17 @@ parse_command_line(int argc, char *argv[]) { /* XXXJAB should we make a copy? */ ns_g_chrootdir = isc_commandline_argument; break; + case 'T': + /* + * clienttest: make clients single shot with their + * own memory context. + */ + if (strcmp(isc_commandline_argument, "clienttest") == 0) + ns_g_clienttest = ISC_TRUE; + else + fprintf(stderr, "unknown -T flag '%s\n", + isc_commandline_argument); + break; case 'u': ns_g_username = isc_commandline_argument; break; diff --git a/bin/named/query.c b/bin/named/query.c index 29b113ad78..23c6bae576 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.298 2007/09/26 03:04:45 each Exp $ */ +/* $Id: query.c,v 1.299 2008/01/02 05:03:07 marka Exp $ */ /*! \file */ @@ -4445,6 +4445,12 @@ ns_query_start(ns_client_t *client) { CTRACE("ns_query_start"); + /* + * Test only. + */ + if (ns_g_clienttest && (client->attributes & NS_CLIENTATTR_TCP) == 0) + RUNTIME_CHECK(ns_client_replace(client) == ISC_R_SUCCESS); + /* * Ensure that appropriate cleanups occur. */ diff --git a/bin/tests/system/start.pl b/bin/tests/system/start.pl index b22f74ce62..a681655ba0 100644 --- a/bin/tests/system/start.pl +++ b/bin/tests/system/start.pl @@ -15,7 +15,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: start.pl,v 1.11 2007/06/19 23:47:00 tbox Exp $ +# $Id: start.pl,v 1.12 2008/01/02 05:03:07 marka Exp $ # Framework for starting test servers. # Based on the type of server specified, check for port availability, remove @@ -129,7 +129,9 @@ sub start_server { if ($options) { $command .= "$options"; } else { - $command .= "-m record,size,mctx -c named.conf -d 99 -g"; + $command .= "-m record,size,mctx "; + $command .= "-T clienttest "; + $command .= "-c named.conf -d 99 -g"; } $command .= " >named.run 2>&1 &"; $pid_file = "named.pid"; @@ -139,7 +141,10 @@ sub start_server { if ($options) { $command .= "$options"; } else { - $command .= "-m record,size,mctx -C resolv.conf -d 99 -g -i lwresd.pid -P 9210 -p 5300"; + $command .= "-m record,size,mctx "; + $command .= "-T clienttest "; + $command .= "-C resolv.conf -d 99 -g "; + $command .= "-i lwresd.pid -P 9210 -p 5300"; } $command .= " >lwresd.run 2>&1 &"; $pid_file = "lwresd.pid"; diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index ade0794a32..1ccfc5e6f5 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.h,v 1.72 2007/06/18 23:47:44 tbox Exp $ */ +/* $Id: mem.h,v 1.73 2008/01/02 05:03:07 marka Exp $ */ #ifndef ISC_MEM_H #define ISC_MEM_H 1 @@ -377,6 +377,12 @@ isc_mem_checkdestroyed(FILE *file); * Fatally fails if there are still active contexts. */ +unsigned int +isc_mem_references(isc_mem_t *ctx); +/*%< + * Return the current reference count. + */ + /* * Memory pools */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 36b9a7b034..9ecb1eda9d 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.c,v 1.137 2007/11/26 04:27:19 marka Exp $ */ +/* $Id: mem.c,v 1.138 2008/01/02 05:03:07 marka Exp $ */ /*! \file */ @@ -1955,6 +1955,18 @@ isc_mem_checkdestroyed(FILE *file) { UNLOCK(&lock); } +unsigned int +isc_mem_references(isc_mem_t *ctx) { + unsigned int references; + REQUIRE(VALID_CONTEXT(ctx)); + + MCTXLOCK(ctx, &ctx->lock); + references = ctx->references; + MCTXUNLOCK(ctx, &ctx->lock); + + return (references); +} + #ifdef HAVE_LIBXML2 void