In the slow process of reorganizing mod_rivet (and its components) in order to make it more tractable for a code refactoring I realized the way mod_rivet handle the Tcl Channels was suboptimal. With a prefork MPM a child process can handle only a request at a time, therefore there is no need for replicating the creation of the Tcl channel for each interpreter when virtual hosts require separate interpreters: Tcl channels are registered to an interpreter but are created independently and are destroyed when by calling Tcl_UnregisterChannel their reference count drops to 0

I will attach a patch which applied to the current trunk code makes mod_rivet create and manage a single channel. To be tested with virtual host private interpreters (SeparateVirtualInterps)

the apache benchmark program reports no errors (with a concurrency 20 and 500 requests)

Anyone with a multiple virtual hosts test system is kindly invited to try this patch, thanks

 -- Massimo
Index: src/apache-2/mod_rivet.c
===================================================================
--- src/apache-2/mod_rivet.c	(revision 1604559)
+++ src/apache-2/mod_rivet.c	(working copy)
@@ -88,10 +88,19 @@
 #define RIVET_TEMPLATE_CTYPE    "application/x-httpd-rivet"
 #define RIVET_TCLFILE_CTYPE     "application/x-rivet-tcl"
 
+/* 
+ * for some reason the max buffer size definition is not exported by Tcl 
+ * we steal and reproduce it here prepending the name with TCL
+ */
+
+#define TCL_MAX_CHANNEL_BUFFER_SIZE (1024*1024)
+
 static Tcl_Interp* Rivet_CreateTclInterp (server_rec* s);
 static void Rivet_CreateCache (server_rec *s, apr_pool_t *p);
 static apr_status_t Rivet_ChildExit(void *data);
 
+mod_rivet_globals* rivet_module_globals = NULL;
+
 /*
  * -- Rivet_chdir_file (const char* filename)
  * 
@@ -713,11 +722,10 @@
     ap_assert (interp != (Tcl_Interp *)NULL);
     Tcl_Preserve (interp);
 
-    /* Create TCL commands to deal with Apache's BUFFs. */
-    rsc->outchannel = apr_pcalloc (p, sizeof(Tcl_Channel));
-    *(rsc->outchannel) = Tcl_CreateChannel(&RivetChan, "apacheout", rsc, TCL_WRITABLE);
-    Tcl_SetStdChannel (*(rsc->outchannel), TCL_STDOUT);
+    /* We register the Tcl channel to the interpreter */
 
+    Tcl_RegisterChannel(interp, *(rsc->outchannel));
+
     /* Set up interpreter associated data */
 
     globals = apr_pcalloc (p, sizeof(rivet_interp_globals));
@@ -803,13 +811,6 @@
         exit(1);
     }
 
-    /* Set the output buffer size to the largest allowed value, so that we 
-     * won't send any result packets to the browser unless the Rivet
-     * programmer does a "flush stdout" or the page is completed.
-     */
-
-    Tcl_SetChannelBufferSize (*(rsc->outchannel), 1000000);
-    Tcl_RegisterChannel(interp, *(rsc->outchannel));
     Tcl_Release(interp);
 }
 
