Re: Sample code for IPC in modules
Hi Mark, Thanks for your observations. On May 4, 2004, at 7:18 PM, mark wrote: Your attach logic should work, however it raises privilege issues because the children run as a different user (nobody or www, etc) the than the process running the create (root). I had problems when I was doing it that way, worked I have to admit I hadn't tested as root, and it does exhibit permission problems on linux and darwin as well. Omitting the attach solves that problem, and I also got reacquainted with unixd_set_global_mutex_perms(). So, both of those are working now. 2) Dettach is never needed. However, depending on desired results, it is usually desireable to perform a destroy when a HUP signal is sent, so that it gets created fresh by post_config I've run into the strange errors under high load where newly forked children startup thinking they are attached to the inherited shm seg, but are in fact attached to some anonymous new segment. No error is produced, but obviously it's a catastrophic situation. Yeah, that would be Bad. However, how does one hook into the SIGHUP handler? AFAIK, httpd has its own signal handlers that do stuff like restarts and graceful, and if I registered another handler, I would overrule the one that httpd sets. Or is there a provision for a chain of signal handlers? I put the new version at http://apache.org/~sctemme/mod_example_ipc.c to save on e-mail bandwidth. Thanks again, S. -- [EMAIL PROTECTED] http://www.temme.net/sander/ PGP FP: 51B4 8727 466A 0BC3 69F4 B7B8 B2BE BC40 1529 24AF smime.p7s Description: S/MIME cryptographic signature
Re: Sample code for IPC in modules
I put the new version at http://apache.org/~sctemme/mod_example_ipc.c to save on e-mail bandwidth. if you're interested in this kind of thing, I've wrapped up mod_example_ipc in an Apache-Test tarball: http://perl.apache.org/~geoff/mod_example-ipc.tar.gz for no particular reason except that I know you were at my apachecon talk on Apache-Test but I didn't cover C module integration at all. fwiw. --Geoff
Re: Sample code for IPC in modules
(see note on hup cleanup below) On May 5, 2004, at 2:51 AM, Sander Temme wrote: Hi Mark, Thanks for your observations. On May 4, 2004, at 7:18 PM, mark wrote: 2) Dettach is never needed. However, depending on desired results, it is usually desireable to perform a destroy when a HUP signal is sent, so that it gets created fresh by post_config I've run into the strange errors under high load where newly forked children startup thinking they are attached to the inherited shm seg, but are in fact attached to some anonymous new segment. No error is produced, but obviously it's a catastrophic situation. Yeah, that would be Bad. However, how does one hook into the SIGHUP handler? AFAIK, httpd has its own signal handlers that do stuff like restarts and graceful, and if I registered another handler, I would overrule the one that httpd sets. Or is there a provision for a chain of signal handlers? You don't really need to worry about the SIGHUP handler, just tie a cleanup function to the pool used to create it in post_config. This will be the process pool of the parent, and its cleanups get run after all the children exit on a restart. It works for me. static apr_status_t shm_cleanup_wrapper(void *unused) { int rv; if (shm_seg) rv = apr_shm_destroy(shm_seg); else rv = APR_EGENERAL; return rv; } then in post_config: apr_pool_cleanup_register(pool, NULL, shm_cleanup_wrapper, apr_pool_cleanup_null); ... where pool is the first parameter to post_config (and used to create shmseg); I put the new version at http://apache.org/~sctemme/mod_example_ipc.c to save on e-mail bandwidth. Thanks again, S. -- [EMAIL PROTECTED] http://www.temme.net/sander/ PGP FP: 51B4 8727 466A 0BC3 69F4 B7B8 B2BE BC40 1529 24AF
Sample code for IPC in modules
Hi all, Following some questions on the apache-modules list, I whipped up a quick module for Apache 2.0 to hopefully demonstrate how it's done. I'm including the module code below: please tell me whether I'm smoking crack before I post this on apache-modules. Thanks for your thoughts, Sander /* ** mod_example_ipc.c -- Apache sample example_ipc module ** [Autogenerated via ``apxs -n example_ipc -g''] ** ** To play with this sample module first compile it into a ** DSO file and install it into Apache's modules directory ** by running: ** **$ 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 **Location /example_ipc **SetHandler example_ipc **/Location ** ** Then after restarting Apache via ** **$ apachectl restart ** ** The module allocates a counter in shared memory, which is incremented ** by the request handler under a mutex. After installation, hit the server ** with ab at various concurrency levels to see how mutex contention affects ** server performance. */ #include sys/types.h #include unistd.h #include httpd.h #include http_config.h #include http_log.h #include http_protocol.h #include ap_config.h #include apr_strings.h #define HTML_HEADER html\nhead\ntitleMod_example_IPC Status Page \ /title\n/head\nbody\nh1Mod_example_IPC Status/h1\n #define HTML_FOOTER /body\n/html\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 apr_shm_t *exipc_shm; char *shmfilename; apr_global_mutex_t *exipc_mutex; char *mutexfilename; typedef struct exipc_data { apr_uint64_t counter; /* More fields if necessary */ } exipc_data; /* * 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 = example_ipc_init_module; apr_status_t rs; exipc_data *base; /* * 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. */ apr_pool_userdata_get(data, userdata_key, s-process-pool); if (!data) { apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, s-process-pool); return OK; } /* Kilroy was here */ /* 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. * TODO get the location from the environment $TMPDIR or somesuch. */ shmfilename = apr_psprintf(pconf, /tmp/httpd_shm.%ld, (long int)getpid()); /* Now create that segment */ rs = apr_shm_create(exipc_shm, sizeof(exipc_data), (const char *) shmfilename, pconf); if (rs != APR_SUCCESS) { 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, /tmp/httpd_mutex.%ld, (long int) getpid()); rs = apr_global_mutex_create(exipc_mutex, (const char *) mutexfilename, APR_LOCK_DEFAULT, pconf); if (rs != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, Failed to create mutex on file %s, mutexfilename); return HTTP_INTERNAL_SERVER_ERROR; } return OK; } /* * This routine gets called when a child exits. It detaches from the * shared memory segment. (is this necessary?) */ static apr_status_t exipc_child_exit(void *data) { apr_status_t rs; rs = apr_shm_detach(exipc_shm); return rs; } /* * 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; /* * Attach to the shared memory segment. Note that we're * reusing the global
Re: Sample code for IPC in modules
On May 4, 2004, at 8:49 PM, Sander Temme wrote: Hi all, Following some questions on the apache-modules list, I whipped up a quick module for Apache 2.0 to hopefully demonstrate how it's done. I'm including the module code below: please tell me whether I'm smoking crack before I post this on apache-modules. Thanks for your thoughts, A few notes, based on my experience using shm in 2.0 and observations of mod_auth_digest's and mod_ssl's implementation. 1) No attach logic is needed provided you keep the base address from apr_shm_create in a global var. It will get inherited when the children are forked. I separate shm handling out into a separate file that is linked in. It declares a static global base, and provides accessor functions to make that work cleanly. Your attach logic should work, however it raises privilege issues because the children run as a different user (nobody or www, etc) the than the process running the create (root). I had problems when I was doing it that way, worked ok on freebsd and linux, but had strange behaviour on solaris. Attach is primarily designed to be used in cases where a totally separate process wants access to a piece of shared memory, not a forked one. 2) Dettach is never needed. However, depending on desired results, it is usually desireable to perform a destroy when a HUP signal is sent, so that it gets created fresh by post_config I've run into the strange errors under high load where newly forked children startup thinking they are attached to the inherited shm seg, but are in fact attached to some anonymous new segment. No error is produced, but obviously it's a catastrophic situation. Sander /* ** mod_example_ipc.c -- Apache sample example_ipc module ** [Autogenerated via ``apxs -n example_ipc -g''] ** ** To play with this sample module first compile it into a ** DSO file and install it into Apache's modules directory ** by running: ** **$ 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 **Location /example_ipc **SetHandler example_ipc **/Location ** ** Then after restarting Apache via ** **$ apachectl restart ** ** The module allocates a counter in shared memory, which is incremented ** by the request handler under a mutex. After installation, hit the server ** with ab at various concurrency levels to see how mutex contention affects ** server performance. */ #include sys/types.h #include unistd.h #include httpd.h #include http_config.h #include http_log.h #include http_protocol.h #include ap_config.h #include apr_strings.h #define HTML_HEADER html\nhead\ntitleMod_example_IPC Status Page \ /title\n/head\nbody\nh1Mod_example_IPC Status/h1\n #define HTML_FOOTER /body\n/html\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 apr_shm_t *exipc_shm; char *shmfilename; apr_global_mutex_t *exipc_mutex; char *mutexfilename; typedef struct exipc_data { apr_uint64_t counter; /* More fields if necessary */ } exipc_data; /* * 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 = example_ipc_init_module; apr_status_t rs; exipc_data *base; /* * 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. */ apr_pool_userdata_get(data, userdata_key, s-process-pool); if (!data) { apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, s-process-pool); return OK; } /* Kilroy was here */ /* 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. * TODO get the location from the environment $TMPDIR or somesuch. */ shmfilename = apr_psprintf(pconf, /tmp/httpd_shm.%ld, (long int)getpid()); /* Now create that segment */ rs = apr_shm_create(exipc_shm, sizeof(exipc_data), (const char *) shmfilename, pconf); if (rs != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, Failed to create shared memory segment on file %s, shmfilename); return HTTP_INTERNAL_SERVER_ERROR; }