From df96b77cf2c5b0a70aeb6b24ea0dff6faec35efc Mon Sep 17 00:00:00 2001 From: Sander Temme Date: Sun, 18 Nov 2007 15:41:03 +0000 Subject: [PATCH] * Move the Example modules to the newly created examples subdirectory * Hopefully correctly fudge the NWGNU make files * Add mod_example_ipc (without NWGNU stuff or dsp) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@596093 13f79535-47bb-0310-9956-ffa450edef68 --- modules/README | 4 + modules/examples/Makefile.in | 3 + .../{experimental => examples}/NWGNUcase_flt | 0 .../NWGNUcase_flt_in | 0 .../NWGNUexample => examples/NWGNUhooks} | 10 +- modules/examples/NWGNUmakefile | 255 ++++++++++++ modules/examples/config.m4 | 9 + .../mod_case_filter.c | 0 .../mod_case_filter.dsp | 0 .../mod_case_filter_in.c | 0 .../mod_case_filter_in.dsp | 0 .../mod_example_hooks.c} | 33 +- .../mod_example_hooks.dsp} | 0 modules/examples/mod_example_ipc.c | 385 ++++++++++++++++++ modules/experimental/NWGNUmakefile | 3 - modules/experimental/config.m4 | 3 - 16 files changed, 678 insertions(+), 27 deletions(-) create mode 100644 modules/examples/Makefile.in rename modules/{experimental => examples}/NWGNUcase_flt (100%) rename modules/{experimental => examples}/NWGNUcase_flt_in (100%) rename modules/{experimental/NWGNUexample => examples/NWGNUhooks} (95%) create mode 100644 modules/examples/NWGNUmakefile create mode 100644 modules/examples/config.m4 rename modules/{experimental => examples}/mod_case_filter.c (100%) rename modules/{experimental => examples}/mod_case_filter.dsp (100%) rename modules/{experimental => examples}/mod_case_filter_in.c (100%) rename modules/{experimental => examples}/mod_case_filter_in.dsp (100%) rename modules/{experimental/mod_example.c => examples/mod_example_hooks.c} (98%) rename modules/{experimental/mod_example.dsp => examples/mod_example_hooks.dsp} (100%) create mode 100644 modules/examples/mod_example_ipc.c diff --git a/modules/README b/modules/README index f4d5549dbe..c79fb726f5 100644 --- a/modules/README +++ b/modules/README @@ -18,6 +18,10 @@ dav/ echo/ +examples/ + This directory contains some sample code that should help you on your + way to develop your own Apache modules. + experimental/ In this directory we've placed some modules which we think provide some pretty interesting functionality, but which diff --git a/modules/examples/Makefile.in b/modules/examples/Makefile.in new file mode 100644 index 0000000000..7c5c149d85 --- /dev/null +++ b/modules/examples/Makefile.in @@ -0,0 +1,3 @@ +# a modules Makefile has no explicit targets -- they will be defined by +# whatever modules are enabled. just grab special.mk to deal with this. +include $(top_srcdir)/build/special.mk diff --git a/modules/experimental/NWGNUcase_flt b/modules/examples/NWGNUcase_flt similarity index 100% rename from modules/experimental/NWGNUcase_flt rename to modules/examples/NWGNUcase_flt diff --git a/modules/experimental/NWGNUcase_flt_in b/modules/examples/NWGNUcase_flt_in similarity index 100% rename from modules/experimental/NWGNUcase_flt_in rename to modules/examples/NWGNUcase_flt_in diff --git a/modules/experimental/NWGNUexample b/modules/examples/NWGNUhooks similarity index 95% rename from modules/experimental/NWGNUexample rename to modules/examples/NWGNUhooks index 6b532570c7..c78685fa73 100644 --- a/modules/experimental/NWGNUexample +++ b/modules/examples/NWGNUhooks @@ -102,19 +102,19 @@ endif # This is used by the link 'name' directive to name the nlm. If left blank # TARGET_nlm (see below) will be used. # -NLM_NAME = example +NLM_NAME = example_hooks # # This is used by the link '-desc ' directive. # If left blank, NLM_NAME will be used. # -NLM_DESCRIPTION = Apache $(VERSION_STR) Example Module +NLM_DESCRIPTION = Apache $(VERSION_STR) Example Hook Callback Handler Module # # This is used by the '-threadname' directive. If left blank, # NLM_NAME Thread will be used. # -NLM_THREAD_NAME = Example Module +NLM_THREAD_NAME = Example Hook Callback Handler Module # # If this is specified, it will override VERSION value in @@ -159,7 +159,7 @@ XDCDATA = # If there is an NLM target, put it here # TARGET_nlm = \ - $(OBJDIR)/example.nlm \ + $(OBJDIR)/example_hooks.nlm \ $(EOLIST) # @@ -173,7 +173,7 @@ TARGET_lib = \ # Paths must all use the '/' character # FILES_nlm_objs = \ - $(OBJDIR)/mod_example.o \ + $(OBJDIR)/mod_example_hooks.o \ $(EOLIST) # diff --git a/modules/examples/NWGNUmakefile b/modules/examples/NWGNUmakefile new file mode 100644 index 0000000000..1189aa8f07 --- /dev/null +++ b/modules/examples/NWGNUmakefile @@ -0,0 +1,255 @@ +# +# Declare the sub-directories to be built here +# + +SUBDIRS = \ + $(EOLIST) + +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)\build\NWGNUhead.inc + +# +# build this level's files + +# +# Make sure all needed macro's are defined +# + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)\build\NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +# We are referencing example.nlm twice to get around a known issue with the +# makefiles. Normally if there is only one element to be built within a +# directory, the makefile for the single element would be called NWGNUmakefile. +# But if there are multiples, the parent NWGNUmakefile must reference more +# than one submakefile. Because the experimental directory might vary in the +# number of submakefiles, but for the moment only contains one, we reference +# it twice to allow it parent NWGNUmakefile to work properly. If another +# submakefile is added, the extra reference to example.nlm should be removed. +TARGET_nlm = \ + $(OBJDIR)/example.nlm \ + $(OBJDIR)/case_flt.nlm \ + $(OBJDIR)/case_flt_in.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples) +# +install :: nlms FORCE + copy $(OBJDIR)\*.nlm $(INSTALL)\$(BASEDIR)\modules\*.* + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(AP_WORK)\build\NWGNUtail.inc + + diff --git a/modules/examples/config.m4 b/modules/examples/config.m4 new file mode 100644 index 0000000000..dab9e87354 --- /dev/null +++ b/modules/examples/config.m4 @@ -0,0 +1,9 @@ + +APACHE_MODPATH_INIT(examples) + +APACHE_MODULE(example_hooks, Example hook callback handler module, , , no) +APACHE_MODULE(case_filter, Example uppercase conversion filter, , , no) +APACHE_MODULE(case_filter_in, Example uppercase conversion input filter, , , no) +APACHE_MODULE(example_ipc, Example of shared memory and mutex usage, , , no) + +APACHE_MODPATH_FINISH diff --git a/modules/experimental/mod_case_filter.c b/modules/examples/mod_case_filter.c similarity index 100% rename from modules/experimental/mod_case_filter.c rename to modules/examples/mod_case_filter.c diff --git a/modules/experimental/mod_case_filter.dsp b/modules/examples/mod_case_filter.dsp similarity index 100% rename from modules/experimental/mod_case_filter.dsp rename to modules/examples/mod_case_filter.dsp diff --git a/modules/experimental/mod_case_filter_in.c b/modules/examples/mod_case_filter_in.c similarity index 100% rename from modules/experimental/mod_case_filter_in.c rename to modules/examples/mod_case_filter_in.c diff --git a/modules/experimental/mod_case_filter_in.dsp b/modules/examples/mod_case_filter_in.dsp similarity index 100% rename from modules/experimental/mod_case_filter_in.dsp rename to modules/examples/mod_case_filter_in.dsp diff --git a/modules/experimental/mod_example.c b/modules/examples/mod_example_hooks.c similarity index 98% rename from modules/experimental/mod_example.c rename to modules/examples/mod_example_hooks.c index ff09d2cfe4..824de41dd7 100644 --- a/modules/experimental/mod_example.c +++ b/modules/examples/mod_example_hooks.c @@ -25,16 +25,17 @@ * this module, but which may have counterparts in *real* modules, are * prefixed with 'x_' instead of 'example_'. * - * To use mod_example, configure the Apache build with --enable-example and - * compile. Set up a block in your configuration file like so: + * To use mod_example_hooks, configure the Apache build with + * --enable-example and compile. Set up a block in your + * configuration file like so: * * - * SetHandler example-handler + * SetHandler example-hooks-handler * * * When you look at that location on your server, you will see a backtrace of * the callbacks that have been invoked up to that point. See the ErrorLog for - * more information on code paths that touch mod_example. + * more information on code paths that touch mod_example_hooks. * * IMPORTANT NOTES * =============== @@ -44,7 +45,7 @@ * request processing, and produces copious amounts of logging data. This will * negatively affect server performance. * - * Do NOT use mod_example as the basis for your own code. This module + * Do NOT use mod_example_hooks as the basis for your own code. This module * implements every callback hook offered by the Apache core, and your * module will almost certainly not have to implement this much. If you * want a simple module skeleton to start development, use apxs -g. @@ -128,7 +129,7 @@ static const char *trace = NULL; * Declare ourselves so the configuration routines can find and know us. * We'll fill it in at the end of the module. */ -module AP_MODULE_DECLARE_DATA example_module; +module AP_MODULE_DECLARE_DATA example_hooks_module; /*--------------------------------------------------------------------------*/ /* */ @@ -279,7 +280,7 @@ module AP_MODULE_DECLARE_DATA example_module; */ static x_cfg *our_dconfig(const request_rec *r) { - return (x_cfg *) ap_get_module_config(r->per_dir_config, &example_module); + return (x_cfg *) ap_get_module_config(r->per_dir_config, &example_hooks_module); } /* @@ -293,7 +294,7 @@ static x_cfg *our_dconfig(const request_rec *r) */ static x_cfg *our_sconfig(const server_rec *s) { - return (x_cfg *) ap_get_module_config(s->module_config, &example_module); + return (x_cfg *) ap_get_module_config(s->module_config, &example_hooks_module); } /* @@ -301,7 +302,7 @@ static x_cfg *our_sconfig(const server_rec *s) */ static x_cfg *our_rconfig(const request_rec *r) { - return (x_cfg *) ap_get_module_config(r->request_config, &example_module); + return (x_cfg *) ap_get_module_config(r->request_config, &example_hooks_module); } #endif /* if 0 */ @@ -310,7 +311,7 @@ static x_cfg *our_rconfig(const request_rec *r) */ static x_cfg *our_cconfig(const conn_rec *c) { - return (x_cfg *) ap_get_module_config(c->conn_config, &example_module); + return (x_cfg *) ap_get_module_config(c->conn_config, &example_hooks_module); } /* @@ -386,7 +387,7 @@ static void trace_startup(apr_pool_t *p, server_rec *s, x_cfg *mconfig, * This utility route traces the hooks called as a request is handled. * It takes the current request as argument */ -#define TRACE_NOTE "example-trace" +#define TRACE_NOTE "example-hooks-trace" static void trace_request(const request_rec *r, const char *note) { @@ -432,7 +433,7 @@ static void trace_request(const request_rec *r, const char *note) * the connection and its pool to itself entirely, and in * multi-threaded mode each connection will have its own pool. */ -#define CONN_NOTE "example-connection" +#define CONN_NOTE "example-hooks-connection" static void trace_connection(conn_rec *c, const char *note) { @@ -983,7 +984,7 @@ static int x_handler(request_rec *r) trace_request(r, note); /* If it's not for us, get out as soon as possible. */ - if (strcmp(r->handler, "example-handler")) { + if (strcmp(r->handler, "example-hooks-handler")) { return DECLINED; } @@ -1007,11 +1008,11 @@ static int x_handler(request_rec *r) ap_rputs(DOCTYPE_HTML_3_2, r); ap_rputs("\n", r); ap_rputs(" \n", r); - ap_rputs(" mod_example Module Content-Handler Output\n", r); + ap_rputs(" <TITLE>mod_example_hooks Module Content-Handler Output\n", r); ap_rputs(" \n", r); ap_rputs(" \n", r); ap_rputs(" \n", r); - ap_rputs("

