give embedded modules a helping hand by backing up and restoring their global variabl...
authorKevin P. Fleming <kpfleming@digium.com>
Thu, 22 Feb 2007 02:36:00 +0000 (02:36 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Thu, 22 Feb 2007 02:36:00 +0000 (02:36 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@56092 65c4cc65-6c06-0410-ace0-fbb531ad65f3

Makefile.moddir_rules
Makefile.rules
build_tools/make_linker_eo_script [new file with mode: 0755]
include/asterisk/module.h
main/loader.c

index c614c2a..d2dafe3 100644 (file)
@@ -34,11 +34,13 @@ $(LOADABLE_MODS:%=%.so): ASTCFLAGS+=-fPIC
 $(LOADABLE_MODS:%=%.so): LIBS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LIB))
 $(LOADABLE_MODS:%=%.so): ASTLDFLAGS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LDFLAGS))
 
+$(EMBEDDED_MODS:%=%.o): ASTCFLAGS+=-DEMBEDDED_MODULE=$*
+
 $(addsuffix .so,$(filter $(LOADABLE_MODS),$(C_MODS))): %.so: %.o
 $(addsuffix .so,$(filter $(LOADABLE_MODS),$(CC_MODS))): %.so: %.oo
 
-modules.link: $(addsuffix .o,$(filter $(EMBEDDED_MODS),$(C_MODS)))
-modules.link: $(addsuffix .oo,$(filter $(EMBEDDED_MODS),$(CC_MODS)))
+modules.link: $(addsuffix .eo,$(filter $(EMBEDDED_MODS),$(C_MODS)))
+modules.link: $(addsuffix .eoo,$(filter $(EMBEDDED_MODS),$(CC_MODS)))
 
 .PHONY: clean uninstall _all
 
@@ -64,11 +66,11 @@ endif
 
 modules.link:
        @rm -f $@
-       @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.o,$^)); do echo "INPUT (../$${file})" >> $@; done
-       @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.o,$^)); do echo "INPUT (../$${file})" >> $@; done
+       @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.eo %.eoo,$^)); do echo "INPUT (../$${file})" >> $@; done
+       @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.eo %.eoo,$^)); do echo "INPUT (../$${file})" >> $@; done
 
 clean::
-       rm -f *.so *.o *.oo
+       rm -f *.so *.o *.oo *.eo *.eoo
        rm -f .*.o.d .*.oo.d
        rm -f modules.link
 
index 9d20c5a..e847c3a 100644 (file)
@@ -44,6 +44,22 @@ else
        $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
 endif
 
+%.o: %.i
+       $(ECHO_PREFIX) echo "   [CC] $< -> $@"
+ifeq ($(AST_DEVMODE),yes)
+       $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
+else
+       $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
+endif
+
+%.i: %.c
+       $(ECHO_PREFIX) echo "   [CC] $< -> $@"
+ifeq ($(AST_DEVMODE),yes)
+       $(CMD_PREFIX) $(CC) -o $@ -E $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
+else
+       $(CMD_PREFIX) $(CC) -o $@ -E $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
+endif
+
 %.o: %.s
        $(ECHO_PREFIX) echo "   [AS] $< -> $@"
 ifeq ($(AST_DEVMODE),yes)
@@ -76,6 +92,18 @@ endif
        $(ECHO_PREFIX) echo "   [LDXX] $^ -> $@"
        $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS)
 
+%.eo: %.o
+       $(ECHO_PREFIX) echo "   [EMBED] $< -> $@"
+       $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld
+       $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $<
+       $(CMD_PREFIX) rm -f .$@.ld
+
+%.eoo: %.o
+       $(ECHO_PREFIX) echo "   [EMBED] $< -> $@"
+       $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld
+       $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $<
+       $(CMD_PREFIX) rm -f .$@.ld
+
 %: %.o
        $(ECHO_PREFIX) echo "   [LD] $^ -> $@"
        $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $^ $(PTHREAD_LIBS) $(LIBS)
