[asterisk-commits] seanbright: branch seanbright/dependency-loader r411654 - in /team/seanbright...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 2 08:31:26 CDT 2014


Author: seanbright
Date: Wed Apr  2 08:31:20 2014
New Revision: 411654

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=411654
Log:
Add support for dynamic dependency loading based on menuselect-tree.

This patch introduces a new build tool, make_loader_dep, that generates a module
dependency list from menuselect-tree that is used by the module loader when a
module load is requested by the user (autoload is unaffected).

I've tested with autoload=no and executing 'module load chan_pjsip.so' from the
CLI and all modules are loaded correctly.  I had to modify res_pjsip's dependency
list to include res_sorcery_astdb and res_sorcery_memory as that module will not
load without them.

Added:
    team/seanbright/dependency-loader/build_tools/make_loader_dep.c   (with props)
Modified:
    team/seanbright/dependency-loader/Makefile
    team/seanbright/dependency-loader/build_tools/   (props changed)
    team/seanbright/dependency-loader/include/asterisk/module.h
    team/seanbright/dependency-loader/main/   (props changed)
    team/seanbright/dependency-loader/main/loader.c
    team/seanbright/dependency-loader/res/res_pjsip.c

Modified: team/seanbright/dependency-loader/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/seanbright/dependency-loader/Makefile?view=diff&rev=411654&r1=411653&r2=411654
==============================================================================
--- team/seanbright/dependency-loader/Makefile (original)
+++ team/seanbright/dependency-loader/Makefile Wed Apr  2 08:31:20 2014
@@ -356,7 +356,7 @@
 	+@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDFLAGS)
 	+@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LIBS)
 
-$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules
+$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules main/loader_deps.c
 
 ifeq ($(findstring $(OSARCH), mingw32 cygwin ),)
   ifeq ($(shell grep ^MENUSELECT_EMBED=$$ menuselect.makeopts 2>/dev/null),)
@@ -396,6 +396,10 @@
 	@cmp -s $@.tmp $@ || mv $@.tmp $@
 	@rm -f $@.tmp
 
+main/loader_deps.c: build_tools/make_loader_dep.c menuselect-tree
+	+@$(SUBMAKE) -C build_tools make_loader_dep CFLAGS="-g $(LIBXML2_INCLUDE)" LDLIBS="$(LIBXML2_LIB)"
+	@build_tools/make_loader_dep menuselect-tree > $@
+
 include/asterisk/buildopts.h: menuselect.makeopts .lastclean
 	@build_tools/make_buildopts_h > $@.tmp
 	@cmp -s $@.tmp $@ || mv $@.tmp $@
@@ -418,6 +422,7 @@
 	rm -f defaults.h
 	rm -f include/asterisk/build.h
 	rm -f main/version.c
