pcs 98/02/06 10:16:46
Modified: src/modules/standard mod_so.c
Log:
Make LoadModule and LoadFile work correctly across restarts (i.e.
by unloading the loaded modules/files, then reloading when the config
file is read again).
Add longer commentary about how to use the module (which could become
a part of the documentation when this module become non-experimental).
Properly report errors during LoadFile.
Revision Changes Path
1.3 +125 -36 apache-1.3/src/modules/standard/mod_so.c
Index: mod_so.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/modules/standard/mod_so.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- mod_so.c 1998/02/04 10:22:18 1.2
+++ mod_so.c 1998/02/06 18:16:45 1.3
@@ -1,5 +1,5 @@
/* ====================================================================
- * Copyright (c) 1995-1997 The Apache Group. All rights reserved.
+ * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,7 +51,58 @@
*
*/
-/* How to create .so files on various platforms:
+/*
+ * This module is used to load Apache modules at runtime. This means
+ * that the server functionality can be extended without recompiling
+ * and even without taking the server down at all!
+ *
+ * To use, you'll first need to build your module as a shared library, then
+ * update your configuration (httpd.conf) to get the Apache core to
+ * load the module at start-up.
+ *
+ * The easiest way to build a module as a shared library is to use the
+ * "SharedModule" command in the Configuration file, instead of AddModule.
+ * You should also change the file extension from .o to .so. So, for example,
+ * to build the status module as a shared library edit Configuration
+ * and change
+ * AddModule modules/standard/mod_status.o
+ * to
+ * SharedModule modules/standard/mod_status.so
+ *
+ * Run Configure and make. Now Apache's httpd will _not_ include
+ * mod_status. Instead a shared library called mod_status.so will be
+ * build, in the modules/standard directory. You can build any or all
+ * modules as shared libraries like this.
+ *
+ * To use the shared module, move the .so file(s) into an appropriate
+ * directory. You might like to create a directory called "modules" under
+ * you server root for this (e.g. /usr/local/httpd/modules).
+ *
+ * Then edit your conf/httpd.conf file, and add LoadModule lines. For
+ * example
+ * LoadModule status_module modules/mod_status.so
+ *
+ * The first argument is the module's structure name (look at the
+ * end of the module source to find this). The second option is
+ * the path to the module file, relative to the server root.
+ * Put these directives right at the top of your httpd.conf file.
+ *
+ * Now you can start Apache. A message will be logged at "debug" level
+ * to your error_log to confirm that the module(s) are loaded (use
+ * "LogLevel debug" directive to get these log messages).
+ *
+ * If you edit the LoadModule directives while the server is live you
+ * can get Apache to re-load the modules by sending it a HUP or USR1
+ * signal as normal. You can use this to dynamically change the
+ * capability of your server without bringing it down.
+ *
+ * Apache's Configure currently only creates shared modules on
+ * Linux 2 and FreeBSD systems.
+ */
+
+/* More details about shared libraries:
+ *
+ * How to create .so files on various platforms:
FreeBSD:
"gcc -fpic" to compile
@@ -120,36 +171,63 @@
#define RTLD_LAZY 1
#endif
-/*
- * The hard part of implementing LoadModule is deciding what to do about
- * rereading the config files. This proof-of-concept implementation takes
the
- * cheap way out: we only actually load the modules the first time through.
- */
-
-static int been_there_done_that = 0; /* Loaded the modules yet? */
static int have_symbol_table = 0;
#ifndef NO_DLOPEN
+
+/* This is the cleanup for a loaded DLL. It unloads the module.
+ * This is called as a cleanup function.
+ */
+
+void unload_module(module *modp)
+{
+ char mod_name[50]; /* Um, no pool, so make this static */
+
+ /* Take a copy of the module name so we can report that it has been
+ * unloaded (since modp itself will have been unloaded). */
+ strncpy(mod_name, modp->name, 49);
+ mod_name[49] = '\0';
+
+ remove_module(modp);
+
+ /* The Linux manpage doesn't give any way to check the success of
+ * dlclose() */
+ dlclose(modp->dynamic_load_handle);
+
+ aplog_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL,
+ "unloaded module %s", mod_name);
+}
+
+/* unload_file is the cleanup routine for files loaded by
+ * load_file(). Unfortunately we don't keep a record of the filename
+ * that was loaded, so we can't report the unload for debug purposes
+ * or include the filename in error message.
+ */
+
+void unload_file(void *handle)
+{
+ /* The Linux manpage doesn't give any way to check the success of
+ * dlclose() */
+ dlclose(handle);
+}
+
+/* load_module is called for the directive LoadModule
+ */
+
static const char *load_module (cmd_parms *cmd, void *dummy, char *modname,
char *filename)
{
void *modhandle;
module *modp;
const char *szModuleFile=server_root_relative(cmd->pool, filename);
- if (been_there_done_that) return NULL;
-
if (!(modhandle = dlopen(szModuleFile, RTLD_NOW)))
{
const char *my_error = dlerror();
return pstrcat (cmd->pool, "Cannot load ", szModuleFile,
- " into server: ", my_error, ":", dlerror(),
+ " into server: ", my_error,
NULL);
}
- /* If I knew what the correct cast is here, I'd be happy. But
- * I don't. So I'll use (void *). It works.
- */
-
aplog_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL,
"loaded module %s", modname);
@@ -162,8 +240,17 @@
" in file ", filename, ":", dlerror(), NULL);
}
+ modp->dynamic_load_handle = modhandle;
+
add_module (modp);
+ /* Register a cleanup in the config pool (normally pconf). When
+ * we do a restart (or shutdown) this cleanup will cause the
+ * DLL to be unloaded.
+ */
+ register_cleanup(cmd->pool, modp,
+ (void (*)(void*))unload_module, null_cleanup);
+
/* Alethea Patch (rws,djw2) - need to run configuration functions
in new modules */
@@ -175,42 +262,46 @@
((void**)cmd->server->lookup_defaults)[modp->module_index]=
(*modp->create_dir_config)(cmd->pool, NULL);
-
return NULL;
}
+/* load_file implements the LoadFile directive.
+ */
+
static const char *load_file (cmd_parms *cmd, void *dummy, char *filename)
{
- if (been_there_done_that) return NULL;
+ void *handle;
+ char *file;
+
+ file = server_root_relative(cmd->pool, filename);
- if (!dlopen(server_root_relative(cmd->pool, filename), 1))
- return pstrcat (cmd->pool, "Cannot load ", filename, " into
server", NULL);
-
- return NULL;
+ if (!(handle = dlopen(file, 1))) {
+ const char *my_error = dlerror();
+ return pstrcat (cmd->pool, "Cannot load ", filename,
+ " into server:", my_error, NULL);
+ }
+
+ aplog_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, NULL,
+ "loaded file %s", filename);
+
+ register_cleanup(cmd->pool, handle, unload_file, null_cleanup);
+
+ return NULL;
}
#else
static const char *load_file(cmd_parms *cmd, void *dummy, char *filename)
{
- if(!been_there_done_that)
- fprintf(stderr, "WARNING: LoadFile not supported\n");
+ fprintf(stderr, "WARNING: LoadFile not supported\n");
return NULL;
}
static const char *load_module(cmd_parms *cmd, void *dummy, char *modname,
char *filename)
{
- if(!been_there_done_that)
- fprintf(stderr, "WARNING: LoadModule not supported\n");
+ fprintf(stderr, "WARNING: LoadModule not supported\n");
return NULL;
}
#endif
-static void check_loaded_modules (server_rec *dummy, pool *p)
-{
- if (been_there_done_that) return;
-
- been_there_done_that = 1;
-}
-
command_rec so_cmds[] = {
{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2,
"a module name, and the name of a file to load it from"},
@@ -221,7 +312,7 @@
module so_module = {
STANDARD_MODULE_STUFF,
- check_loaded_modules, /* initializer */
+ NULL, /* initializer */
NULL, /* create per-dir config */
NULL, /* merge per-dir config */
NULL, /* server config */
@@ -236,5 +327,3 @@
NULL, /* logger */
NULL /* header parser */
};
-
-