diff --git a/build_tools/make_linker_eo_script b/build_tools/make_linker_eo_script
new file mode 100755 (executable)
index 0000000..39456c0
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+cat << EOF
+SECTIONS {
+.text : { *(.text) }
+.data : { __${1}_data_start = . ; *(.data) __${1}_data_end = . ;}
+.rodata : { *(.rodata*) }
+.bss : { __${1}_bss_start = . ; *(.bss) __${1}_bss_end = . ;}
+.debug_abbrev : { *(.debug_abbrev) }
+.debug_info : { *(.debug_info) }
+.debug_line : { *(.debug_line) }
+.debug_macinfo : { *(.debug_macinfo) }
+.dtors : { *(.dtors) }
+.ctors : { *(.ctors) }
+.data.rel.local : { *(.data.rel.local) }
+.data.rel.ro.local : { *(.data.rel.ro.local) }
+.debug_frame : { *(.debug_frame) }
+.eh_frame : { *(.eh_frame) }
+.debug_loc : { *(.debug_loc) }
+.debug_pubname : { *(.debug_pubname) }
+.debug_aranges : { *(.debug_aranges) }
+.debug_ranges : { *(.debug_ranges) }
+.debug_str : { *(.debug_str) }
+.comment : { *(.comment) }
+.note.GNU-stack : { *(.note.GNU-stack) }
+}
+EOF
index 9d51488..4ced03f 100644 (file)
@@ -192,6 +192,8 @@ struct ast_module_info {
        enum ast_module_load_result (*load)(void);      /* register stuff etc. Optional. */
        int (*reload)(void);                    /* config etc. Optional. */
        int (*unload)(void);                    /* unload. called with the module locked */
+       int (*backup_globals)(void);            /* for embedded modules, backup global data */
+       void (*restore_globals)(void);          /* for embedded modules, restore global data */
        const char *name;                       /* name of the module for loader reference and CLI commands */
        const char *description;                /* user friendly description of the module. */
 
@@ -253,8 +255,54 @@ void ast_module_unref(struct ast_module *);
    and populated at the end of the module's source file... */
 const static __attribute__((unused)) struct ast_module_info *ast_module_info;
 
+#if defined(EMBEDDED_MODULE)
+
+#define make_var_sub(mod, type) __ ## mod ## _ ## type
+#define make_var(mod, type) make_var_sub(mod, type)
+
+extern void make_var(EMBEDDED_MODULE, bss_start);
+extern void make_var(EMBEDDED_MODULE, bss_end);
+extern void make_var(EMBEDDED_MODULE, data_start);
+extern void make_var(EMBEDDED_MODULE, data_end);
+
+static void * __attribute__((section(".embed_module"))) __global_backup;
+
+static int __backup_globals(void)
+{
+       size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start);
+
+       if (__global_backup)
+               return 0;
+
+       if (!data_size)
+               return 0;
+
+       if (!(__global_backup = ast_malloc(data_size)))
+               return -1;
+
+       memcpy(__global_backup, & make_var(EMBEDDED_MODULE, data_start), data_size);
+
+       return 0;
+}
+
+static void __restore_globals(void)
+{
+       size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start);
+       size_t bss_size = & make_var(EMBEDDED_MODULE, bss_end) - & make_var(EMBEDDED_MODULE, bss_start);
+
+       if (bss_size)
+               memset(& make_var(EMBEDDED_MODULE, bss_start), 0, bss_size);
+
+       if (!data_size || !__global_backup)
+               return;
+
+       memcpy(& make_var(EMBEDDED_MODULE, data_start), __global_backup, data_size);
+}
+
 #define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...) \
        static struct ast_module_info __mod_info = {            \
+               .backup_globals = __backup_globals,             \
+               .restore_globals = __restore_globals,           \
                .name = AST_MODULE,                             \
                .flags = flags_to_set,                          \
                .description = desc,                            \
@@ -271,6 +319,31 @@ const static __attribute__((unused)) struct ast_module_info *ast_module_info;
        } \
        const static struct ast_module_info *ast_module_info = &__mod_info
 
+#undef make_var
+#undef make_var_sub
+
+#else /* !defined(EMBEDDED_MODULE) */
+
+#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...) \
+       static struct ast_module_info __mod_info = {            \
+               .name = AST_MODULE,                             \
+               .flags = flags_to_set,                          \
+               .description = desc,                            \
+               .key = keystr,                                  \
+               fields                                          \
+       };                                                      \
+       static void  __attribute__ ((constructor)) __reg_module(void) \
+       { \
+               ast_module_register(&__mod_info); \
+       } \
+       static void  __attribute__ ((destructor)) __unreg_module(void) \
+       { \
+               ast_module_unregister(&__mod_info); \
+       } \
+       const static struct ast_module_info *ast_module_info = &__mod_info
+
+#endif /* !defined(EMBEDDED_MODULE) */
+
 #define AST_MODULE_INFO_STANDARD(keystr, desc)         \
        AST_MODULE_INFO(keystr, AST_MODFLAG_DEFAULT, desc,      \
                        .load = load_module,                    \
index 65c95ec..4516b37 100644 (file)
@@ -483,6 +483,9 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
        if (!error)
                ast_update_use_count();
 
+       if (!error && !mod->lib)
+               mod->info->restore_globals();
+
        return res;
 }
 
@@ -627,6 +630,11 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi
                return AST_MODULE_LOAD_DECLINE;
        }
 
+       if (!mod->lib && mod->info->backup_globals()) {
+               ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
        ast_clear_flag(mod, FLAG_DECLINED);
 
        if (mod->info->load)