Return-Path: Delivered-To: apache-cvs-archive@hyperreal.org Received: (qmail 8541 invoked by uid 6000); 6 Feb 1998 18:16:48 -0000 Received: (qmail 8533 invoked by alias); 6 Feb 1998 18:16:47 -0000 Delivered-To: apache-1.3-cvs@hyperreal.org Received: (qmail 8531 invoked by uid 151); 6 Feb 1998 18:16:46 -0000 Date: 6 Feb 1998 18:16:46 -0000 Message-ID: <19980206181646.8530.qmail@hyperreal.org> From: pcs@hyperreal.org To: apache-1.3-cvs@hyperreal.org Subject: cvs commit: apache-1.3/src/modules/standard mod_so.c Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org 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 */ }; - -