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