+3492. [bug] Fixed a regression in zone loading performance
+ due to lock contention. [RT #30399]
+
3491. [bug] Slave zones using inline-signing must specify a
file name. [RT #31946]
}
}
- CHECK(dns_zone_create(&zone, mctx));
+ CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
+ &zone));
CHECK(dns_zone_setorigin(zone, name));
dns_zone_setview(zone, view);
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
dns_zone_attach(pview->redirect, &zone);
dns_zone_setview(zone, view);
} else {
- CHECK(dns_zone_create(&zone, mctx));
+ CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
+ &zone));
CHECK(dns_zone_setorigin(zone, origin));
dns_zone_setview(zone, view);
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
* We cannot reuse an existing zone, we have
* to create a new one.
*/
- CHECK(dns_zone_create(&zone, mctx));
+ CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
CHECK(dns_zone_setorigin(zone, origin));
dns_zone_setview(zone, view);
if (view->acache != NULL)
}
/* No existing keydata zone was found; create one */
- CHECK(dns_zone_create(&zone, mctx));
+ CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
CHECK(dns_zone_setorigin(zone, dns_rootname));
isc_sha256_data((void *)view->name, strlen(view->name), buffer);
s = isc_mem_get(mctx, sizeof(*s));
if (s == NULL)
return (ISC_R_NOMEMORY);
- s->common.mctx = mctx;
+ s->common.mctx = NULL;
+ isc_mem_attach(mctx, &s->common.mctx);
s->common.methods = &ixfr_rrstream_methods;
s->journal = NULL;
ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp;
if (s->journal != 0)
dns_journal_destroy(&s->journal);
- isc_mem_put(s->common.mctx, s, sizeof(*s));
+ isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
}
static rrstream_methods_t ixfr_rrstream_methods = {
s = isc_mem_get(mctx, sizeof(*s));
if (s == NULL)
return (ISC_R_NOMEMORY);
- s->common.mctx = mctx;
+ s->common.mctx = NULL;
+ isc_mem_attach(mctx, &s->common.mctx);
s->common.methods = &axfr_rrstream_methods;
s->it_valid = ISC_FALSE;
axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp;
if (s->it_valid)
dns_rriterator_destroy(&s->it);
- isc_mem_put(s->common.mctx, s, sizeof(*s));
+ isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
}
static rrstream_methods_t axfr_rrstream_methods = {
s = isc_mem_get(mctx, sizeof(*s));
if (s == NULL)
return (ISC_R_NOMEMORY);
- s->common.mctx = mctx;
+ s->common.mctx = NULL;
+ isc_mem_attach(mctx, &s->common.mctx);
s->common.methods = &soa_rrstream_methods;
s->soa_tuple = NULL;
soa_rrstream_t *s = (soa_rrstream_t *) *rsp;
if (s->soa_tuple != NULL)
dns_difftuple_free(&s->soa_tuple);
- isc_mem_put(s->common.mctx, s, sizeof(*s));
+ isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
}
static rrstream_methods_t soa_rrstream_methods = {
s = isc_mem_get(mctx, sizeof(*s));
if (s == NULL)
return (ISC_R_NOMEMORY);
- s->common.mctx = mctx;
+ s->common.mctx = NULL;
+ isc_mem_attach(mctx, &s->common.mctx);
s->common.methods = &compound_rrstream_methods;
s->components[0] = *soa_stream;
s->components[1] = *data_stream;
s->components[0]->methods->destroy(&s->components[0]);
s->components[1]->methods->destroy(&s->components[1]);
s->components[2] = NULL; /* Copy of components[0]. */
- isc_mem_put(s->common.mctx, s, sizeof(*s));
+ isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
}
static rrstream_methods_t compound_rrstream_methods = {
acl = isc_mem_get(mctx, sizeof(*acl));
if (acl == NULL)
return (ISC_R_NOMEMORY);
- acl->mctx = mctx;
+
+ acl->mctx = NULL;
+ isc_mem_attach(mctx, &acl->mctx);
+
acl->name = NULL;
result = isc_refcount_init(&acl->refcount, 1);
dns_iptable_detach(&dacl->iptable);
isc_refcount_destroy(&dacl->refcount);
dacl->magic = 0;
- isc_mem_put(dacl->mctx, dacl, sizeof(*dacl));
+ isc_mem_putanddetach(&dacl->mctx, dacl, sizeof(*dacl));
}
void
byaddr = isc_mem_get(mctx, sizeof(*byaddr));
if (byaddr == NULL)
return (ISC_R_NOMEMORY);
- byaddr->mctx = mctx;
+ byaddr->mctx = NULL;
+ isc_mem_attach(mctx, &byaddr->mctx);
byaddr->options = options;
byaddr->event = isc_mem_get(mctx, sizeof(*byaddr->event));
isc_task_detach(&byaddr->task);
cleanup_byaddr:
- isc_mem_put(mctx, byaddr, sizeof(*byaddr));
+ isc_mem_putanddetach(&mctx, byaddr, sizeof(*byaddr));
return (result);
}
DESTROYLOCK(&byaddr->lock);
byaddr->magic = 0;
- isc_mem_put(byaddr->mctx, byaddr, sizeof(*byaddr));
+ isc_mem_putanddetach(&byaddr->mctx, byaddr, sizeof(*byaddr));
*byaddrp = NULL;
}
goto clean3;
dbtable->default_db = NULL;
- dbtable->mctx = mctx;
+ dbtable->mctx = NULL;
+ isc_mem_attach(mctx, &dbtable->mctx);
dbtable->rdclass = rdclass;
dbtable->magic = DBTABLE_MAGIC;
dbtable->references = 1;
dns_rbt_destroy(&dbtable->rbt);
clean1:
- isc_mem_put(mctx, dbtable, sizeof(*dbtable));
+ isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
return (result);
}
dbtable->magic = 0;
- isc_mem_put(dbtable->mctx, dbtable, sizeof(*dbtable));
+ isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
}
void
t = isc_mem_allocate(mctx, size);
if (t == NULL)
return (ISC_R_NOMEMORY);
- t->mctx = mctx;
+ t->mctx = NULL;
+ isc_mem_attach(mctx, &t->mctx);
t->op = op;
datap = (unsigned char *)(t + 1);
void
dns_difftuple_free(dns_difftuple_t **tp) {
dns_difftuple_t *t = *tp;
+ isc_mem_t *mctx;
+
REQUIRE(DNS_DIFFTUPLE_VALID(t));
+
dns_name_invalidate(&t->name);
t->magic = 0;
- isc_mem_free(t->mctx, t);
+ mctx = t->mctx;
+ isc_mem_free(mctx, t);
+ isc_mem_detach(&mctx);
*tp = NULL;
}
isc_buffer_free(&key->key_tkeytoken);
}
memset(key, 0, sizeof(dst_key_t));
- isc_mem_put(mctx, key, sizeof(dst_key_t));
+ isc_mem_putanddetach(&mctx, key, sizeof(dst_key_t));
*keyp = NULL;
}
isc_mem_put(mctx, key, sizeof(dst_key_t));
return (NULL);
}
+ isc_mem_attach(mctx, &key->mctx);
key->key_alg = alg;
key->key_flags = flags;
key->key_proto = protocol;
- key->mctx = mctx;
key->keydata.generic = NULL;
key->key_size = bits;
key->key_class = rdclass;
*\li zmgr->zonetasks has been initialized.
*/
+isc_result_t
+dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep);
+/*%<
+ * Allocate a new zone using a memory context from the
+ * zone manager's memory context pool.
+ *
+ * Require:
+ *\li 'zmgr' to be a valid zone manager.
+ *\li 'zonep' != NULL and '*zonep' == NULL.
+ */
+
+
isc_result_t
dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
/*%<
tab = isc_mem_get(mctx, sizeof(*tab));
if (tab == NULL)
return (ISC_R_NOMEMORY);
- tab->mctx = mctx;
+ tab->mctx = NULL;
+ isc_mem_attach(mctx, &tab->mctx);
isc_refcount_init(&tab->refcount, 1);
tab->radix = NULL;
tab->magic = DNS_IPTABLE_MAGIC;
isc_refcount_destroy(&dtab->refcount);
dtab->magic = 0;
- isc_mem_put(dtab->mctx, dtab, sizeof(*dtab));
+ isc_mem_putanddetach(&dtab->mctx, dtab, sizeof(*dtab));
}
if (j == NULL)
return (ISC_R_NOMEMORY);
- j->mctx = mctx;
+ j->mctx = NULL;
+ isc_mem_attach(mctx, &j->mctx);
j->state = JOURNAL_STATE_INVALID;
j->fp = NULL;
j->filename = filename;
}
if (j->fp != NULL)
(void)isc_stdio_close(j->fp);
- isc_mem_put(j->mctx, j, sizeof(*j));
+ isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
return (result);
}
if (j->fp != NULL)
(void)isc_stdio_close(j->fp);
j->magic = 0;
- isc_mem_put(j->mctx, j, sizeof(*j));
+ isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
*journalp = NULL;
}
if (result != ISC_R_SUCCESS)
goto cleanup_lock;
- keytable->mctx = mctx;
+ keytable->mctx = NULL;
+ isc_mem_attach(mctx, &keytable->mctx);
keytable->active_nodes = 0;
keytable->references = 1;
keytable->magic = KEYTABLE_MAGIC;
dns_rbt_destroy(&keytable->table);
cleanup_keytable:
- isc_mem_put(mctx, keytable, sizeof(*keytable));
+ isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
return (result);
}
isc_rwlock_destroy(&keytable->rwlock);
DESTROYLOCK(&keytable->lock);
keytable->magic = 0;
- isc_mem_put(keytable->mctx, keytable, sizeof(*keytable));
+ isc_mem_putanddetach(&keytable->mctx,
+ keytable, sizeof(*keytable));
}
*keytablep = NULL;
lookup = isc_mem_get(mctx, sizeof(*lookup));
if (lookup == NULL)
return (ISC_R_NOMEMORY);
- lookup->mctx = mctx;
+ lookup->mctx = NULL;
+ isc_mem_attach(mctx, &lookup->mctx);
lookup->options = options;
ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
isc_task_detach(&lookup->task);
cleanup_lookup:
- isc_mem_put(mctx, lookup, sizeof(*lookup));
+ isc_mem_putanddetach(&mctx, lookup, sizeof(*lookup));
return (result);
}
DESTROYLOCK(&lookup->lock);
lookup->magic = 0;
- isc_mem_put(lookup->mctx, lookup, sizeof(*lookup));
+ isc_mem_putanddetach(&lookup->mctx, lookup, sizeof(*lookup));
*lookupp = NULL;
}
for (i = 0; i < DNS_SECTION_MAX; i++)
ISC_LIST_INIT(m->sections[i]);
- m->mctx = mctx;
+
+ m->mctx = NULL;
+ isc_mem_attach(mctx, &m->mctx);
ISC_LIST_INIT(m->scratchpad);
ISC_LIST_INIT(m->cleanup);
if (m->rdspool != NULL)
isc_mempool_destroy(&m->rdspool);
m->magic = 0;
- isc_mem_put(mctx, m, sizeof(dns_message_t));
+ isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
return (ISC_R_NOMEMORY);
}
isc_mempool_destroy(&msg->namepool);
isc_mempool_destroy(&msg->rdspool);
msg->magic = 0;
- isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
+ isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
}
static isc_result_t
if (rbt == NULL)
return (ISC_R_NOMEMORY);
- rbt->mctx = mctx;
+ rbt->mctx = NULL;
+ isc_mem_attach(mctx, &rbt->mctx);
rbt->data_deleter = deleter;
rbt->deleter_arg = deleter_arg;
rbt->root = NULL;
#ifdef DNS_RBT_USEHASH
result = inithash(rbt);
if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, rbt, sizeof(*rbt));
+ isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
return (result);
}
#endif
rbt->magic = 0;
- isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
+ isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
*rbtp = NULL;
return (ISC_R_SUCCESS);
}
else if (!keepview)
keepview = ISC_TRUE;
- CHECK(dns_zone_create(&zone, mctx));
+ zone = *zonep;
+ if (zone == NULL)
+ CHECK(dns_zone_create(&zone, mctx));
isc_buffer_constinit(&buffer, name, strlen(name));
isc_buffer_add(&buffer, strlen(name));
dns_test_end();
}
+ATF_TC(zonemgr_createzone);
+ATF_TC_HEAD(zonemgr_createzone, tc) {
+ atf_tc_set_md_var(tc, "descr", "create and release a zone");
+}
+ATF_TC_BODY(zonemgr_createzone, tc) {
+ dns_zonemgr_t *zonemgr = NULL;
+ dns_zone_t *zone = NULL;
+ isc_result_t result;
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
+ &zonemgr);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* This should not succeed until the dns_zonemgr_setsize() is run */
+ result = dns_zonemgr_createzone(zonemgr, &zone);
+ ATF_REQUIRE_EQ(result, ISC_R_FAILURE);
+
+ result = dns_zonemgr_setsize(zonemgr, 1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* Now it should succeed */
+ result = dns_zonemgr_createzone(zonemgr, &zone);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(zone != NULL);
+
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+
+ dns_zonemgr_shutdown(zonemgr);
+ dns_zonemgr_detach(&zonemgr);
+ ATF_REQUIRE_EQ(zonemgr, NULL);
+
+ dns_test_end();
+}
+
ATF_TC(zonemgr_unreachable);
ATF_TC_HEAD(zonemgr_unreachable, tc) {
atf_tc_set_md_var(tc, "descr", "manage and release a zone");
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, zonemgr_create);
ATF_TP_ADD_TC(tp, zonemgr_managezone);
+ ATF_TP_ADD_TC(tp, zonemgr_createzone);
ATF_TP_ADD_TC(tp, zonemgr_unreachable);
return (atf_no_error());
}
dns_zonekey_iszonekey
dns_zonemgr_attach
dns_zonemgr_create
+dns_zonemgr_createzone
dns_zonemgr_detach
dns_zonemgr_forcemaint
dns_zonemgr_getcount
#include <isc/file.h>
#include <isc/hex.h>
#include <isc/mutex.h>
+#include <isc/pool.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/ratelimiter.h>
isc_taskpool_t * zonetasks;
isc_taskpool_t * loadtasks;
isc_task_t * task;
+ isc_pool_t * mctxpool;
isc_ratelimiter_t * rl;
isc_rwlock_t rwlock;
isc_mutex_t iolock;
zmgr->socketmgr = socketmgr;
zmgr->zonetasks = NULL;
zmgr->loadtasks = NULL;
+ zmgr->mctxpool = NULL;
zmgr->task = NULL;
zmgr->rl = NULL;
ISC_LIST_INIT(zmgr->zones);
return (result);
}
+isc_result_t
+dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) {
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+ dns_zone_t *zone = NULL;
+ void *item;
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+ REQUIRE(zonep != NULL && *zonep == NULL);
+
+ if (zmgr->mctxpool == NULL)
+ return (ISC_R_FAILURE);
+
+ item = isc_pool_get(zmgr->mctxpool);
+ if (item == NULL)
+ return (ISC_R_FAILURE);
+
+ isc_mem_attach((isc_mem_t *) item, &mctx);
+ result = dns_zone_create(&zone, mctx);
+ isc_mem_detach(&mctx);
+
+ if (result == ISC_R_SUCCESS)
+ *zonep = zone;
+
+ return (result);
+}
+
isc_result_t
dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
isc_result_t result;
isc_taskpool_destroy(&zmgr->zonetasks);
if (zmgr->loadtasks != NULL)
isc_taskpool_destroy(&zmgr->loadtasks);
+ if (zmgr->mctxpool != NULL)
+ isc_pool_destroy(&zmgr->mctxpool);
RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
for (zone = ISC_LIST_HEAD(zmgr->zones);
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
}
+static isc_result_t
+mctxinit(void **target, void *arg) {
+ isc_result_t result;
+ isc_mem_t *mctx = NULL;
+
+ UNUSED(arg);
+
+ REQUIRE(target != NULL && *target == NULL);
+
+ result = isc_mem_create(0, 0, &mctx);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_mem_setname(mctx, "zonemgr-pool", NULL);
+
+ *target = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+mctxfree(void **target) {
+ isc_mem_t *mctx = *(isc_mem_t **) target;
+ isc_mem_detach(&mctx);
+ *target = NULL;
+}
+
+#define ZONES_PER_TASK 100
+#define ZONES_PER_MCTX 1000
+
isc_result_t
dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
isc_result_t result;
- int ntasks = num_zones / 100;
+ int ntasks = num_zones / ZONES_PER_TASK;
+ int nmctx = num_zones / ZONES_PER_MCTX;
isc_taskpool_t *pool = NULL;
+ isc_pool_t *mctxpool = NULL;
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
/*
* For anything fewer than 1000 zones we use 10 tasks in
* the task pools. More than that, and we'll scale at one
- * task per 100 zones.
+ * task per 100 zones. Similarly, for anything smaller than
+ * 2000 zones we use 2 memory contexts, then scale at 1:1000.
*/
if (ntasks < 10)
ntasks = 10;
+ if (nmctx < 2)
+ nmctx = 2;
/* Create or resize the zone task pools. */
if (zmgr->zonetasks == NULL)
isc_taskpool_setprivilege(zmgr->loadtasks, ISC_TRUE);
#endif
+ /* Create or resize the zone memory context pool. */
+ if (zmgr->mctxpool == NULL)
+ result = isc_pool_create(zmgr->mctx, nmctx, mctxfree,
+ mctxinit, NULL, &mctxpool);
+ else
+ result = isc_pool_expand(&zmgr->mctxpool, nmctx, &mctxpool);
+
+ if (result == ISC_R_SUCCESS)
+ zmgr->mctxpool = mctxpool;
+
return (result);
}
httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
- netaddr.@O@ netscope.@O@ ondestroy.@O@ \
+ netaddr.@O@ netscope.@O@ pool.@O@ ondestroy.@O@ \
parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
httpd.c inet_aton.c iterated_hash.c \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c \
- netaddr.c netscope.c ondestroy.c \
+ netaddr.c netscope.c pool.c ondestroy.c \
parseint.c portset.c quota.c radix.c random.c \
ratelimiter.c refcount.c region.c result.c rwlock.c \
serial.c sha1.c sha2.c sockaddr.c stats.c string.c strtoul.c \
--- /dev/null
+/*
+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ISC_OBJPOOL_H
+#define ISC_OBJPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/pool.h
+ * \brief An object pool is a mechanism for sharing a small pool of
+ * fungible objects among a large number of objects that depend on them.
+ *
+ * This is useful, for example, when it causes performance problems for
+ * large number of zones to share a single memory context or task object,
+ * but it would create a different set of problems for them each to have an
+ * independent task or memory context.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef void
+(*isc_pooldeallocator_t)(void **object);
+
+typedef isc_result_t
+(*isc_poolinitializer_t)(void **target, void *arg);
+
+typedef struct isc_pool isc_pool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count,
+ isc_pooldeallocator_t free,
+ isc_poolinitializer_t init, void *initarg,
+ isc_pool_t **poolp);
+/*%<
+ * Create a pool of "count" object pointers. If 'free' is not NULL,
+ * it points to a function that will detach the objects. 'init'
+ * points to a function that will initialize the arguments, and
+ * 'arg' to an argument to be passed into that function (for example,
+ * a relevant manager or context object).
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li init != NULL
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*poolp' points to the new object pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void *
+isc_pool_get(isc_pool_t *pool);
+/*%<
+ * Returns a pointer to an object from the pool. Currently the object
+ * is chosen from the pool at random. (This may be changed in the future
+ * to something that guaratees balance.)
+ */
+
+int
+isc_pool_count(isc_pool_t *pool);
+/*%<
+ * Returns the number of objcts in the pool 'pool'.
+ */
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count, isc_pool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of objects in the pool pointed to by
+ * 'sourcep', then a new pool of size 'count' is allocated, the existing
+ * objects are copied into it, additional ones created to bring the
+ * total number up to 'count', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'count' is less than or equal to the number of objects in 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_pool_destroy(isc_pool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OBJPOOL_H */
} while(0)
typedef struct isc_prefix {
- unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
- unsigned int bitlen; /* 0 for "any" */
- isc_refcount_t refcount;
- union {
+ isc_mem_t *mctx;
+ unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
+ unsigned int bitlen; /* 0 for "any" */
+ isc_refcount_t refcount;
+ union {
struct in_addr sin;
struct in6_addr sin6;
- } add;
+ } add;
} isc_prefix_t;
typedef void (*isc_radix_destroyfunc_t)(void *);
#define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0)
typedef struct isc_radix_node {
- isc_uint32_t bit; /* bit length of the prefix */
- isc_prefix_t *prefix; /* who we are in radix tree */
- struct isc_radix_node *l, *r; /* left and right children */
- struct isc_radix_node *parent; /* may be used */
- void *data[2]; /* pointers to IPv4 and IPV6 data */
- int node_num[2]; /* which node this was in the tree,
+ isc_mem_t *mctx;
+ isc_uint32_t bit; /* bit length of the prefix */
+ isc_prefix_t *prefix; /* who we are in radix tree */
+ struct isc_radix_node *l, *r; /* left and right children */
+ struct isc_radix_node *parent; /* may be used */
+ void *data[2]; /* pointers to IPv4 and IPV6 data */
+ int node_num[2]; /* which node this was in the tree,
or -1 for glue nodes */
} isc_radix_node_t;
#define RADIX_TREE_VALID(a) ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC);
typedef struct isc_radix_tree {
- unsigned int magic;
- isc_mem_t *mctx;
- isc_radix_node_t *head;
- isc_uint32_t maxbits; /* for IP, 32 bit addresses */
- int num_active_node; /* for debugging purposes */
- int num_added_node; /* total number of nodes */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_radix_node_t *head;
+ isc_uint32_t maxbits; /* for IP, 32 bit addresses */
+ int num_active_node; /* for debugging purposes */
+ int num_added_node; /* total number of nodes */
} isc_radix_tree_t;
isc_result_t
lctx = isc_mem_get(mctx, sizeof(*lctx));
if (lctx != NULL) {
- lctx->mctx = mctx;
+ lctx->mctx = NULL;
+ isc_mem_attach(mctx, &lctx->mctx);
lctx->categories = NULL;
lctx->category_count = 0;
lctx->modules = NULL;
result = isc_mutex_init(&lctx->lock);
if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, lctx, sizeof(*lctx));
+ isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
return (result);
}
lctx->mctx = NULL;
lctx->magic = 0;
- isc_mem_put(mctx, lctx, sizeof(*lctx));
+ isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
*lctxp = NULL;
}
--- /dev/null
+/*
+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/mem.h>
+#include <isc/random.h>
+#include <isc/pool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_pool {
+ isc_mem_t * mctx;
+ unsigned int count;
+ isc_pooldeallocator_t free;
+ isc_poolinitializer_t init;
+ void * initarg;
+ void ** pool;
+};
+
+/***
+ *** Functions.
+ ***/
+
+static isc_result_t
+alloc_pool(isc_mem_t *mctx, unsigned int count, isc_pool_t **poolp) {
+ isc_pool_t *pool;
+
+ pool = isc_mem_get(mctx, sizeof(*pool));
+ if (pool == NULL)
+ return (ISC_R_NOMEMORY);
+ pool->count = count;
+ pool->free = NULL;
+ pool->init = NULL;
+ pool->initarg = NULL;
+ pool->mctx = NULL;
+ isc_mem_attach(mctx, &pool->mctx);
+ pool->pool = isc_mem_get(mctx, count * sizeof(void *));
+ if (pool->pool == NULL) {
+ isc_mem_put(mctx, pool, sizeof(*pool));
+ return (ISC_R_NOMEMORY);
+ }
+ memset(pool->pool, 0, count * sizeof(void *));
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count,
+ isc_pooldeallocator_t free,
+ isc_poolinitializer_t init, void *initarg,
+ isc_pool_t **poolp)
+{
+ isc_pool_t *pool = NULL;
+ isc_result_t result;
+ unsigned int i;
+
+ INSIST(count > 0);
+
+ /* Allocate the pool structure */
+ result = alloc_pool(mctx, count, &pool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ pool->free = free;
+ pool->init = init;
+ pool->initarg = initarg;
+
+ /* Populate the pool */
+ for (i = 0; i < count; i++) {
+ result = init(&pool->pool[i], initarg);
+ if (result != ISC_R_SUCCESS) {
+ isc_pool_destroy(&pool);
+ return (result);
+ }
+ }
+
+ *poolp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void *
+isc_pool_get(isc_pool_t *pool) {
+ isc_uint32_t i;
+ isc_random_get(&i);
+ return (pool->pool[i % pool->count]);
+}
+
+int
+isc_pool_count(isc_pool_t *pool) {
+ REQUIRE(pool != NULL);
+ return (pool->count);
+}
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count,
+ isc_pool_t **targetp)
+{
+ isc_result_t result;
+ isc_pool_t *pool;
+
+ REQUIRE(sourcep != NULL && *sourcep != NULL);
+ REQUIRE(targetp != NULL && *targetp == NULL);
+
+ pool = *sourcep;
+ if (count > pool->count) {
+ isc_pool_t *newpool = NULL;
+ unsigned int i;
+
+ /* Allocate a new pool structure */
+ result = alloc_pool(pool->mctx, count, &newpool);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ newpool->free = pool->free;
+ newpool->init = pool->init;
+ newpool->initarg = pool->initarg;
+
+ /* Copy over the objects from the old pool */
+ for (i = 0; i < pool->count; i++) {
+ newpool->pool[i] = pool->pool[i];
+ pool->pool[i] = NULL;
+ }
+
+ /* Populate the new entries */
+ for (i = pool->count; i < count; i++) {
+ result = pool->init(&newpool->pool[i], pool->initarg);
+ if (result != ISC_R_SUCCESS) {
+ isc_pool_destroy(&pool);
+ return (result);
+ }
+ }
+
+ isc_pool_destroy(&pool);
+ pool = newpool;
+ }
+
+ *sourcep = NULL;
+ *targetp = pool;
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_pool_destroy(isc_pool_t **poolp) {
+ unsigned int i;
+ isc_pool_t *pool = *poolp;
+ for (i = 0; i < pool->count; i++) {
+ if (pool->free != NULL && pool->pool[i] != NULL)
+ pool->free(&pool->pool[i]);
+ }
+ isc_mem_put(pool->mctx, pool->pool, pool->count * sizeof(void *));
+ isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
+ *poolp = NULL;
+}
void *dest, int bitlen);
static void
-_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix);
+_deref_prefix(isc_prefix_t *prefix);
static isc_result_t
_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix);
}
prefix->family = family;
+ prefix->mctx = NULL;
+ isc_mem_attach(mctx, &prefix->mctx);
isc_refcount_init(&prefix->refcount, 1);
}
static void
-_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix) {
+_deref_prefix(isc_prefix_t *prefix) {
int refs;
if (prefix == NULL)
if (refs <= 0) {
isc_refcount_destroy(&prefix->refcount);
- isc_mem_put(mctx, prefix, sizeof(isc_prefix_t));
+ isc_mem_putanddetach(&prefix->mctx, prefix,
+ sizeof(isc_prefix_t));
}
}
isc_result_t ret;
ret = _new_prefix(mctx, target, prefix->family,
&prefix->add, prefix->bitlen);
- return ret;
+ return (ret);
}
isc_refcount_increment(&prefix->refcount, NULL);
if (radix == NULL)
return (ISC_R_NOMEMORY);
- radix->mctx = mctx;
+ radix->mctx = NULL;
+ isc_mem_attach(mctx, &radix->mctx);
radix->maxbits = maxbits;
radix->head = NULL;
radix->num_active_node = 0;
REQUIRE(radix != NULL);
if (radix->head != NULL) {
-
isc_radix_node_t *Xstack[RADIX_MAXBITS+1];
isc_radix_node_t **Xsp = Xstack;
isc_radix_node_t *Xrn = radix->head;
isc_radix_node_t *r = Xrn->r;
if (Xrn->prefix != NULL) {
- _deref_prefix(radix->mctx, Xrn->prefix);
+ _deref_prefix(Xrn->prefix);
if (func != NULL && (Xrn->data[0] != NULL ||
Xrn->data[1] != NULL))
func(Xrn->data);
void
-isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func)
-{
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
REQUIRE(radix != NULL);
_clear_radix(radix, func);
- isc_mem_put(radix->mctx, radix, sizeof(*radix));
+ isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix));
}
* func will be called as func(node->prefix, node->data)
*/
void
-isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func)
-{
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func) {
isc_radix_node_t *node;
REQUIRE(func != NULL);
*target = node;
return (ISC_R_SUCCESS);
} else {
- result =
- _ref_prefix(radix->mctx, &node->prefix, prefix);
+ result = _ref_prefix(radix->mctx,
+ &node->prefix, prefix);
if (result != ISC_R_SUCCESS)
return (result);
}
* make sure there is a prefix associated with it!
*/
if (node->prefix != NULL)
- _deref_prefix(radix->mctx, node->prefix);
+ _deref_prefix(node->prefix);
node->prefix = NULL;
node->data[0] = node->data[1] = NULL;
if (node->r == NULL && node->l == NULL) {
parent = node->parent;
- _deref_prefix(radix->mctx, node->prefix);
+ _deref_prefix(node->prefix);
isc_mem_put(radix->mctx, node, sizeof(*node));
radix->num_active_node--;
parent = node->parent;
child->parent = parent;
- _deref_prefix(radix->mctx, node->prefix);
+ _deref_prefix(node->prefix);
isc_mem_put(radix->mctx, node, sizeof(*node));
radix->num_active_node--;
OBJS = isctest.@O@
SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \
sockaddr_test.c symtab_test.c task_test.c queue_test.c \
- parse_test.c
+ parse_test.c pool_test.c
SUBDIRS =
TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
- queue_test@EXEEXT@ parse_test@EXEEXT@
+ queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@
@BIND9_MAKE_RULES@
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
sockaddr_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+pool_test@EXEEXT@: pool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ pool_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
unit::
sh ${top_srcdir}/unit/unittest.sh
--- /dev/null
+/*
+ * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/mem.h>
+#include <isc/pool.h>
+
+#include "isctest.h"
+
+static isc_result_t
+poolinit(void **target, void *arg) {
+ isc_result_t result;
+
+ isc_taskmgr_t *mgr = (isc_taskmgr_t *) arg;
+ isc_task_t *task = NULL;
+ result = isc_task_create(mgr, 0, &task);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ *target = (void *) task;
+ return (ISC_R_SUCCESS);
+}
+
+static void
+poolfree(void **target) {
+ isc_task_t *task = *(isc_task_t **) target;
+ isc_task_destroy(&task);
+ *target = NULL;
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a pool */
+ATF_TC(create_pool);
+ATF_TC_HEAD(create_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a pool");
+}
+ATF_TC_BODY(create_pool, tc) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 8, poolfree, poolinit, taskmgr, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool), 8);
+
+ isc_pool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+/* Resize a pool */
+ATF_TC(expand_pool);
+ATF_TC_HEAD(expand_pool, tc) {
+ atf_tc_set_md_var(tc, "descr", "expand a pool");
+}
+ATF_TC_BODY(expand_pool, tc) {
+ isc_result_t result;
+ isc_pool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 10, poolfree, poolinit, taskmgr, &pool1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool1), 10);
+
+ /* resizing to a smaller size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 5, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to the same size should have no effect */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 10, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+ ATF_REQUIRE_EQ(pool2, hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+ pool1 = pool2;
+ pool2 = NULL;
+
+ /* resizing to larger size should make a new pool */
+ hold = pool1;
+ result = isc_pool_expand(&pool1, 20, &pool2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool2), 20);
+ ATF_REQUIRE(pool2 != hold);
+ ATF_REQUIRE_EQ(pool1, NULL);
+
+ isc_pool_destroy(&pool2);
+ ATF_REQUIRE_EQ(pool2, NULL);
+
+ isc_test_end();
+}
+
+/* Get objects */
+ATF_TC(get_objects);
+ATF_TC_HEAD(get_objects, tc) {
+ atf_tc_set_md_var(tc, "descr", "get objects");
+}
+ATF_TC_BODY(get_objects, tc) {
+ isc_result_t result;
+ isc_pool_t *pool = NULL;
+ void *item;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_pool_create(mctx, 2, poolfree, poolinit, taskmgr, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_pool_count(pool), 2);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task1);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task2);
+
+ item = isc_pool_get(pool);
+ ATF_REQUIRE(item != NULL);
+ isc_task_attach((isc_task_t *) item, &task3);
+
+ isc_task_detach(&task1);
+ isc_task_detach(&task2);
+ isc_task_detach(&task3);
+
+ isc_pool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, create_pool);
+ ATF_TP_ADD_TC(tp, expand_pool);
+ ATF_TP_ADD_TC(tp, get_objects);
+
+ return (atf_no_error());
+}
+
isc_parse_uint16
isc_parse_uint32
isc_parse_uint8
+isc_pool_create
+isc_pool_count
+isc_pool_destroy
+isc_pool_expand
+isc_pool_get
isc_portset_add
isc_portset_addrange
isc_portset_create
# End Source File
# Begin Source File
+SOURCE=..\pool.c
+# End Source File
+# Begin Source File
+
SOURCE=..\portset.c
# End Source File
# Begin Source File
-@erase "$(INTDIR)\ondestroy.obj"
-@erase "$(INTDIR)\os.obj"
-@erase "$(INTDIR)\parseint.obj"
+ -@erase "$(INTDIR)\pool.obj"
-@erase "$(INTDIR)\portset.obj"
-@erase "$(INTDIR)\quota.obj"
-@erase "$(INTDIR)\radix.obj"
"$(INTDIR)\taskpool.obj" \
"$(INTDIR)\timer.obj" \
"$(INTDIR)\parseint.obj" \
+ "$(INTDIR)\pool.obj" \
"$(INTDIR)\portset.obj" \
"$(INTDIR)\region.obj"
-@erase "$(INTDIR)\os.sbr"
-@erase "$(INTDIR)\parseint.obj"
-@erase "$(INTDIR)\parseint.sbr"
+ -@erase "$(INTDIR)\pool.obj"
+ -@erase "$(INTDIR)\pool.sbr"
-@erase "$(INTDIR)\portset.obj"
-@erase "$(INTDIR)\portset.sbr"
-@erase "$(INTDIR)\quota.obj"
"$(INTDIR)\taskpool.sbr" \
"$(INTDIR)\timer.sbr" \
"$(INTDIR)\parseint.sbr" \
+ "$(INTDIR)\pool.sbr" \
"$(INTDIR)\portset.sbr" \
"$(INTDIR)\region.sbr"
"$(INTDIR)\taskpool.obj" \
"$(INTDIR)\timer.obj" \
"$(INTDIR)\parseint.obj" \
+ "$(INTDIR)\pool.obj" \
"$(INTDIR)\portset.obj" \
"$(INTDIR)\region.obj"
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\pool.c
+
+!IF "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\pool.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\pool.obj" "$(INTDIR)\pool.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\portset.c