+	rm -f main/loader_deps.c
 	rm -f doc/core-en_US.xml
 	rm -f doc/full-en_US.xml
 	rm -f doc/rest-api/*.wiki

Propchange: team/seanbright/dependency-loader/build_tools/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Apr  2 08:31:20 2014
@@ -1,3 +1,4 @@
 vercomp
+make_loader_dep
 menuselect-deps
 menuselect

Added: team/seanbright/dependency-loader/build_tools/make_loader_dep.c
URL: http://svnview.digium.com/svn/asterisk/team/seanbright/dependency-loader/build_tools/make_loader_dep.c?view=auto&rev=411654
==============================================================================
--- team/seanbright/dependency-loader/build_tools/make_loader_dep.c (added)
+++ team/seanbright/dependency-loader/build_tools/make_loader_dep.c Wed Apr  2 08:31:20 2014
@@ -1,0 +1,229 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2014, malleable, LLC.
+ *
+ * Sean Bright <sean at malleable.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+struct dependency {
+	const xmlChar *name;
+	int is_module;
+};
+
+struct module {
+	const xmlChar *name;
+	int dep_count;
+	int dep_mod_count;
+	struct dependency **dependencies;
+};
+
+struct module_context {
+	const char *app;
+	int modcount;
+	struct module **modules;
+};
+
+static struct module *handle_member_element(xmlNode *node, struct module_context *ctx)
+{
+	xmlNode *curr;
+	struct module *module;
+	int count = 0;
+
+	module = calloc(1, sizeof(struct module));
+	module->name = xmlGetProp(node, "name");
+
+	/* One pass through to count the child nodes */
+	for (curr = node->children; curr; curr = curr->next) {
+		if (curr->type != XML_ELEMENT_NODE) {
+			continue;
+		}
+
+		if (!xmlStrcmp(curr->name, "depend")) {
+			count++;
+		}
+	}
+
+	module->dep_count = module->dep_mod_count = count;
+
+	if (count > 0) {
+		module->dependencies = calloc(count, sizeof(struct dependency *));
+
+		/* Second pass to add the nodes */
+		for (count = 0, curr = node->children; curr; curr = curr->next) {
+			if (curr->type != XML_ELEMENT_NODE) {
+				continue;
+			}
+
+			if (!xmlStrcmp(curr->name, "depend")) {
+				module->dependencies[count] = calloc(1, sizeof(struct dependency));
+				module->dependencies[count]->name = xmlNodeGetContent(curr);
+				count++;
+			}
+		}
+	}
+
+	return module;
+}
+
+static void print_header(struct module_context *ctx)
+{
+	printf("/*\n");
+	printf(" * Dependency loader support\n");
+	printf(" * This file is automatically generated by %s, do not modify.\n", ctx->app);
+	printf(" */\n\n");
+	printf("#include \"asterisk.h\"\n");
+	printf("#include \"asterisk/module.h\"\n\n");
+	printf("#include <stddef.h>\n\n");
+	printf("struct ast_module_dep ast_module_deps[] = {\n");
+}
+
+static void print_module(struct module *module)
+{
+	int i;
+
+	printf("\t{ \"%s\", { ", module->name);
+
+	for (i = 0; i < module->dep_count; i++) {
+		struct dependency *dep = module->dependencies[i];
+
+		if (!dep->is_module) {
+			continue;
+		}
+
+		printf("\"%s\", ", dep->name);
+	}
+
+	printf(" NULL } },\n");
+}
+
+static void print_footer(struct module_context *ctx)
+{
+	printf("\t{ NULL, { NULL } },\n");
+	printf("};\n");
+}
+
+static int build_module_tree(const char *filename, struct module_context *ctx)
+{
+	int size, i;
+	xmlDocPtr doc;
+	xmlXPathContextPtr xpathCtx;
+	xmlXPathObjectPtr xpathObj;
+	xmlNodeSetPtr members;
+
+	doc = xmlParseFile(filename);
+	if (!doc) {
+		fprintf(stderr, "Unable to open file `%s'\n", filename);
+		return -1;
+	}
+
+	xpathCtx = xmlXPathNewContext(doc);
+	if (!xpathCtx) {
+		fprintf(stderr, "Unable to create XPath context\n");
+		xmlFreeDoc(doc);
+		return -1;
+	}
+
+	xpathObj = xmlXPathEvalExpression("/menu/category[contains(@remove_on_change, 'modules.link')]/member", xpathCtx);
+	if (!xpathObj) {
+		fprintf(stderr, "Unable to evaluate XPath expression\n");
+		xmlXPathFreeContext(xpathCtx);
+		xmlFreeDoc(doc);
+		return -1;
+	}
+
+	members = xpathObj->nodesetval;
+
+	size = members ? members->nodeNr : 0;
+
+	if (!size) {
+		xmlXPathFreeObject(xpathObj);
+		xmlXPathFreeContext(xpathCtx);
+		xmlFreeDoc(doc);
+		return 0;
+	}
+
+	ctx->modcount = size;
+	ctx->modules = calloc(size, sizeof(struct module *));
+
+	for (i = 0; i < ctx->modcount; i++) {
+		ctx->modules[i] = handle_member_element(members->nodeTab[i], ctx);
+	}
+
+	xmlXPathFreeObject(xpathObj);
+	xmlXPathFreeContext(xpathCtx);
+	xmlFreeDoc(doc);
+
+	print_header(ctx);
+
+	/* For every module... */
+	for (i = 0; i < ctx->modcount; i++) {
+		int depidx;
+		struct module *module = ctx->modules[i];
+
+		/* Go through each dependency... */
+		for (depidx = 0; depidx < module->dep_count; depidx++) {
+			int modidx;
+			struct dependency *dep = module->dependencies[depidx];
+
+			/* And if it is not a module dependency, exclude it. */
+			for (modidx = 0; modidx < ctx->modcount; modidx++) {
+				if (!xmlStrcmp(dep->name, ctx->modules[modidx]->name)) {
+					dep->is_module = 1;
+					break;
+				}
+			}
+
+			if (!dep->is_module) {
+				module->dep_mod_count--;
+			}
+		}
+
+		if (module->dep_mod_count) {
+			print_module(module);
+		}
+	}
+
+	print_footer(ctx);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct module_context context;
+	context.modules = NULL;
+	context.app = argv[0];
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <menuselect-tree>\n", argv[0]);
+		return -1;
+	}
+
+	xmlInitParser();
+	LIBXML_TEST_VERSION;
+
+	build_module_tree(argv[1], &context);
+
+	xmlCleanupParser();
+	return 0;
+}

