On Wed, 2006-08-30 at 10:37 -0400, Brian Akins wrote:
> With all the talk of a "generic scoreboard," here's something I whipped
> up that allows any other module to have some amount of memory per
> "worker slot." We have a different module in-house at CNN which does
> something similar. This one is a little rough around the edges, but
> gives an idea of what I was thinking about doing.
Nice stuff but I am not sure that having shared memory per slot scales
when having a lot of entries, but that makes sure that one
process/thread won't overwrite another one slot.
I will try to use memory providers of httpd-scoreboard to provide the
memory to your module.
Cheers
Jean-Frederic
>
>
> plain text document attachment (mod_slotmem.h)
> #ifndef __MOD_slotmem__
> #define __MOD_slotmem__
>
> typedef struct ap_slotmem_t ap_slotmem_t;
>
> typedef apr_status_t ap_slotmem_callback_fn_t(void* mem, void *data,
> apr_pool_t *pool);
>
> AP_DECLARE(apr_status_t)ap_slotmem_do(ap_slotmem_t *s,
> ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool);
>
> AP_DECLARE(apr_status_t) ap_slotmem_create(ap_slotmem_t **new, const char
> *name, apr_size_t item_size, apr_pool_t *pool);
>
> AP_DECLARE(apr_status_t) ap_slotmem_mem(ap_slotmem_t *s, conn_rec *c,
> void**mem);
>
> #endif
> plain text document attachment (mod_slotmem.c)
> #include "httpd.h"
> #include "http_config.h"
> #include "http_protocol.h"
> #include "http_connection.h"
> #include "ap_config.h"
> #include "http_log.h"
> #include "scoreboard.h"
> #include "apr_strings.h"
> #include "apr_shm.h"
> #include "ap_mpm.h"
>
> #include <sys/types.h>
> #include <unistd.h>
>
> #include "mod_status.h"
> #include "mod_slotmem.h"
>
> module AP_MODULE_DECLARE_DATA slotmem_module;
>
> static int server_limit = 0;
> static int thread_limit = 0;
> static int total_limit = 0;
>
> static apr_array_header_t *slotmem_array = NULL;
>
> struct ap_slotmem_t {
> apr_pool_t *pool;
> const char *name;
> apr_shm_t *shm;
> void *mem;
> apr_size_t item_size; /*size of each item*/
> apr_size_t total_size;
> };
>
>
> AP_DECLARE(apr_status_t)ap_slotmem_do(ap_slotmem_t *s,
> ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool) {
> apr_status_t rv = APR_SUCCESS;
> int i;
> void *mem;
>
> for(i = 0; i < total_limit; i++) {
> mem = s->mem + (i * s->item_size);
> if((rv = func(mem, data, pool)) != APR_SUCCESS) {
> return rv;
> }
> }
> return rv;
> }
>
> AP_DECLARE(apr_status_t) ap_slotmem_create(ap_slotmem_t **n, const char
> *name, apr_size_t item_size, apr_pool_t *pool) {
> ap_slotmem_t *s, **new;
>
> s = apr_pcalloc(pool, sizeof(ap_slotmem_t));
>
> s->pool = pool;
> s->name = apr_pstrdup(pool, name);
> s->item_size = item_size;
>
> new = (ap_slotmem_t **) apr_array_push(slotmem_array);
> (*new) = (ap_slotmem_t *) s;
>
> *n = s;
>
> return APR_SUCCESS;
> }
>
> AP_DECLARE(apr_status_t) ap_slotmem_mem(ap_slotmem_t *s, conn_rec *c, void
> **mem) {
> /*this should work for all mpm's*/
> void *d = s->mem + (c->id * s->item_size);
>
> *mem = d;
> if(!d) {
> ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
> "ap_slotmem_mem: d is NULL, %ld, %p",
> c->id, s->mem
> );
> return APR_EGENERAL;
> }
> return APR_SUCCESS;
> }
>
> static int slotmem_status(request_rec *r, int flags)
> {
> int i;
> ap_slotmem_t *sb, **list;
>
> if (!(flags & AP_STATUS_SHORT)) {
> ap_rputs("<hr /><b>slotmems</b>\n", r);
> ap_rputs("<table border=1><tr><td><b>Name</b></td><td><b>Item
> Size</b></td><td><b>Total Size</b></td></tr>\n", r);
> }
> list = (ap_slotmem_t **)slotmem_array->elts;
> for(i = 0; i < slotmem_array->nelts; i++) {
> sb = list[i];
> if (!(flags & AP_STATUS_SHORT)) {
> ap_rprintf(r,
> "<tr><td>%s</td><td>%"APR_SIZE_T_FMT"</td><td>%"APR_SIZE_T_FMT"</td></tr>\n",
> sb->name, sb->item_size, sb->total_size);
> } else {
> ap_rprintf(r, "slotmem: %s %"APR_SIZE_T_FMT"%"APR_SIZE_T_FMT"\n",
> sb->name, sb->item_size, sb->total_size);
> }
> }
>
> if (!(flags & AP_STATUS_SHORT)) {
> ap_rputs("</table>\n", r);
> }
> return OK;
> }
>
> static int post_config(apr_pool_t *p, apr_pool_t * plog, apr_pool_t * ptemp,
> server_rec *s)
> {
>
> apr_size_t amt;
> apr_time_t now;
> pid_t pid;
> char *file;
> ap_slotmem_t *sb, **list;
> int i;
> apr_status_t rv;
> const char *temp_dir;
> char *data = NULL;
>
> /*have we been here before? */
> apr_pool_userdata_get((void *) &data, __FILE__,
> s->process->pool);
>
> if (!data) {
> apr_pool_userdata_set((const void *) 1, __FILE__,
> apr_pool_cleanup_null, s->process->pool);
> return OK;
> }
>
> ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
> ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
> total_limit = thread_limit * server_limit;
>
> now = apr_time_now();
> pid = getpid();
> if ((rv = apr_temp_dir_get(&temp_dir, p)) != APR_SUCCESS) {
> ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
> "apr_temp_dir_get failed");
> return rv;
> }
>
> /*XXX: currently, this uses one shm per slotmem. We could try to pack
> them
> all into a few larger shm's*/
> list = (ap_slotmem_t **)slotmem_array->elts;
> for(i = 0; i < slotmem_array->nelts; i++) {
> sb = list[i];
> sb->total_size = amt = sb->item_size * total_limit;
>
> ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> "creating slotmem %d: %s : %"APR_SIZE_T_FMT" item size x
> %d total = %"APR_SIZE_T_FMT" total bytes",
> i, sb->name, sb->item_size, total_limit, amt);
>
> file = apr_psprintf(p, "%s/" __FILE__ ":%s:%" APR_PID_T_FMT ":%"
> APR_TIME_T_FMT"-%d",
> temp_dir, sb->name, pid, now, i);
> if ((rv =
> apr_shm_create(&sb->shm, amt, file,
> p)) != APR_SUCCESS) {
> ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
> __FILE__": apr_shm_create failed trying to allocate
> %"APR_SIZE_T_FMT" bytes: %s",
> amt, file);
> return rv;
> }
>
> if((sb->mem = apr_shm_baseaddr_get(sb->shm)) == NULL) {
> ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
> __FILE__": apr_shm_baseaddr_get failed for %s",
> sb->name);
> return APR_EGENERAL;
> }
>
> memset(sb->mem, 0, amt);
> }
>
> return OK;
> }
>
> static void register_hooks(apr_pool_t * p)
> {
> ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_REALLY_LAST);
> slotmem_array = apr_array_make(p, 10, sizeof(ap_slotmem_t *));
> APR_OPTIONAL_HOOK(ap, status_hook, slotmem_status, NULL, NULL,
> APR_HOOK_MIDDLE);
>
> }
>
> /* Dispatch list for API hooks */
> module AP_MODULE_DECLARE_DATA slotmem_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 */
> register_hooks /* register hooks */
> };