@@ -818,9 +819,11 @@
        server_rec *s)
 {
     rivet_server_conf *rsc = RIVET_SERVER_CONF( s->module_config );
-    rivet_panic_pool = pPool;
+    rivet_panic_pool       = pPool;
     rivet_panic_server_rec = s;
 
+    rivet_module_globals = apr_palloc(pPool,sizeof(mod_rivet_globals));
+    rivet_module_globals->rsc_p = rsc;
 #if RIVET_DISPLAY_VERSION
     ap_add_version_component(pPool, RIVET_PACKAGE_NAME"/"RIVET_VERSION);
 #else
@@ -829,15 +832,32 @@
 
     FILEDEBUGINFO;
 
+    /* we create and initialize a master (server) interpreter */
+
     rsc->server_interp = Rivet_CreateTclInterp(s) ; /* root interpreter */
 
+    /* Create TCL channel and store a pointer in the rivet_server_conf object */
+
+    rsc->outchannel    = apr_pcalloc (pPool, sizeof(Tcl_Channel));
+    *(rsc->outchannel) = Tcl_CreateChannel(&RivetChan, "apacheout", rivet_module_globals, TCL_WRITABLE);
+
+    /* The channel we have just created replaces Tcl's stdout */
+
+    Tcl_SetStdChannel (*(rsc->outchannel), TCL_STDOUT);
+
+    /* Set the output buffer size to the largest allowed value, so that we 
+     * won't send any result packets to the browser unless the Rivet
+     * programmer does a "flush stdout" or the page is completed.
+     */
+
+    Tcl_SetChannelBufferSize (*(rsc->outchannel), TCL_MAX_CHANNEL_BUFFER_SIZE);
+
     Rivet_PerInterpInit(s, rsc, pPool);
+
+    /* we create also the cache */
+
     Rivet_CreateCache(s,pPool);
 
-    /* we create and initialize a master (server) interpreter
-     * Rivet_InitTclStuff(s,pPool);
-     */
-
     if (rsc->rivet_server_init_script != NULL) {
         Tcl_Interp* interp = rsc->server_interp;
 
@@ -1059,6 +1079,7 @@
         }
 
         myrsc->outchannel = rsc->outchannel;
+
         /* This sets up slave interpreters for other virtual hosts. */
         if (sr != s) /* not the first one  */
         {
@@ -1278,6 +1299,7 @@
     rivet_panic_request_rec = r;
 
     rsc = Rivet_GetConf(r);
+    rivet_module_globals->rsc_p = rsc;
     interp = rsc->server_interp;
     globals = Tcl_GetAssocData(interp, "rivet", NULL);
 
Index: src/apache-2/mod_rivet.h
===================================================================
--- src/apache-2/mod_rivet.h	(revision 1600490)
+++ src/apache-2/mod_rivet.h	(working copy)
@@ -113,6 +113,14 @@
     server_rec*     srec;               /* pointer to the current server rec obj */
 } rivet_interp_globals;
 
+/* 
+ * we need also a place where to store module wide globals
+ */
+
+typedef struct _mod_rivet_globals {
+    rivet_server_conf* rsc_p;
+} mod_rivet_globals;
+
 int Rivet_ParseExecFile   (TclWebRequest *req, char *filename, int toplevel);
 int Rivet_ParseExecString (TclWebRequest* req, Tcl_Obj* inbuf);
 
@@ -125,12 +133,9 @@
 #undef ap_set_module_config
 #endif
 
-#define RIVET_SERVER_CONF(module) \
-	(rivet_server_conf *)ap_get_module_config(module, &rivet_module)
+#define RIVET_SERVER_CONF(module) (rivet_server_conf *)ap_get_module_config(module, &rivet_module)
+#define RIVET_NEW_CONF(p)         (rivet_server_conf *)apr_pcalloc(p, sizeof(rivet_server_conf))
 
-#define RIVET_NEW_CONF(p) \
-	(rivet_server_conf *)apr_pcalloc(p, sizeof(rivet_server_conf))
-
 Tcl_Obj* Rivet_BuildConfDictionary ( Tcl_Interp*        interp,
                                     rivet_server_conf*  rivet_conf);
 
Index: src/channel/rivetChannel.c
===================================================================
--- src/channel/rivetChannel.c	(revision 1600490)
+++ src/channel/rivetChannel.c	(working copy)
@@ -44,7 +44,9 @@
 outputproc(ClientData instancedata, CONST84 char *buf,
 	   int toWrite, int *errorCodePtr)
 {
-    rivet_server_conf *rsc = (rivet_server_conf *)instancedata;
+    mod_rivet_globals* rivet_module_globals = (mod_rivet_globals *)instancedata;
+
+    rivet_server_conf *rsc = rivet_module_globals->rsc_p;
     rivet_interp_globals *globals =
         Tcl_GetAssocData(rsc->server_interp, "rivet", NULL);
 

---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-dev-unsubscr...@tcl.apache.org
For additional commands, e-mail: rivet-dev-h...@tcl.apache.org

Reply via email to