Propchange: team/seanbright/dependency-loader/build_tools/make_loader_dep.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/seanbright/dependency-loader/build_tools/make_loader_dep.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/seanbright/dependency-loader/build_tools/make_loader_dep.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/seanbright/dependency-loader/include/asterisk/module.h
URL: http://svnview.digium.com/svn/asterisk/team/seanbright/dependency-loader/include/asterisk/module.h?view=diff&rev=411654&r1=411653&r2=411654
==============================================================================
--- team/seanbright/dependency-loader/include/asterisk/module.h (original)
+++ team/seanbright/dependency-loader/include/asterisk/module.h Wed Apr  2 08:31:20 2014
@@ -482,6 +482,11 @@
 #define SCOPED_MODULE_USE(module) \
 	RAII_VAR(struct ast_module *, __self__ ## __LINE__, ast_module_ref(module), ast_module_unref)
 
+struct ast_module_dep {
+	const char *resource;
+	const char *dependencies[32];
+};
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Propchange: team/seanbright/dependency-loader/main/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Apr  2 08:31:20 2014
@@ -8,4 +8,5 @@
 *.s
 *.so*
 asterisk
+loader_deps.c
 version.c

Modified: team/seanbright/dependency-loader/main/loader.c
URL: http://svnview.digium.com/svn/asterisk/team/seanbright/dependency-loader/main/loader.c?view=diff&rev=411654&r1=411653&r2=411654
==============================================================================
--- team/seanbright/dependency-loader/main/loader.c (original)
+++ team/seanbright/dependency-loader/main/loader.c Wed Apr  2 08:31:20 2014
@@ -128,6 +128,8 @@
 	char resource[0];
 };
 
+extern struct ast_module_dep ast_module_deps[];
+
 static AST_LIST_HEAD_STATIC(module_list, ast_module);
 
 const char *ast_module_name(const struct ast_module *mod)
@@ -1072,14 +1074,66 @@
 	return res;
 }
 
+static int load_dependencies(const char *resource_name)
+{
+	struct ast_module_dep *curr, *module = NULL;
+	const char **dep;
+
+	for (curr = ast_module_deps; curr->resource; curr++) {
+		if (!resource_name_match(curr->resource, resource_name)) {
+			module = curr;
+			break;
+		}
+	}
+
+	if (!module) {
+		/* No dependencies */
+		return 0;
+	}
+
+	dep = module->dependencies;
+	while (*dep) {
+		int res;
+
+		if (find_resource(*dep, 0)) {
+			dep++;
+			continue;
+		}
+
+		/* If our dependency has dependencies, load them first */
+		if ((res = load_dependencies(*dep))) {
+			return res;
+		}
+
+		/* And now load the dependency */
+		if ((res = load_resource(*dep, 0, NULL, 0))) {
+			return res;
+		} else {
+			ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", *dep);
+		}
+
+		dep++;
+	}
+
+	return 0;
+}
+
 int ast_load_resource(const char *resource_name)
 {
 	int res;
+
 	AST_LIST_LOCK(&module_list);
+
+	if ((res = load_dependencies(resource_name))) {
+		AST_LIST_UNLOCK(&module_list);
+		return res;
+	}
+
 	res = load_resource(resource_name, 0, NULL, 0);
 	if (!res) {
 		ast_test_suite_event_notify("MODULE_LOAD", "Message: %s", resource_name);
 	}
+
 	AST_LIST_UNLOCK(&module_list);
 
 	return res;

Modified: team/seanbright/dependency-loader/res/res_pjsip.c
URL: http://svnview.digium.com/svn/asterisk/team/seanbright/dependency-loader/res/res_pjsip.c?view=diff&rev=411654&r1=411653&r2=411654
==============================================================================
--- team/seanbright/dependency-loader/res/res_pjsip.c (original)
+++ team/seanbright/dependency-loader/res/res_pjsip.c Wed Apr  2 08:31:20 2014
@@ -38,7 +38,9 @@
 
 /*** MODULEINFO
 	<depend>pjproject</depend>
+	<depend>res_sorcery_astdb</depend>
 	<depend>res_sorcery_config</depend>
+	<depend>res_sorcery_memory</depend>
 	<support_level>core</support_level>
  ***/
 




More information about the asterisk-commits mailing list