mod_example Module Content-Handler Output\n", r); + ap_rputs("

mod_example_hooks Module Content-Handler Output\n", r); ap_rputs("

\n", r); ap_rputs("

\n", r); ap_rprintf(r, " Apache HTTP Server version: \"%s\"\n", @@ -1505,7 +1506,7 @@ static const command_rec x_cmds[] = * Module definition for configuration. If a particular callback is not * needed, replace its routine name below with the word NULL. */ -module AP_MODULE_DECLARE_DATA example_module = +module AP_MODULE_DECLARE_DATA example_hooks_module = { STANDARD20_MODULE_STUFF, x_create_dir_config, /* per-directory config creator */ diff --git a/modules/experimental/mod_example.dsp b/modules/examples/mod_example_hooks.dsp similarity index 100% rename from modules/experimental/mod_example.dsp rename to modules/examples/mod_example_hooks.dsp diff --git a/modules/examples/mod_example_ipc.c b/modules/examples/mod_example_ipc.c new file mode 100644 index 0000000000..7340cb7b0f --- /dev/null +++ b/modules/examples/mod_example_ipc.c @@ -0,0 +1,385 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * mod_example_ipc -- Apache sample module + * + * This module illustrates the use in an Apache 2.x module of the Interprocess + * Communications routines that come with APR. It is example code, and not meant + * to be used in a production server. + * + * To play with this sample module first compile it into a DSO file and install + * it into Apache's modules directory by running: + * + * $ /path/to/apache2/bin/apxs -c -i mod_example_ipc.c + * + * Then activate it in Apache's httpd.conf file for instance for the URL + * /example_ipc in as follows: + * + * # httpd.conf + * LoadModule example_ipc_module modules/mod_example_ipc.so + * + * SetHandler example_ipc + * + * + * Then restart Apache via + * + * $ /path/to/apache2/bin/apachectl restart + * + * The module allocates a counter in shared memory, which is incremented by the + * request handler under a mutex. After installation, activate the handler by + * hitting the URL configured above with ab at various concurrency levels to see + * how mutex contention affects server performance. + */ + +#include "apr.h" +#include "apr_strings.h" + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "ap_config.h" + +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) +#include "unixd.h" +#define MOD_EXIPC_SET_MUTEX_PERMS /* XXX Apache should define something */ +#endif + +#if APR_HAVE_SYS_TYPES_H +#include +#endif +#if APR_HAVE_UNISTD_H +#include +#endif + +#define HTML_HEADER "\n\nMod_example_IPC Status Page " \ + "\n\n\n

Mod_example_IPC Status

\n" +#define HTML_FOOTER "\n\n" + +/* Number of microseconds to camp out on the mutex */ +#define CAMPOUT 10 +/* Maximum number of times we camp out before giving up */ +#define MAXCAMP 10 +/* Number of microseconds the handler sits on the lock once acquired. */ +#define SLEEPYTIME 1000 + +apr_shm_t *exipc_shm; /* Pointer to shared memory block */ +char *shmfilename; /* Shared memory file name, used on some systems */ +apr_global_mutex_t *exipc_mutex; /* Lock around shared memory segment access */ +char *mutexfilename; /* Lock file name, used on some systems */ + +/* Data structure for shared memory block */ +typedef struct exipc_data { + apr_uint64_t counter; + /* More fields if necessary */ +} exipc_data; + +/* + * Clean up the shared memory block. This function is registered as + * cleanup function for the configuration pool, which gets called + * on restarts. It assures that the new children will not talk to a stale + * shared memory segment. + */ +static apr_status_t shm_cleanup_wrapper(void *unused) { + if (exipc_shm) + return apr_shm_destroy(exipc_shm); + return OK; +} + + +/* + * This routine is called in the parent, so we'll set up the shared + * memory segment and mutex here. + */ + +static int exipc_post_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + void *data; /* These two help ensure that we only init once. */ + const char *userdata_key; + apr_status_t rs; + exipc_data *base; + const char *tempdir; + + + /* + * The following checks if this routine has been called before. + * This is necessary because the parent process gets initialized + * a couple of times as the server starts up, and we don't want + * to create any more mutexes and shared memory segments than + * we're actually going to use. + * + * The key needs to be unique for the entire web server, so put + * the module name in it. + */ + userdata_key = "example_ipc_init_module"; + apr_pool_userdata_get(&data, userdata_key, s->process->pool); + if (!data) { + /* + * If no data was found for our key, this must be the first + * time the module is initialized. Put some data under that + * key and return. + */ + apr_pool_userdata_set((const void *) 1, userdata_key, + apr_pool_cleanup_null, s->process->pool); + return OK; + } /* Kilroy was here */ + + /* + * Both the shared memory and mutex allocation routines take a + * file name. Depending on system-specific implementation of these + * routines, that file may or may not actually be created. We'd + * like to store those files in the operating system's designated + * temporary directory, which APR can point us to. + */ + rs = apr_temp_dir_get(&tempdir, pconf); + if (APR_SUCCESS != rs) { + ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, + "Failed to find temporary directory"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* Create the shared memory segment */ + + /* + * Create a unique filename using our pid. This information is + * stashed in the global variable so the children inherit it. + */ + shmfilename = apr_psprintf(pconf, "%s/httpd_shm.%ld", tempdir, + (long int)getpid()); + + /* Now create that segment */ + rs = apr_shm_create(&exipc_shm, sizeof(exipc_data), + (const char *) shmfilename, pconf); + if (APR_SUCCESS != rs) { + ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, + "Failed to create shared memory segment on file %s", + shmfilename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* Created it, now let's zero it out */ + base = (exipc_data *)apr_shm_baseaddr_get(exipc_shm); + base->counter = 0; + + /* Create global mutex */ + + /* + * Create another unique filename to lock upon. Note that + * depending on OS and locking mechanism of choice, the file + * may or may not be actually created. + */ + mutexfilename = apr_psprintf(pconf, "%s/httpd_mutex.%ld", tempdir, + (long int) getpid()); + + rs = apr_global_mutex_create(&exipc_mutex, (const char *) mutexfilename, + APR_LOCK_DEFAULT, pconf); + if (APR_SUCCESS != rs) { + ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, + "Failed to create mutex on file %s", + mutexfilename); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* + * After the mutex is created, its permissions need to be adjusted + * on unix platforms so that the child processe can acquire + * it. This call takes care of that. The preprocessor define was + * set up early in this source file since Apache doesn't provide + * it. + */ +#ifdef MOD_EXIPC_SET_MUTEX_PERMS + rs = unixd_set_global_mutex_perms(exipc_mutex); + if (APR_SUCCESS != rs) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s, + "Parent could not set permissions on Example IPC " + "mutex: check User and Group directives"); + return HTTP_INTERNAL_SERVER_ERROR; + } +#endif /* MOD_EXIPC_SET_MUTEX_PERMS */ + + /* + * Destroy the shm segment when the configuration pool gets destroyed. This + * happens on server restarts. The parent will then (above) allocate a new + * shm segment that the new children will bind to. + */ + apr_pool_cleanup_register(pconf, NULL, shm_cleanup_wrapper, + apr_pool_cleanup_null); + return OK; +} + +/* + * This routine gets called when a child inits. We use it to attach + * to the shared memory segment, and reinitialize the mutex. + */ + +static void exipc_child_init(apr_pool_t *p, server_rec *s) +{ + apr_status_t rs; + + /* + * Re-open the mutex for the child. Note we're reusing + * the mutex pointer global here. + */ + rs = apr_global_mutex_child_init(&exipc_mutex, + (const char *) mutexfilename, + p); + if (APR_SUCCESS != rs) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rs, s, + "Failed to reopen mutex on file %s", + shmfilename); + /* There's really nothing else we can do here, since This + * routine doesn't return a status. If this ever goes wrong, + * it will turn Apache into a fork bomb. Let's hope it never + * will. + */ + exit(1); /* Ugly, but what else? */ + } +} + +/* The sample content handler */ +static int exipc_handler(request_rec *r) +{ + int gotlock = 0; + int camped; + apr_time_t startcamp; + apr_int64_t timecamped; + apr_status_t rs; + exipc_data *base; + + if (strcmp(r->handler, "example_ipc")) { + return DECLINED; + } + + /* + * The main function of the handler, aside from sending the + * status page to the client, is to increment the counter in + * the shared memory segment. This action needs to be mutexed + * out using the global mutex. + */ + + /* + * First, acquire the lock. This code is a lot more involved than + * it usually needs to be, because the process based trylock + * routine is not implemented on unix platforms. I left it in to + * show how it would work if trylock worked, and for situations + * and platforms where trylock works. + */ + for (camped = 0, timecamped = 0; camped < MAXCAMP; camped++) { + rs = apr_global_mutex_trylock(exipc_mutex); + if (APR_STATUS_IS_EBUSY(rs)) { + apr_sleep(CAMPOUT); + } else if (APR_SUCCESS == rs) { + gotlock = 1; + break; /* Get out of the loop */ + } else if (APR_STATUS_IS_ENOTIMPL(rs)) { + /* If it's not implemented, just hang in the mutex. */ + startcamp = apr_time_now(); + rs = apr_global_mutex_lock(exipc_mutex); + timecamped = (apr_int64_t) (apr_time_now() - startcamp); + if (APR_SUCCESS == rs) { + gotlock = 1; + break; /* Out of the loop */ + } else { + /* Some error, log and bail */ + ap_log_error(APLOG_MARK, APLOG_ERR, rs, r->server, + "Child %ld failed to acquire lock", + (long int)getpid()); + break; /* Out of the loop without having the lock */ + } + } else { + /* Some other error, log and bail */ + ap_log_error(APLOG_MARK, APLOG_ERR, rs, r->server, + "Child %ld failed to try and acquire lock", + (long int)getpid()); + break; /* Out of the loop without having the lock */ + + } + /* + * The only way to get to this point is if the trylock worked + * and returned BUSY. So, bump the time and try again + */ + timecamped += CAMPOUT; + ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_NOTICE, + 0, r->server, "Child %ld camping out on mutex for %d " + "microseconds", + (long int) getpid(), timecamped); + } /* Lock acquisition loop */ + + /* Sleep for a millisecond to make it a little harder for + * httpd children to acquire the lock. + */ + apr_sleep(SLEEPYTIME); + + r->content_type = "text/html"; + + if (!r->header_only) { + ap_rputs(HTML_HEADER, r); + if (gotlock) { + /* Increment the counter */ + base = (exipc_data *)apr_shm_baseaddr_get(exipc_shm); + base->counter++; + /* Send a page with our pid and the new value of the counter. */ + ap_rprintf(r, "

Lock acquired after %ld microseoncds.

\n", + (long int) timecamped); + ap_rputs("\n", r); + ap_rprintf(r, "\n", + (int) getpid()); + ap_rprintf(r, "\n", + (unsigned int)base->counter); + ap_rputs("
Child pid:%d
Counter:%u
\n", r); + } else { + /* + * Send a page saying that we couldn't get the lock. Don't say + * what the counter is, because without the lock the value could + * race. + */ + ap_rprintf(r, "

Child %d failed to acquire lock " + "after camping out for %d microseconds.

\n", + (int) getpid(), (int) timecamped); + } + ap_rputs(HTML_FOOTER, r); + } /* r->header_only */ + + /* Release the lock */ + if (gotlock) + rs = apr_global_mutex_unlock(exipc_mutex); + /* Swallowing the result because what are we going to do with it at + * this stage? + */ + + return OK; +} + +static void exipc_register_hooks(apr_pool_t *p) +{ + ap_hook_post_config(exipc_post_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(exipc_child_init, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_handler(exipc_handler, NULL, NULL, APR_HOOK_MIDDLE); +} + +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA example_ipc_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + exipc_register_hooks /* register hooks */ +}; + diff --git a/modules/experimental/NWGNUmakefile b/modules/experimental/NWGNUmakefile index 20927ee258..f0d539679c 100644 --- a/modules/experimental/NWGNUmakefile +++ b/modules/experimental/NWGNUmakefile @@ -160,9 +160,6 @@ XDCDATA = # it twice to allow it parent NWGNUmakefile to work properly. If another # submakefile is added, the extra reference to example.nlm should be removed. TARGET_nlm = \ - $(OBJDIR)/example.nlm \ - $(OBJDIR)/case_flt.nlm \ - $(OBJDIR)/case_flt_in.nlm \ $(OBJDIR)/substitute.nlm \ $(EOLIST) diff --git a/modules/experimental/config.m4 b/modules/experimental/config.m4 index 5ce1d7c93d..dd708f3eba 100644 --- a/modules/experimental/config.m4 +++ b/modules/experimental/config.m4 @@ -1,9 +1,6 @@ APACHE_MODPATH_INIT(experimental) -APACHE_MODULE(example, example and demo module, , , no) -APACHE_MODULE(case_filter, example uppercase conversion filter, , , no) -APACHE_MODULE(case_filter_in, example uppercase conversion input filter, , , no) APACHE_MODULE(substitute, response content rewrite-like filtering, , , most) APACHE_MODPATH_FINISH -- 2.40.0