[svn:mod_parrot] r501 - in mod_parrot/trunk: include src

[email protected] Sun, 23 Nov 2008 09:52:06 -0800 (PST)
Newsgroups perl.cvs.mod_parrot
Message-ID <[email protected]>
Author: jhorwitz
Date: Sun Nov 23 09:52:05 2008
New Revision: 501

Modified:
   mod_parrot/trunk/include/mod_parrot.h
   mod_parrot/trunk/src/context.c
   mod_parrot/trunk/src/mod_parrot.c

Log:
use connection ID to bind contexts to connections.  this guarantees all phases
of a request will use the same context/interpreter in a threaded MPM.


Modified: mod_parrot/trunk/include/mod_parrot.h
==============================================================================
--- mod_parrot/trunk/include/mod_parrot.h	(original)
+++ mod_parrot/trunk/include/mod_parrot.h	Sun Nov 23 09:52:05 2008
@@ -37,6 +37,7 @@
 #define MODPARROT_CTX_ISLOCKED(x) (x->locked == 1)
 #define MODPARROT_CTX_LOCK(x) (x->locked = 1)
 #define MODPARROT_CTX_UNLOCK(x) (x->locked = 0)
+#define MP_CTX_ANY (-1)
 
 /* we need to move things around to avoid this */
 #include "modparrot_config.h"
@@ -57,6 +58,7 @@
     conn_rec *c;
     void *csd;
     int module_index;
+    int pool_index;
 };
 typedef struct modparrot_context modparrot_context;
 
@@ -75,7 +77,7 @@
 Parrot_PMC get_sub_pmc(Parrot_Interp , char *, char *);
 apr_array_header_t *mp_ctx_pool_init(apr_pool_t *, Parrot_Interp, int);
 void mp_ctx_pool_destroy(apr_array_header_t *);
-modparrot_context *reserve_ctx(apr_array_header_t *);
+modparrot_context *reserve_ctx(apr_array_header_t *, int index);
 void release_ctx(modparrot_context *);
 modparrot_context *get_interp_ctx(Parrot_Interp);
 void set_interp_ctx(Parrot_Interp, modparrot_context *);

Modified: mod_parrot/trunk/src/context.c
==============================================================================
--- mod_parrot/trunk/src/context.c	(original)
+++ mod_parrot/trunk/src/context.c	Sun Nov 23 09:52:05 2008
@@ -53,6 +53,7 @@
         ctx = (*(modparrot_context **)apr_array_push(ctx_pool) =
             (modparrot_context *)apr_pcalloc(p, sizeof(modparrot_context)));
         ctx->parent_interp = parent_interp;
+        ctx->pool_index = -1;
     }
 
 #ifdef MPM_IS_THREADED
@@ -91,38 +92,52 @@
 }
 
 /* finds and reserves a context for use by a handler */
