summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Nagy <mnagy@redhat.com>2008-12-15 17:38:40 +0100
committerMartin Nagy <mnagy@redhat.com>2009-02-11 20:40:41 +0100
commitc76f8c86f453ad60719d31289b04f13ac244114c (patch)
treec776e71a184c3334d4449c9ccf28a6f00524a60a
parentaad64960a5681975b032c1e4fcd133e8f806c9cb (diff)
downloadbind_dynamic-c76f8c86f453ad60719d31289b04f13ac244114c.tar.gz
bind_dynamic-c76f8c86f453ad60719d31289b04f13ac244114c.tar.xz
bind_dynamic-c76f8c86f453ad60719d31289b04f13ac244114c.zip
Use a destroy function to free all the resources.
The handle returned by dlopen() is now saved and the library is unloaded on exit. We also load symbol "dynamic_driver_destroy" which is a function with no arguments returning void. It is called on exit. The load_library() is now split into two functions, one function is specifically used to load symbols.
-rw-r--r--bin/named/main.c3
-rw-r--r--lib/dns/dynamic_db.c158
-rw-r--r--lib/dns/include/dns/dynamic_db.h1
3 files changed, 138 insertions, 24 deletions
diff --git a/bin/named/main.c b/bin/named/main.c
index aa6575a..8030e3d 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -44,6 +44,7 @@
#include <isccc/result.h>
#include <dns/dispatch.h>
+#include <dns/dynamic_db.h>
#include <dns/name.h>
#include <dns/result.h>
#include <dns/view.h>
@@ -778,6 +779,8 @@ cleanup(void) {
dlz_drivers_clear();
#endif
+ dns_dynamic_db_cleanup();
+
dns_name_destroy();
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
diff --git a/lib/dns/dynamic_db.c b/lib/dns/dynamic_db.c
index fcee6a5..4e54bc6 100644
--- a/lib/dns/dynamic_db.c
+++ b/lib/dns/dynamic_db.c
@@ -16,6 +16,9 @@
*/
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/once.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
@@ -37,72 +40,179 @@
if (result != ISC_R_SUCCESS) goto cleanup; \
} while (0)
+
typedef isc_result_t (*register_func_t)(isc_mem_t *mctx, const char *name,
const char * const *argv, dns_view_t *view);
+typedef void (*destroy_func_t)(void);
+
+typedef struct dyndb_implementation dyndb_implementation_t;
+
+struct dyndb_implementation {
+ isc_mem_t *mctx;
+ void *handle;
+ register_func_t register_function;
+ destroy_func_t destroy_function;
+ LINK(dyndb_implementation_t) link;
+};
+
+/* List of implementations. Locked by dyndb_lock. */
+static LIST(dyndb_implementation_t) dyndb_implementations;
+/* Locks dyndb_implementations. */
+static isc_mutex_t dyndb_lock;
+static isc_once_t once = ISC_ONCE_INIT;
+
+static void
+dyndb_initialize(void) {
+ RUNTIME_CHECK(isc_mutex_init(&dyndb_lock) == ISC_R_SUCCESS);
+ INIT_LIST(dyndb_implementations);
+}
+
#if HAVE_DLOPEN
static isc_result_t
-load_library(const char *filename, register_func_t *register_function)
+load_symbol(void *handle, const char *symbol_name, void **symbol)
{
- isc_result_t result;
- void *handle; /* XXX: We don't keep the handle around. Should we? */
const char *errmsg;
- REQUIRE(register_function != NULL && *register_function == NULL);
+ REQUIRE(handle != NULL);
+ REQUIRE(symbol != NULL && *symbol == NULL);
- handle = dlopen(filename, RTLD_LAZY);
- if (handle == NULL) {
+ *symbol = dlsym(handle, symbol_name);
+ if (*symbol == NULL) {
+ errmsg = dlerror();
+ if (errmsg == NULL)
+ errmsg = "returned function pointer is NULL";
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
- "Failed to dynamically load driver '%s': %s",
- filename, dlerror());
- CHECK(ISC_R_FAILURE);
+ "Failed to lookup symbol %s: %s",
+ symbol_name, errmsg);
+ return ISC_R_FAILURE;
}
dlerror();
- *register_function = dlsym(handle, "dynamic_driver_init");
- if (*register_function == NULL) {
- errmsg = dlerror();
- if (errmsg == NULL)
- errmsg = "returned function pointer is NULL";
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+load_library(isc_mem_t *mctx, const char *filename, dyndb_implementation_t **imp)
+{
+ isc_result_t result;
+ void *handle;
+ register_func_t register_function = NULL;
+ destroy_func_t destroy_function = NULL;
+
+ REQUIRE(imp != NULL && *imp == NULL);
+
+ handle = dlopen(filename, RTLD_LAZY);
+ if (handle == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
- "Failed to lookup symbol dynamic_driver_init from %s: %s",
- filename, errmsg);
+ "Failed to dynamically load driver '%s': %s",
+ filename, dlerror());
CHECK(ISC_R_FAILURE);
}
dlerror();
+ CHECK(load_symbol(handle, "dynamic_driver_init", (void **)&register_function));
+ CHECK(load_symbol(handle, "dynamic_driver_destroy", (void **)&destroy_function));
+
+ *imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t));
+ if (*imp == NULL)
+ CHECK(ISC_R_NOMEMORY);
+
+ (*imp)->mctx = NULL;
+ isc_mem_attach(mctx, &((*imp)->mctx));
+ (*imp)->handle = handle;
+ (*imp)->register_function = register_function;
+ (*imp)->destroy_function = destroy_function;
+ INIT_LINK(*imp, link);
+
return ISC_R_SUCCESS;
cleanup:
if (handle != NULL)
dlclose(handle);
- *register_function = NULL;
return result;
}
-#else
+
+static void
+unload_library(dyndb_implementation_t **imp)
+{
+ REQUIRE(imp != NULL && *imp != NULL);
+
+ dlclose((*imp)->handle);
+
+ isc_mem_putanddetach(&((*imp)->mctx), *imp, sizeof(dyndb_implementation_t));
+
+ *imp = NULL;
+}
+
+#else /* HAVE_DLOPEN */
static isc_result_t
-load_library(const char *filename, register_func_t *register_function)
+load_library(isc_mem_t *mctx, const char *filename, dyndb_implementation_t **imp)
{
+ UNUSED(mctx);
UNUSED(filename);
- UNUSED(register_function);
+ UNUSED(imp);
return ISC_R_NOTIMPLEMENTED;
}
-#endif
+
+static void
+unload_library(dyndb_implementation_t **imp)
+{
+ REQUIRE(imp != NULL && *imp != NULL);
+
+ isc_mem_putanddetach(&((*imp)->mctx), *imp, sizeof(dyndb_implementation_t));
+
+ *imp = NULL;
+}
+#endif /* HAVE_DLOPEN */
isc_result_t
dns_dynamic_db_load(const char *libname, const char *name, isc_mem_t *mctx,
const char * const *argv, dns_view_t *view)
{
isc_result_t result;
- register_func_t register_func = NULL;
+ dyndb_implementation_t *implementation = NULL;
+
+ RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
+
+ CHECK(load_library(mctx, libname, &implementation));
+ CHECK(implementation->register_function(mctx, name, argv, view));
- CHECK(load_library(libname, &register_func));
- CHECK(register_func(mctx, name, argv, view));
+ LOCK(&dyndb_lock);
+ APPEND(dyndb_implementations, implementation, link);
+ UNLOCK(&dyndb_lock);
+
+ return ISC_R_SUCCESS;
cleanup:
+ if (implementation != NULL)
+ unload_library(&implementation);
+
return result;
}
+
+isc_result_t
+dns_dynamic_db_cleanup(void)
+{
+ dyndb_implementation_t *elem;
+ dyndb_implementation_t *next;
+
+ RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
+
+ LOCK(&dyndb_lock);
+ elem = HEAD(dyndb_implementations);
+ while (elem != NULL) {
+ next = NEXT(elem, link);
+ UNLINK(dyndb_implementations, elem, link);
+ elem->destroy_function();
+ unload_library(&elem);
+ elem = next;
+ }
+ UNLOCK(&dyndb_lock);
+
+ isc_mutex_destroy(&dyndb_lock);
+}
diff --git a/lib/dns/include/dns/dynamic_db.h b/lib/dns/include/dns/dynamic_db.h
index c37fb83..151103f 100644
--- a/lib/dns/include/dns/dynamic_db.h
+++ b/lib/dns/include/dns/dynamic_db.h
@@ -26,5 +26,6 @@ isc_result_t dns_dynamic_db_load(const char *libname, const char *name,
isc_mem_t *mctx, const char * const *argv,
dns_view_t *view);
+isc_result_t dns_dynamic_db_cleanup(void);
#endif