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 */ > };