-modparrot_context *reserve_ctx(apr_array_header_t *ctx_pool)
+modparrot_context *reserve_ctx(apr_array_header_t *ctx_pool, int index)
 {
 #ifdef MPM_IS_THREADED
     int i;
 #endif /* MPM_IS_THREADED */
-    modparrot_context *ctx;
+    modparrot_context *ctxp = (modparrot_context *)NULL;
 
     if (!ctx_pool) return NULL;
 #ifdef MPM_IS_THREADED
     apr_thread_mutex_lock(ctx_pool_mutex);
-    for (i = 0; i < ctx_pool->nelts; i++) {
-        ctx = ((modparrot_context **)ctx_pool->elts)[i];
-        if (MODPARROT_CTX_ISLOCKED(ctx)) continue;
-        MODPARROT_CTX_LOCK(ctx);
-        apr_thread_mutex_unlock(ctx_pool_mutex);
-        return(ctx);
+    if (index == MP_CTX_ANY) {
+        for (i = 0; i < ctx_pool->nelts; i++) {
+            modparrot_context *c;
+            c = ((modparrot_context **)ctx_pool->elts)[i];
+            if (MODPARROT_CTX_ISLOCKED(c)) continue;
+            MODPARROT_CTX_LOCK(c);
+            ctxp = c;
+            ctxp->pool_index = i;
+            break;
+        }
+    }
+    else {
+        if (ctxp = ((modparrot_context **)ctx_pool->elts)[index]) {
+            if (MODPARROT_CTX_ISLOCKED(ctxp)) {
+                ctxp = NULL;
+            }
+            else {
+                MODPARROT_CTX_LOCK(ctxp);
+                ctxp->pool_index = index;
+            }
+        }
     }
     apr_thread_mutex_unlock(ctx_pool_mutex);
-
-    /* XXX should wait for free context here instead of bailing */
-    return (modparrot_context *)NULL;
 #else /* MPM_IS_THREADED */
-    ctx = ((modparrot_context **)ctx_pool->elts)[0];
-    MODPARROT_CTX_LOCK(ctx); /* no threads here, just for consistency */
-    return ctx;
+    ctxp = ((modparrot_context **)ctx_pool->elts)[0];
+    ctxp->pool_index = 0;
+    MODPARROT_CTX_LOCK(ctxp); /* no threads here, just for consistency */
 #endif /* MPM_IS_THREADED */
+    return(ctxp);
 }
 
 /* releases a context back into the pool of available contexts */
-void release_ctx(modparrot_context *ctx)
+void release_ctx(modparrot_context *ctxp)
 {
-    MODPARROT_CTX_UNLOCK(ctx);
+    ctxp->pool_index = -1;
+    MODPARROT_CTX_UNLOCK(ctxp);
 }
 
 void set_interp_ctx(Parrot_Interp interp, modparrot_context *ctx)

Modified: mod_parrot/trunk/src/mod_parrot.c
==============================================================================
--- mod_parrot/trunk/src/mod_parrot.c	(original)
+++ mod_parrot/trunk/src/mod_parrot.c	Sun Nov 23 09:52:05 2008
@@ -27,6 +27,7 @@
 #include "http_core.h"
 #include "http_connection.h"
 #include "http_main.h"
+#include "ap_mpm.h"
 
 #include "parrot/parrot.h"
 #include "parrot/embed.h"
@@ -40,6 +41,12 @@
 
 #define NEXT_HANDLER_MODULE(x) (mpcfg->handler_modules[x] ? ((module **)mpcfg->module_array->elts)[((int *)mpcfg->handler_modules[x]->elts)[++(ctxp->module_index)]] : NULL);
 
+#ifdef MPM_IS_THREADED
+#define CONN_INDEX(c) (c->id % max_threads)
+#else
+#define CONN_INDEX(c) MP_CTX_ANY
+#endif
+
 /* declare our module */
 extern module AP_MODULE_DECLARE_DATA parrot_module;
 
@@ -52,6 +59,17 @@
 /* have we started?  this can be global since it's written to at startup */
 int mp_is_started = 0;
 
+/* thread info */
+int hard_thread_limit, max_threads;
+
+/* maps connection ID to a context so we can maintain state between phases */
+int *conn_ctx;
+
+#ifdef MPM_IS_THREADED
+apr_thread_mutex_t *ctx_pool_mutex;
+apr_thread_mutex_t *conn_ctx_mutex;
+#endif /* MPM_IS_THREADED */
+
 void modparrot_load_file(Parrot_Interp interp, server_rec *s, const char *file)
 {
     int ret;
@@ -118,15 +136,29 @@
     return(interp);
 }
 
-static modparrot_context *init_ctx(server_rec *s)
+static modparrot_context *init_ctx(server_rec *s, conn_rec *c)
 {
     Parrot_Interp interp;
     modparrot_context *ctxp;
     modparrot_srv_config *cfg;
+    int conn_idx, ctx_idx;
 
     cfg = ap_get_module_config(s->module_config, &parrot_module);
 
-    if ((ctxp = reserve_ctx(cfg->ctx_pool))) {
+#ifdef MPM_IS_THREADED
+    if (c) {
+        conn_idx = c->id % max_threads;
+        ctx_idx = conn_ctx[conn_idx];
+    }
+    else {
+        conn_idx = -1; /* unused */
+        ctx_idx = MP_CTX_ANY;
+    }
+#else /* MPM_IS_THREADED */
+    ctx_idx = MP_CTX_ANY;
+#endif /* MPM_IS_THREADED */
+
+    if ((ctxp = reserve_ctx(cfg->ctx_pool, ctx_idx))) {
         if (!ctxp->interp) {
             if (!(interp = modparrot_init(ctxp, s))) {
                 MPLOG_ERROR(s,
@@ -139,6 +171,13 @@
             interp = ctxp->interp;
         }
 
+#ifdef MPM_IS_THREADED
+        /* if we're in a connection, remember this context for future phases */
+        if (c) {
+            conn_ctx[conn_idx] = ctxp->pool_index;
+        }
+#endif /* MPM_IS_THREADED */
+
         /* usually set s in a hook, but need it here for the config phase */
         ctxp->s = s;
     }
@@ -166,7 +205,7 @@
         }
     }
 
-    if ((ctxp = init_ctx(s))) {
+    if ((ctxp = init_ctx(s, NULL))) {
         mp_is_started = 1;
     }
     else {
@@ -242,7 +281,7 @@
     modparrot_context *ctxp;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(r->server))) {
+    if (!(ctxp = init_ctx(r->server, r->connection))) {
         MPLOG_ERROR(r->server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -261,7 +300,7 @@
     modparrot_context *ctxp;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(c->base_server))) {
+    if (!(ctxp = init_ctx(c->base_server, c))) {
         MPLOG_ERROR(c->base_server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -287,7 +326,7 @@
     int status, m;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(r->server))) {
+    if (!(ctxp = init_ctx(r->server, r->connection))) {
         MPLOG_ERROR(r->server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -304,7 +343,7 @@
 
     /* get HLL config */
     /* can't use NEXT_HANDLER_MODULE here since cleanup handlers are LIFO */
-    modp = ((module **)mpcfg->module_array->elts)[mpcfg->handler_modules[MP_HOOK_CLEANUP]->elts[ctxp->module_index]];
+    modp = ((module **)mpcfg->module_array->elts)[mpcfg->handler_modules[MP_HOOK_CLEANUP]->elts[m]];
     minfo = (modparrot_module_info *)modp->dynamic_load_handle;
     /* check for an actual cleanup metahandler sub */
     /* XXX we shouldn't really be using get_sub_pmc here... */
@@ -346,7 +385,7 @@
         Parrot_PMC sub; \
         int status; \
         /* initialize context */ \
-        if (!(ctxp = init_ctx(r->server))) { \
+        if (!(ctxp = init_ctx(r->server, r->connection))) { \
             MPLOG_ERROR(r->server, "context initialization failed"); \
             return HTTP_INTERNAL_SERVER_ERROR; \
         } \
@@ -410,7 +449,7 @@
     int status;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(c->base_server))) {
+    if (!(ctxp = init_ctx(c->base_server, c))) {
         MPLOG_ERROR(c->base_server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -447,7 +486,7 @@
     modparrot_context *ctxp;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(c->base_server))) {
+    if (!(ctxp = init_ctx(c->base_server, c))) {
         MPLOG_ERROR(c->base_server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -472,7 +511,7 @@
     int status;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(c->base_server))) {
+    if (!(ctxp = init_ctx(c->base_server, c))) {
         MPLOG_ERROR(c->base_server, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -509,7 +548,7 @@
     modparrot_context *ctxp;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(s))) {
+    if (!(ctxp = init_ctx(s, NULL))) {
         MPLOG_ERROR(s, "context initialization failed");
         return;
     }
@@ -517,6 +556,17 @@
     /* we're FIRST, so reset the module index */
     ctxp->module_index = -1;
 
+    /* query apache mpm for thread limits */
+#ifdef MPM_IS_THREADED
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &hard_thread_limit);
+    ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads);
+    /* an APR array is overkill for a static array, so alloc it ourselves */
+    conn_ctx = (int *)apr_pcalloc(p, sizeof(int) * max_threads);
+#else /* MPM_IS_THREADED */
+    hard_thread_limit = 1;
+    max_threads = 1;
+#endif /* MPM_IS_THREADED */
+
     /* clean up */
     release_ctx(ctxp);
 }
@@ -532,7 +582,7 @@
     int status;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(s))) {
+    if (!(ctxp = init_ctx(s, NULL))) {
         MPLOG_ERROR(s, "context initialization failed");
         return;
     }
@@ -567,7 +617,7 @@
     modparrot_context *ctxp;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(s))) {
+    if (!(ctxp = init_ctx(s, NULL))) {
         MPLOG_ERROR(s, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -593,7 +643,7 @@
     int status;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(s))) {
+    if (!(ctxp = init_ctx(s, NULL))) {
         MPLOG_ERROR(s, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -707,7 +757,7 @@
     int status;
 
     /* initialize context */
-    if (!(ctxp = init_ctx(s))) {
+    if (!(ctxp = init_ctx(s, NULL))) {
         MPLOG_ERROR(s, "context initialization failed");
         return HTTP_INTERNAL_SERVER_ERROR;
     }