Re: Sample code for IPC in modules

2004-05-05 Thread Sander Temme
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

2004-05-05 Thread Geoffrey Young

 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

2004-05-05 Thread Mark Wolgemuth
(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

2004-05-04 Thread Sander Temme
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

2004-05-04 Thread mark
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;
}