You are viewing a plain text version of this content. The canonical link for it is here.
Posted to site-cvs@tcl.apache.org by mx...@apache.org on 2015/10/04 01:05:14 UTC

svn commit: r1706645 - in /tcl/rivet/trunk: ./ src/mod_rivet/

Author: mxmanghi
Date: Sat Oct  3 23:05:14 2015
New Revision: 1706645

URL: http://svn.apache.org/viewvc?rev=1706645&view=rev
Log:
    * src/mod_rivet/mod_rivet.c: moving Rivet_ProcessorCleanup in 
    mod_rivet_common.c
    * src/mod_rivet/mod_rivet.h: add exit status code to
    thread private data
    * src/mod_rivet/mod_rivet_common.c: Rivet_ProcessorCleanup now
    in this file
    * src/mod_rivet/rivet_worker_mpm.c: thread exit handling
    now calling the finalize handling function. Functions naming
    scheme reformed. Since the exit_thread command forces
    the whole child process to exit the check on the thread
    counter in the supervisor thread was changed as the thread
    executing thread_exit brings about can't exit before
    the supervisor itself terminates
    * src/mod_rivet/rivet_prefork_mpm.c: function naming scheme
    changed.


Modified:
    tcl/rivet/trunk/ChangeLog
    tcl/rivet/trunk/src/mod_rivet/mod_rivet.c
    tcl/rivet/trunk/src/mod_rivet/mod_rivet.h
    tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.c
    tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.h
    tcl/rivet/trunk/src/mod_rivet/rivetCore.c
    tcl/rivet/trunk/src/mod_rivet/rivet_prefork_mpm.c
    tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c

Modified: tcl/rivet/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/ChangeLog?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Sat Oct  3 23:05:14 2015
@@ -1,3 +1,20 @@
+2015-10-04 Massimo Manghi <mx...@apache.org>
+    * src/mod_rivet/mod_rivet.c: moving Rivet_ProcessorCleanup in 
+    mod_rivet_common.c
+    * src/mod_rivet/mod_rivet.h: add exit status code to
+    thread private data
+    * src/mod_rivet/mod_rivet_common.c: Rivet_ProcessorCleanup now
+    in this file
+    * src/mod_rivet/rivet_worker_mpm.c: thread exit handling
+    now calling the finalize handling function. Functions naming
+    scheme reformed. Since the exit_thread command forces
+    the whole child process to exit the check on the thread
+    counter in the supervisor thread was changed as the thread
+    executing thread_exit brings about can't exit before
+    the supervisor itself terminates
+    * src/mod_rivet/rivet_prefork_mpm.c: function naming scheme
+    changed.
+
 2015-09-04 Massimo Manghi <mx...@apache.org>
     * src/mod_rivet/rivet_prefork_mpm.c: fix message severity
     in finalize method

Modified: tcl/rivet/trunk/src/mod_rivet/mod_rivet.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/mod_rivet.c?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/mod_rivet.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/mod_rivet.c Sat Oct  3 23:05:14 2015
@@ -66,21 +66,24 @@ extern Tcl_ChannelType   RivetChan;
 apr_threadkey_t*         rivet_thread_key    = NULL;
 mod_rivet_globals*       module_globals      = NULL;
 
-void        Rivet_PerInterpInit (   rivet_thread_interp* interp, 
-                                    rivet_thread_private* private, 
-                                    server_rec *s, apr_pool_t *p );
-static int  Rivet_ExecuteAndCheck   (rivet_thread_private *private, Tcl_Obj *tcl_script_obj);
-int         Rivet_InitCore          (Tcl_Interp *interp,rivet_thread_private* p); 
+void        Rivet_PerInterpInit (rivet_thread_interp* interp, 
+                                 rivet_thread_private* private, 
+                                 server_rec *s, apr_pool_t *p );
+static int  Rivet_ExecuteAndCheck (rivet_thread_private *private, Tcl_Obj *tcl_script_obj);
+int         Rivet_InitCore (Tcl_Interp *interp,rivet_thread_private* p); 
 
 #define ERRORBUF_SZ     256
 
 /*
+ * -- Rivet_Exit_Handler
+ *
+ * 
  *
  */
 
 int Rivet_Exit_Handler(int code)
 {
-    Tcl_Exit(code);
+    //Tcl_Exit(code);
     /*NOTREACHED*/
     return TCL_OK;		/* Better not ever reach this! */
 }
@@ -430,90 +433,6 @@ rivet_thread_private* Rivet_VirtualHosts
 }
 
 
-/*
- * -- Rivet_ProcessorCleanup
- *
- * Thread private data cleanup. This function is called by MPM bridges to 
- * release data owned by private and pointed in the array of rivet_thread_interp
- * objects. It has to be called just before an agent, either thread or
- * process, exits.
- *
- *  Arguments:
- *
- *      data:   pointer to a rivet_thread_private data structure. 
- *
- *  Returned value:
- *
- *      none
- *
- *  Side effects:
- *
- *      resources stored in the array of rivet_thread_interp objects are released
- *      and interpreters are deleted.
- *
- */
-
-void Rivet_ProcessorCleanup (void *data)
-{
-    rivet_thread_private*   private = (rivet_thread_private *) data;
-    Tcl_HashSearch*         searchCtx; 
-    Tcl_HashEntry*          entry;
-    int                     i;
-    rivet_server_conf*      rsc = RIVET_SERVER_CONF(module_globals->server->module_config);
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, module_globals->server, 
-                 "Thread exiting after %d requests served (%d vhosts)", 
-                                        private->req_cnt,module_globals->vhosts_count);
-
-    /* We are deleting the interpreters and release the thread channel. 
-     * Rivet channel is set as stdout channel of Tcl and as such is treated
-     * by Tcl_UnregisterChannel is a special way. When its refCount reaches 1
-     * the channel is released immediately by forcing the refCount to 0
-     * (see Tcl source code: generic/TclIO.c). Unregistering for each interpreter
-     * causes the process to segfault at least for certain Tcl versions.
-     * We unset the channel as stdout to avoid this
-     */
-
-    Tcl_SetStdChannel(NULL,TCL_STDOUT);
-
-    /* there must be always a root interpreter in the slot 0 of private->interps,
-       so there is always need to run at least one cycle here */
-
-    i = 0;
-    do
-    {
-
-        /* cleaning the cache contents and deleting it */
-
-        searchCtx = apr_pcalloc(private->pool,sizeof(Tcl_HashSearch));
-        entry = Tcl_FirstHashEntry(private->interps[i]->objCache,searchCtx);    
-        while (entry)
-        {
-            Tcl_DecrRefCount(Tcl_GetHashValue(entry)); /* Let Tcl clear the mem allocated */
-            Tcl_DeleteHashEntry(entry);
-
-            entry = Tcl_NextHashEntry(searchCtx);
-        }
- 
-        if ((i > 0) && rsc->separate_channels) 
-            Rivet_ReleaseRivetChannel(private->interps[i]->interp,private->channel);
-
-        Tcl_DeleteInterp(private->interps[i]->interp);
-
-        /* if separate_virtual_interps == 0 we are running the same interpreter
-         * instance for each vhost, thus we can jump out of this loop after 
-         * the first cycle as the only real intepreter object we have is stored
-         * in private->interps[0]
-         */
-
-    } while ((++i < module_globals->vhosts_count) && rsc->separate_virtual_interps);
-
-    Tcl_DecrRefCount(private->request_init);
-    Tcl_DecrRefCount(private->request_cleanup);
-    apr_pool_destroy(private->pool);
-    
-}
-
 /* ----------------------------------------------------------------------------
  * -- Rivet_SendContent
  *
@@ -766,22 +685,29 @@ Rivet_SendContent(rivet_thread_private *
     retval = OK;
 sendcleanup:
 
-    /* Let's set the charset in the headers if one was set in the configuration  */
+    /* Request processing final stage */
+
+    /* A new big catch is the handling of exit commands that are treated
+     * as ::rivet::abort_page. After the AbortScript has been evaluated
+     * the exit condition is checked and in case the exit handler
+     * of the bridge module is called before terminating the whole process
+     */
+    
+    if (private->thread_exit)
+    {
+        RIVET_MPM_BRIDGE_CALL(mpm_exit_handler,private->exit_status);
+        Tcl_Exit(private->exit_status);
+    }
+
+    /* We now reset the status to prepare the child process for another request */
 
-    //if (!globals->req->headers_set && (globals->req->charset != NULL)) {
-    //    TclWeb_SetHeaderType (apr_pstrcat(globals->req->req->pool,"text/html;",
-    //                          globals->req->charset,NULL),globals->req);
-    //}
-
-    private->req->content_sent  = 0;
-    private->page_aborting      = 0;
-    private->abort_code         = NULL;
-    private->page_aborting      = 0;
+    private->req->content_sent = 0;
     if (private->abort_code != NULL)
     {
         Tcl_DecrRefCount(private->abort_code);
         private->abort_code = NULL;
     }
+    private->page_aborting = 0;
 
     /* We reset this pointer to signal we have terminated the request processing */
 
@@ -836,6 +762,7 @@ Rivet_ExecuteErrorHandler (Tcl_Interp* i
     /* This shouldn't make the default_error_script go away,
      * because it gets a Tcl_IncrRefCount when it is created.
      */
+
     Tcl_DecrRefCount(errscript);
 
     /* In case we are handling an error occurring after an abort_page call (for
@@ -848,6 +775,48 @@ Rivet_ExecuteErrorHandler (Tcl_Interp* i
     return result;
 }
 
+/*
+ * -- Rivet_RunAbortScript
+ *
+ * 
+ */
+
+static int
+Rivet_RunAbortScript (rivet_thread_private *private)
+{
+    int retcode = TCL_OK;
+    Tcl_Interp* interp = private->interps[private->running_conf->idx]->interp;
+
+    if (private->running->rivet_abort_script) 
+    {
+
+        /* Ideally an AbortScript should be fail safe, but in case
+         * it fails we give a chance to the subsequent ErrorScript
+         * to catch this error.
+         */
+
+        retcode = Tcl_EvalObjEx(interp,private->running->rivet_abort_script,0);
+
+        if (retcode == TCL_ERROR)
+        {
+            /* This is not elegant, but we want to avoid to print
+             * this error message if an ErrorScript will handle this error.
+             * Thus we print the usual error message only if we are running the
+             * default error handler
+             */
+
+            if (private->running->rivet_error_script == NULL) {
+
+                Rivet_PrintErrorMessage(interp,"<b>Rivet AbortScript failed</b>");
+
+            }
+            Rivet_ExecuteErrorHandler(interp,private->running->rivet_abort_script,private);
+        }
+
+    }
+    return retcode;
+}
+
 
 /* -- Rivet_ExecuteAndCheck
  * 
@@ -887,16 +856,10 @@ Rivet_ExecuteAndCheck(rivet_thread_priva
 
     Tcl_Preserve (interp_obj->interp);
 
-    /* before execution we reset the thread_exit flag. It will in case set if
-     * ::rivet::thread_exit gets called
-     */
-
-    private->thread_exit = 0;
     tcl_result = Tcl_EvalObjEx(interp_obj->interp, tcl_script_obj, 0);
     if (tcl_result == TCL_ERROR) {
         Tcl_Obj*    errorCodeListObj;
         Tcl_Obj*    errorCodeElementObj;
-        char*       errorCodeSubString;
 
         /* There was an error, see if it's from Rivet and it was caused
          * by abort_page.
@@ -920,54 +883,27 @@ Rivet_ExecuteAndCheck(rivet_thread_priva
          * a rivet_abort_script is defined, otherwise the page emits 
          * as normal
          */
-        if (strcmp (Tcl_GetString (errorCodeElementObj), "RIVET") == 0) {
+
+        // if (strcmp (Tcl_GetString (errorCodeElementObj), "RIVET") == 0) 
+        if (private->page_aborting)
+        {
+            //char*       errorCodeSubString;
 
             /* dig the second element out of the errorCode list, make sure
              * it succeeds -- it should always
              */
-            ap_assert (Tcl_ListObjIndex (interp_obj->interp, errorCodeListObj, 1, &errorCodeElementObj) == TCL_OK);
+            //ap_assert (Tcl_ListObjIndex (interp_obj->interp, errorCodeListObj, 1, &errorCodeElementObj) == TCL_OK);
 
-            errorCodeSubString = Tcl_GetString (errorCodeElementObj);
-            if (strcmp (errorCodeSubString, ABORTPAGE_CODE) == 0) 
-            {
-                if (private->running->rivet_abort_script) 
-                {
-                    Tcl_Interp* interp = interp_obj->interp;
-
-                    /* Ideally an AbortScript should be fail safe, but in case
-                     * it fails we give a chance to the subsequent ErrorScript
-                     * to catch this error.
-                     */
-
-                    if (Tcl_EvalObjEx(interp,private->running->rivet_abort_script,0) == TCL_ERROR)
-                    {
-                        /* This is not elegant, but we want to avoid to print
-                         * this error message if an ErrorScript will handle this error.
-                         * Thus we print the usual error message only if we are running the
-                         * default error handler
-                         */
-
-                        if (private->running->rivet_error_script == NULL) {
-
-                            Rivet_PrintErrorMessage(interp,"<b>Rivet AbortScript failed</b>");
-                        }
-                        Rivet_ExecuteErrorHandler(interp,private->running->rivet_abort_script,private);
-                    }
-                }
-            }
-            else if (strcmp(errorCodeSubString, THREAD_EXIT_CODE) == 0)
-            {
-
-                /* we simply set the thread_exit flag and finish with this 
-                 * request and proceed checking whether an after_every_script 
-                 * is defined 
-                 */
-
-                private->thread_exit = 1;
-            } 
+            //errorCodeSubString = Tcl_GetString (errorCodeElementObj);
+            //if ((strcmp(errorCodeSubString, ABORTPAGE_CODE) == 0) || 
+            //    (strcmp(errorCodeSubString, THREAD_EXIT_CODE) == 0))
+            //
+            //{
+                Rivet_RunAbortScript(private);
+            //}
  
         }
-        else if (!private->page_aborting)
+        else 
         {
             Rivet_ExecuteErrorHandler (interp_obj->interp,tcl_script_obj,private);
         }
@@ -1016,9 +952,6 @@ Rivet_ParseExecFile(rivet_thread_private
     time_t          ctime;
     time_t          mtime;
     int             res = 0;
-    //rivet_server_conf *rsc;
-
-    //rsc = Rivet_GetConf( private->r );
 
     /* We have to fetch the interpreter data from the thread private environment */
 
@@ -1470,8 +1403,6 @@ Rivet_RunServerInit (apr_pool_t *pPool,
 static int
 Rivet_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *server)
 {
-    apr_status_t        aprrv;
-    char                errorbuf[ERRORBUF_SZ];
     char*               mpm_prefork_bridge = "rivet_prefork_mpm.so";
     char*               mpm_worker_bridge  = "rivet_worker_mpm.so";
     char*               mpm_model_path;
@@ -1479,9 +1410,9 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
     apr_dso_handle_t*   dso_handle;
 
 #if RIVET_DISPLAY_VERSION
-    ap_add_version_component(pPool, RIVET_PACKAGE_NAME"/"RIVET_VERSION);
+    ap_add_version_component(pPool,RIVET_PACKAGE_NAME"/"RIVET_VERSION);
 #else
-    ap_add_version_component(pPool, RIVET_PACKAGE_NAME);
+    ap_add_version_component(pPool,RIVET_PACKAGE_NAME);
 #endif
 
     /* Everything revolves around this structure */
@@ -1532,8 +1463,7 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         mpm_model_path = apr_pstrcat(pTemp,RIVET_DIR,"/mpm/",module_globals->rivet_mpm_bridge,NULL);
     } 
 
-    aprrv = apr_dso_load(&dso_handle,mpm_model_path,pPool);
-    if (aprrv == APR_SUCCESS)
+    if (apr_dso_load(&dso_handle,mpm_model_path,pPool) == APR_SUCCESS)
     {
         apr_status_t                rv;
         apr_dso_handle_sym_t        func = NULL;
@@ -1547,6 +1477,8 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         }
         else
         {
+            char errorbuf[ERRORBUF_SZ];
+
             ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                          MODNAME ": Error loading symbol bridge_jump_table: %s", 
                          apr_dso_error(dso_handle,errorbuf,ERRORBUF_SZ));
@@ -1558,11 +1490,6 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
         ap_assert(RIVET_MPM_BRIDGE_FUNCTION(mpm_request) != NULL);
         ap_assert(RIVET_MPM_BRIDGE_FUNCTION(mpm_master_interp) != NULL);
 
-        if (RIVET_MPM_BRIDGE_FUNCTION(mpm_exit_handler) == NULL) {
-            RIVET_MPM_BRIDGE_FUNCTION(mpm_exit_handler) = Rivet_Exit_Handler;
-        }
-
-        apr_atomic_init(pPool);
         apr_thread_mutex_create(&module_globals->pool_mutex, APR_THREAD_MUTEX_UNNESTED, pPool);
 
     /* Another crucial point: we are storing in the globals a reference to the
@@ -1580,12 +1507,13 @@ Rivet_ServerInit (apr_pool_t *pPool, apr
     }
     else
     {
+        char errorbuf[ERRORBUF_SZ];
 
         /* If we don't find the mpm handler module we give up and exit */
 
         ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, 
                      MODNAME " Error loading MPM manager: %s", 
-                     apr_dso_error(dso_handle,errorbuf,1024));
+                     apr_dso_error(dso_handle,errorbuf,ERRORBUF_SZ));
         exit(1);   
     }
 
@@ -1671,6 +1599,7 @@ static int Rivet_Handler (request_rec *r
     if (ctype == CTYPE_NOT_HANDLED) {
         return DECLINED;
     }
+
     return (*RIVET_MPM_BRIDGE_FUNCTION(mpm_request))(r,ctype);
 }
 

Modified: tcl/rivet/trunk/src/mod_rivet/mod_rivet.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/mod_rivet.h?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/mod_rivet.h (original)
+++ tcl/rivet/trunk/src/mod_rivet/mod_rivet.h Sat Oct  3 23:05:14 2015
@@ -28,7 +28,6 @@
 #include <apr_tables.h>
 #include <apr_thread_proc.h>
 #include <apr_thread_cond.h>
-#include <apr_atomic.h>
 #include <tcl.h>
 #include "rivet.h"
 #include "apache_request.h"
@@ -210,8 +209,8 @@ typedef struct _thread_worker_private {
                                             
     rivet_server_conf*  running_conf;       /* running configuration                */
     running_scripts*    running;            /* (per request) running conf scripts   */
-    int                 thread_exit;        /* Flag signalling thread_exit call     */
-
+    int                 thread_exit;        /* Thread exit code                     */
+    int                 exit_status;        /* status code to be passed to exit()   */
 
     int                 page_aborting;      /* abort_page flag                      */
     Tcl_Obj*            abort_code;         /* To be reset by before request        *
@@ -286,7 +285,6 @@ EXTERN Tcl_Interp* Rivet_CreateTclInterp
 #define ABORTPAGE_CODE              "ABORTPAGE"
 #define THREAD_EXIT_CODE            "THREAD_EXIT"
 
-#define MOD_RIVET_QUEUE_SIZE        100
 #define TCL_MAX_CHANNEL_BUFFER_SIZE (1024*1024)
 #define MODNAME                     "mod_rivet"
 

Modified: tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.c?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.c Sat Oct  3 23:05:14 2015
@@ -38,6 +38,7 @@
 
 extern apr_threadkey_t*   rivet_thread_key;
 extern mod_rivet_globals* module_globals;
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -150,6 +151,8 @@ rivet_thread_private* Rivet_CreatePrivat
     private->r              = NULL;
     private->req            = TclWeb_NewRequestObject (private->pool);
     private->page_aborting  = 0;
+    private->thread_exit    = 0;
+    private->exit_status    = 0;
     private->abort_code     = NULL;
     private->request_init = Tcl_NewStringObj("::Rivet::initialize_request\n", -1);
     private->request_cleanup = Tcl_NewStringObj("::Rivet::cleanup_request\n", -1);
@@ -481,4 +484,87 @@ Rivet_CheckType (request_rec *req)
     return ctype; 
 }
 
+/*
+ * -- Rivet_ProcessorCleanup
+ *
+ * Thread private data cleanup. This function is called by MPM bridges to 
+ * release data owned by private and pointed in the array of rivet_thread_interp
+ * objects. It has to be called just before an agent, either thread or
+ * process, exits.
+ *
+ *  Arguments:
+ *
+ *      data:   pointer to a rivet_thread_private data structure. 
+ *
+ *  Returned value:
+ *
+ *      none
+ *
+ *  Side effects:
+ *
+ *      resources stored in the array of rivet_thread_interp objects are released
+ *      and interpreters are deleted.
+ *
+ */
+
+void Rivet_ProcessorCleanup (void *data)
+{
+    rivet_thread_private*   private = (rivet_thread_private *) data;
+    Tcl_HashSearch*         searchCtx; 
+    Tcl_HashEntry*          entry;
+    int                     i;
+    rivet_server_conf*      rsc = RIVET_SERVER_CONF(module_globals->server->module_config);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, module_globals->server, 
+                 "Thread exiting after %d requests served (%d vhosts)", 
+                                        private->req_cnt,module_globals->vhosts_count);
+
+    /* We are deleting the interpreters and release the thread channel. 
+     * Rivet channel is set as stdout channel of Tcl and as such is treated
+     * by Tcl_UnregisterChannel is a special way. When its refCount reaches 1
+     * the channel is released immediately by forcing the refCount to 0
+     * (see Tcl source code: generic/TclIO.c). Unregistering for each interpreter
+     * causes the process to segfault at least for certain Tcl versions.
+     * We unset the channel as stdout to avoid this
+     */
+
+    Tcl_SetStdChannel(NULL,TCL_STDOUT);
+
+    /* there must be always a root interpreter in the slot 0 of private->interps,
+       so there is always need to run at least one cycle here */
+
+    i = 0;
+    do
+    {
+
+        /* cleaning the cache contents and deleting it */
+
+        searchCtx = apr_pcalloc(private->pool,sizeof(Tcl_HashSearch));
+        entry = Tcl_FirstHashEntry(private->interps[i]->objCache,searchCtx);    
+        while (entry)
+        {
+            Tcl_DecrRefCount(Tcl_GetHashValue(entry)); /* Let Tcl clear the mem allocated */
+            Tcl_DeleteHashEntry(entry);
+
+            entry = Tcl_NextHashEntry(searchCtx);
+        }
+ 
+        if ((i > 0) && rsc->separate_channels) 
+            Rivet_ReleaseRivetChannel(private->interps[i]->interp,private->channel);
+
+        Tcl_DeleteInterp(private->interps[i]->interp);
+
+        /* if separate_virtual_interps == 0 we are running the same interpreter
+         * instance for each vhost, thus we can jump out of this loop after 
+         * the first cycle as the only real intepreter object we have is stored
+         * in private->interps[0]
+         */
+
+    } while ((++i < module_globals->vhosts_count) && rsc->separate_virtual_interps);
+
+    Tcl_DecrRefCount(private->request_init);
+    Tcl_DecrRefCount(private->request_cleanup);
+    apr_pool_destroy(private->pool);
+    
+}
 

Modified: tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.h?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.h (original)
+++ tcl/rivet/trunk/src/mod_rivet/mod_rivet_common.h Sat Oct  3 23:05:14 2015
@@ -22,6 +22,7 @@
 #ifndef _MOD_RIVET_COMMON_
 #define _MOD_RIVET_COMMON_
 
+EXTERN void Rivet_ProcessorCleanup (void *data);
 EXTERN int Rivet_chdir_file (const char *file);
 EXTERN int Rivet_CheckType (request_rec* r);
 EXTERN void Rivet_CleanupRequest(request_rec *r);
@@ -31,4 +32,5 @@ EXTERN Tcl_Channel* Rivet_CreateRivetCha
 EXTERN rivet_thread_private* Rivet_CreatePrivateData (void);
 EXTERN rivet_thread_private* Rivet_SetupTclPanicProc (void);
 EXTERN void Rivet_ReleaseRivetChannel (Tcl_Interp* interp, Tcl_Channel* channel);
+
 #endif

Modified: tcl/rivet/trunk/src/mod_rivet/rivetCore.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/rivetCore.c?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivetCore.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivetCore.c Sat Oct  3 23:05:14 2015
@@ -1234,6 +1234,11 @@ TCL_CMD_HEADER( Rivet_AbortPageCmd )
 
     /* this is the first (and supposedly unique) abort_page call during this request */
 
+    /* we eleveta the page_aborting flag to the actual flag controlling the page abort execution. 
+     * We still return the RIVET and ABORTPAGE_CODE, but internally
+     * its page_aborting that will drive the code execution after abort_page
+     */
+
     private->page_aborting = 1;
 
     Tcl_AddErrorInfo (interp, errorMessage);
@@ -1335,6 +1340,8 @@ TCL_CMD_HEADER( Rivet_EnvCmd )
 TCL_CMD_HEADER( Rivet_ExitCmd )
 {
     int value;
+    rivet_thread_private*   private;
+    char* errorMessage = "page generation interrupted by exit command";
 
     if ((objc != 1) && (objc != 2)) {
         Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
@@ -1347,11 +1354,40 @@ TCL_CMD_HEADER( Rivet_ExitCmd )
         return TCL_ERROR;
     }
 
+    THREAD_PRIVATE_DATA(private)
+
+    private->page_aborting = 1;
+    private->abort_code = Tcl_NewDictObj();
+
+    /* The private->abort_code ref count is decremented before 
+     * request processing terminates*/
+
+    Tcl_IncrRefCount(private->abort_code);
+
+    /*
+     * mod_rivet traps call to exit and offers a chance to handle them 
+     * in the way we handle ::rivet::abort_page calls
+     */
+
+    Tcl_DictObjPut(interp,private->abort_code,
+                   Tcl_NewStringObj("error_code",-1),
+                   Tcl_NewStringObj("exit",-1));
+
+    Tcl_DictObjPut(interp,private->abort_code,
+                   Tcl_NewStringObj("return_code",-1),
+                   Tcl_NewIntObj(value));
+
+    private->thread_exit = 1;
+    private->exit_status = value;
+
     /* this call actually could never return for a non-threaded MPM bridge
      * as it eventually will call Tcl_Exit
      */
+    Tcl_AddErrorInfo (interp, errorMessage);
+    Tcl_SetErrorCode (interp, "RIVET", THREAD_EXIT_CODE, errorMessage, (char *)NULL);
 
-    return (*RIVET_MPM_BRIDGE_FUNCTION(mpm_exit_handler))(value);
+    //return (*RIVET_MPM_BRIDGE_FUNCTION(mpm_exit_handler))(value);
+    return TCL_ERROR;
 }
 /*
  *-----------------------------------------------------------------------------
@@ -1383,8 +1419,8 @@ TCL_CMD_HEADER( Rivet_VirtualFilenameCmd
         return TCL_ERROR;
     }
 
-    virtual   = Tcl_GetStringFromObj( objv[1], NULL );
-    filename  = TclWeb_GetVirtualFile( private->req, virtual );
+    virtual  = Tcl_GetStringFromObj( objv[1], NULL );
+    filename = TclWeb_GetVirtualFile( private->req, virtual );
 
     Tcl_SetObjResult(interp, Tcl_NewStringObj( filename, -1 ) );
     return TCL_OK;
@@ -1728,7 +1764,7 @@ Rivet_InitCore(Tcl_Interp *interp,rivet_
     RIVET_OBJ_CMD ("env",Rivet_EnvCmd,private);
     RIVET_OBJ_CMD ("apache_log_error",Rivet_LogErrorCmd,private);
     RIVET_OBJ_CMD ("inspect",Rivet_InspectCmd,private);
-    RIVET_OBJ_CMD ("exit_thread",Rivet_ExitCmd,NULL);
+    RIVET_OBJ_CMD ("exit_thread",Rivet_ExitCmd,private);
 
 #ifdef TESTPANIC
     RIVET_OBJ_CMD ("testpanic",TestpanicCmd,private);
@@ -1738,6 +1774,5 @@ Rivet_InitCore(Tcl_Interp *interp,rivet_
     Tcl_Export(interp,rivet_ns,"*",0);
 #endif
 
-//  return Tcl_PkgProvide( interp,RIVET_TCL_PACKAGE,"1.2");
     return TCL_OK;
 }

Modified: tcl/rivet/trunk/src/mod_rivet/rivet_prefork_mpm.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/rivet_prefork_mpm.c?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivet_prefork_mpm.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivet_prefork_mpm.c Sat Oct  3 23:05:14 2015
@@ -33,31 +33,31 @@
 extern mod_rivet_globals* module_globals;
 extern apr_threadkey_t*   rivet_thread_key;
 
-void        Rivet_ProcessorCleanup (void *data);
-int         Rivet_InitCore          (Tcl_Interp *interp,rivet_thread_private* p); 
+int Rivet_InitCore (Tcl_Interp *interp,rivet_thread_private* p); 
 
 rivet_thread_private* Rivet_VirtualHostsInterps (rivet_thread_private* private);
 rivet_thread_interp* Rivet_NewVHostInterp(apr_pool_t* pool);
 
-/* */
+/* -- Prefork_MPM_Finalize */
 
-apr_status_t Rivet_MPM_Finalize (void* data)
+apr_status_t Prefork_MPM_Finalize (void* data)
 {
     rivet_thread_private*   private;
     server_rec* s = (server_rec*) data;
 
-    ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS);
+    RIVET_PRIVATE_DATA_NOT_NULL(rivet_thread_key,private)
     ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s, "Running prefork bridge finalize method");
 
-    Rivet_ProcessorCleanup(private);
+    // No, we don't clean up anymore as we are just shutting this process down
+    // Rivet_ProcessorCleanup(private);
 
     apr_threadkey_private_delete (rivet_thread_key);
     return OK;
 }
 
-//int Rivet_MPM_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s) { return OK; }
+//int Prefork_MPM_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s) { return OK; }
 
-void Rivet_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
+void Prefork_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
 {
     rivet_thread_private*   private;
 
@@ -85,7 +85,7 @@ void Rivet_MPM_ChildInit (apr_pool_t* po
 
 #ifdef RIVET_NAMESPACE_IMPORT
     {
-        char*    tcl_import_cmd = "namespace eval :: { namespace eval :: { namespace import -force ::rivet::* }}\n";
+        char* tcl_import_cmd = "namespace eval :: { namespace import -force ::rivet::* }\n";
 
         Tcl_Eval (module_globals->server_interp->interp,tcl_import_cmd);
     }
@@ -104,7 +104,7 @@ void Rivet_MPM_ChildInit (apr_pool_t* po
 }
 
 /*
- * -- Rivet_MPM_Request
+ * -- Prefork_MPM_Request
  *
  *  The prefork implementation of this function is basically a wrapper of
  *  Rivet_SendContent. The real job is fetching the thread private data
@@ -118,7 +118,7 @@ void Rivet_MPM_ChildInit (apr_pool_t* po
  *   HTTP status code (see the Apache HTTP web server documentation)
  */
 
-int Rivet_MPM_Request (request_rec* r,rivet_req_ctype ctype)
+int Prefork_MPM_Request (request_rec* r,rivet_req_ctype ctype)
 {
     rivet_thread_private*   private;
 
@@ -131,7 +131,7 @@ int Rivet_MPM_Request (request_rec* r,ri
     return Rivet_SendContent(private,r);
 }
 
-rivet_thread_interp* Rivet_MPM_MasterInterp(void)
+rivet_thread_interp* Prefork_MPM_MasterInterp(void)
 {
     rivet_thread_private*   private;
 
@@ -143,10 +143,10 @@ rivet_thread_interp* Rivet_MPM_MasterInt
 
 rivet_bridge_table bridge_jump_table = {
     NULL,
-    Rivet_MPM_ChildInit,
-    Rivet_MPM_Request,
-    Rivet_MPM_Finalize,
-    Rivet_MPM_MasterInterp,
+    Prefork_MPM_ChildInit,
+    Prefork_MPM_Request,
+    Prefork_MPM_Finalize,
+    Prefork_MPM_MasterInterp,
     NULL
 };
 

Modified: tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c?rev=1706645&r1=1706644&r2=1706645&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c Sat Oct  3 23:05:14 2015
@@ -26,6 +26,7 @@
 #include <tcl.h>
 #include <ap_mpm.h>
 #include <apr_strings.h>
+#include <apr_atomic.h>
 
 #include "rivet.h"
 #include "mod_rivet.h"
@@ -36,6 +37,7 @@
 #include "rivet_config.h"
 
 #define BRIDGE_SUPERVISOR_WAIT  1000000
+#define MOD_RIVET_QUEUE_SIZE        100
 
 #ifdef RIVET_SERIALIZE_HTTP_REQUESTS
     #define HTTP_REQUESTS_PROC(request_proc_call) \
@@ -51,7 +53,6 @@ extern apr_threadkey_t*   rivet_thread_k
 
 apr_threadkey_t*        handler_thread_key;
 
-void                    Rivet_ProcessorCleanup (void *data);
 rivet_thread_private*   Rivet_VirtualHostsInterps (rivet_thread_private* private);
 rivet_thread_interp*    Rivet_NewVHostInterp(apr_pool_t* pool);
 
@@ -63,8 +64,8 @@ typedef struct mpm_bridge_status {
     apr_array_header_t* exiting;                /* */
     apr_uint32_t*       threads_count;
     apr_uint32_t*       running_threads_count;
-    apr_queue_t*        queue;                  /* jobs queue                   */
-    void**              workers;                /* thread pool ids              */
+    apr_queue_t*        queue;                  /* jobs queue               */
+    void**              workers;                /* thread pool ids          */
 
     int                 max_threads;
     int                 min_spare_threads;
@@ -73,6 +74,7 @@ typedef struct mpm_bridge_status {
     apr_thread_mutex_t* req_mutex;
 #endif
 } mpm_bridge_status;
+
 /* data private to the Apache callback handling the request */
 
 typedef struct _handler_private 
@@ -92,10 +94,12 @@ enum
     init,
     idle,
     request_processing,
-    done
+    done,
+    child_exit
 };
 
-/* Rivet_MPM_Shutdown --
+/* 
+ * -- Worker_Bridge_Shutdown
  *
  *  Child process shutdown. The thread count is read and 
  * on the job queue are places as many orderly exit commands
@@ -120,7 +124,7 @@ enum
  *
  */
 
-void Rivet_MPM_Shutdown (void)
+void Worker_Bridge_Shutdown (void)
 {
     handler_private* job;
     int count;
@@ -135,18 +139,26 @@ void Rivet_MPM_Shutdown (void)
     count = (int) apr_atomic_read32(module_globals->mpm->threads_count);
     for (i = 0; i < count; i++) { apr_queue_push(module_globals->mpm->queue,job); }
     apr_sleep(500000);
+
     do 
     {
+
         count = (int) apr_atomic_read32(module_globals->mpm->threads_count);
-        if (count == 0) break;
+
+        /* Actually, when Rivet exit command implementation shuts the bridge down
+         * the thread running the command is waiting for the supervisor to terminate
+         * therefore the 'count' variable can't drop to 0
+         */
+
+        if (count <= 1) break;
+
+        ap_log_error(APLOG_MARK, APLOG_ERR, APR_SUCCESS, module_globals->server, 
+            "Sending %d more stop signals to threads",count);
         apr_sleep(1000000);
-    } while (waits-- > 0);
 
-    if (count > 0) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, module_globals->server, 
-            "Unexpected %d threads still running after 5 seconds. Child process exits anyway",count);
-    }
+    } while (waits-- > 0);
 
+    return;
 }
 
 
@@ -227,9 +239,6 @@ static void* APR_THREAD_FUNC request_pro
         
         apr_atomic_inc32(module_globals->mpm->running_threads_count);
 
-        //server_conf = RIVET_SERVER_CONF(request_obj->r->server->module_config);
-        //TclWeb_InitRequest(request_obj->req, private->interps[server_conf->idx]->interp, request_obj->r);
-        
         /* these assignements are crucial for both calling Rivet_SendContent and
          * for telling the channel where stuff must be sent to */
 
@@ -238,7 +247,10 @@ static void* APR_THREAD_FUNC request_pro
         HTTP_REQUESTS_PROC(request_obj->code = Rivet_SendContent(private,request_obj->r));
 
         apr_thread_mutex_lock(request_obj->mutex);
+
         request_obj->status = done;
+        if (private->thread_exit) request_obj->status = child_exit;
+
         apr_thread_cond_signal(request_obj->cond);
         apr_thread_mutex_unlock(request_obj->mutex);
     
@@ -249,7 +261,9 @@ static void* APR_THREAD_FUNC request_pro
             
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, module_globals->server, "processor thread orderly exit");
 
-    Rivet_ProcessorCleanup(private);
+    // We don't clean up the thread resources anymore, if the thread exits the whole process terminates
+
+    // Rivet_ProcessorCleanup(private);
 
     apr_thread_mutex_lock(module_globals->mpm->job_mutex);
     *(apr_thread_t **) apr_array_push(module_globals->mpm->exiting) = thd;
@@ -283,7 +297,8 @@ static void start_thread_pool (int nthre
         rv = create_worker_thread(&slot);
         module_globals->mpm->workers[i] = (void *) slot;
 
-        if (rv != APR_SUCCESS) {
+        if (rv != APR_SUCCESS) 
+        {
             char    errorbuf[512];
 
             apr_strerror(rv, errorbuf,200);
@@ -328,11 +343,13 @@ static void supervisor_housekeeping (voi
 
 static void* APR_THREAD_FUNC threaded_bridge_supervisor (apr_thread_t *thd, void *data)
 {
+    mpm_bridge_status* mpm = module_globals->mpm;
+
     server_rec* s = (server_rec *)data;
 #ifdef RIVET_MPM_SINGLE_TCL_THREAD
     int thread_to_start = 1;
 #else
-    int thread_to_start = (int)round(module_globals->mpm->max_threads);
+    int thread_to_start = (int) round(mpm->max_threads);
 #endif
 
     ap_log_error(APLOG_MARK,APLOG_INFO,0,s,"starting %d Tcl threads",thread_to_start);
@@ -340,31 +357,32 @@ static void* APR_THREAD_FUNC threaded_br
 
     do
     {
-        apr_thread_t*   p;
+        apr_thread_t* p;
       
-        apr_thread_mutex_lock(module_globals->mpm->job_mutex);
-        while (apr_is_empty_array(module_globals->mpm->exiting) && !module_globals->mpm->server_shutdown)
+        apr_thread_mutex_lock(mpm->job_mutex);
+        while (apr_is_empty_array(mpm->exiting) && !mpm->server_shutdown)
         {
-            apr_thread_cond_wait ( module_globals->mpm->job_cond, module_globals->mpm->job_mutex );
+            apr_thread_cond_wait ( mpm->job_cond, mpm->job_mutex );
         }
 
-        while (!apr_is_empty_array(module_globals->mpm->exiting) && !module_globals->mpm->server_shutdown)
+        while (!apr_is_empty_array(mpm->exiting) && !mpm->server_shutdown)
         {
             int i;
-            p = *(apr_thread_t **)apr_array_pop(module_globals->mpm->exiting);
+            p = *(apr_thread_t **)apr_array_pop(mpm->exiting);
             
-            for (i = 0; (i < TCL_INTERPS) && !module_globals->mpm->server_shutdown; i++)
+            for (i = 0; (i < TCL_INTERPS) && !mpm->server_shutdown; i++)
             {
-                if (p == module_globals->mpm->workers[i])
+                if (p == mpm->workers[i])
                 {
                     apr_status_t rv;
 
                     ap_log_error(APLOG_MARK,APLOG_DEBUG,0,s,"thread %d notifies orderly exit",i);
 
-                    module_globals->mpm->workers[i] = NULL;
+                    mpm->workers[i] = NULL;
 
                     /* terminated thread restart */
-                    rv = create_worker_thread (&((apr_thread_t **)module_globals->mpm->workers)[i]);
+
+                    rv = create_worker_thread (&((apr_thread_t **)mpm->workers)[i]);
                     if (rv != APR_SUCCESS) {
                         char errorbuf[512];
 
@@ -384,19 +402,30 @@ static void* APR_THREAD_FUNC threaded_br
                 }
             }       
         }   
-        apr_thread_mutex_unlock(module_globals->mpm->job_mutex);
-    }  while (!module_globals->mpm->server_shutdown);
+        apr_thread_mutex_unlock(mpm->job_mutex);
+    }  while (!mpm->server_shutdown);
 
-    Rivet_MPM_Shutdown();
+    Worker_Bridge_Shutdown();
     
+    {
+        int count = (int) apr_atomic_read32(mpm->threads_count);
+        if (count > 0) 
+        {
+
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, module_globals->server, 
+                "%d threads are still running after 5 attempts. Child process exits anyway",count);
+
+        }
+    }
     apr_thread_exit(thd,APR_SUCCESS);
+
     return NULL;
 }
 
-// int Rivet_MPM_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s) { return OK; }
+// int Worker_MPM_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s) { return OK; }
 
 /*
- * -- Rivet_MPM_ChildInit
+ * -- Worker_MPM_ChildInit
  *
  * Child initialization function called by the web server framework.
  * For this bridge tasks are 
@@ -405,10 +434,9 @@ static void* APR_THREAD_FUNC threaded_br
  *   + content generation callback private key creation
  *   + supervisor thread creation
  * 
- *
  */
 
-void Rivet_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
+void Worker_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
 {
     apr_status_t        rv;
 
@@ -427,6 +455,9 @@ void Rivet_MPM_ChildInit (apr_pool_t* po
     module_globals->mpm->workers            = NULL;
     module_globals->mpm->server_shutdown    = 0;
 
+    /* We keep some atomic counters that could provide basic data for a workload balancer */
+
+    apr_atomic_init(pool);
     module_globals->mpm->threads_count = (apr_uint32_t *) apr_pcalloc(pool,sizeof(apr_uint32_t));
     module_globals->mpm->running_threads_count = (apr_uint32_t *) apr_pcalloc(pool,sizeof(apr_uint32_t));
     apr_atomic_set32(module_globals->mpm->threads_count,0);
@@ -516,9 +547,8 @@ apr_status_t Worker_RequestPrivateCleanu
     return APR_SUCCESS;
 }
 
-
 /*
- * -- Rivet_MPM_Request
+ * -- Worker_MPM_Request
  *
  * Content generation callback. Actually on the bridge this function is not
  * generating directly the requested content but instead builds a handler_private 
@@ -526,7 +556,7 @@ apr_status_t Worker_RequestPrivateCleanu
  * queue (module_globals->mpm->queue). In this structure are also a
  * condition variable and associated mutex. Through this condition variable a
  * worker thread running a Tcl interpreter will tell the framework thread the request
- * has been served letting it go and return to the HTTP server framework
+ * has been served letting it return to the HTTP server framework
  *
  * Arguments:
  *
@@ -537,7 +567,7 @@ apr_status_t Worker_RequestPrivateCleanu
  *   HTTP status code (see the Apache HTTP web server documentation)
  */
 
-int Rivet_MPM_Request (request_rec* r,rivet_req_ctype ctype)
+int Worker_MPM_Request (request_rec* r,rivet_req_ctype ctype)
 {
     handler_private*    request_private;
     apr_status_t        rv;
@@ -603,13 +633,21 @@ int Rivet_MPM_Request (request_rec* r,ri
     }
     else
     {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,  
+                      MODNAME ": rivet_worker_mpm: could not push request on threads queue");
         request_private->code = HTTP_INTERNAL_SERVER_ERROR;
     }
 
     return request_private->code;
 }
 
-apr_status_t Rivet_MPM_Finalize (void* data)
+/* 
+ * -- Worker_MPM_Finalize
+ *
+ *
+ */
+
+apr_status_t Worker_MPM_Finalize (void* data)
 {
     apr_status_t  rv;
     apr_status_t  thread_status;
@@ -617,6 +655,11 @@ apr_status_t Rivet_MPM_Finalize (void* d
     
     apr_thread_mutex_lock(module_globals->mpm->job_mutex);
     module_globals->mpm->server_shutdown = 1;
+
+    /* We wake up the supervisor who is now supposed to stop 
+     * all the Tcl worker threads
+     */
+
     apr_thread_cond_signal(module_globals->mpm->job_cond);
     apr_thread_mutex_unlock(module_globals->mpm->job_mutex);
 
@@ -633,7 +676,7 @@ apr_status_t Rivet_MPM_Finalize (void* d
 }
 
 /*
- * Rivet_MPM_MasterInterp --
+ * -- Worker_MPM_MasterInterp
  *
  *  Arguments:
  *
@@ -643,14 +686,12 @@ apr_status_t Rivet_MPM_Finalize (void* d
  *
  */
 
-rivet_thread_interp* Rivet_MPM_MasterInterp(void)
+rivet_thread_interp* Worker_MPM_MasterInterp(void)
 {
     rivet_thread_private*   private;
-    rivet_thread_interp*           interp_obj; 
+    rivet_thread_interp*    interp_obj; 
 
     RIVET_PRIVATE_DATA_NOT_NULL(rivet_thread_key,private)
-    //ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS);
-    //ap_assert (private != NULL);
 
     interp_obj = Rivet_NewVHostInterp(private->pool);
     //interp_obj->channel = Rivet_CreateRivetChannel(private->pool,rivet_thread_key);
@@ -658,29 +699,44 @@ rivet_thread_interp* Rivet_MPM_MasterInt
     return interp_obj;
 }
 
-int Rivet_MPM_ExitHandler(int code)
+/*
+ * -- Worker_MPM_ExitHandler
+ *  
+ *  Signals a thread to exit by setting the loop control flag to 0
+ * and by returning a Tcl error with error code THREAD_EXIT_CODE
+ *
+ *  Arguments:
+ *      int code
+ *
+ * Side Effects:
+ *
+ *  the thread running the Tcl script will exit 
+ */
+
+int Worker_MPM_ExitHandler(int code)
 {
     rivet_thread_private*   private;
-    Tcl_Interp*             interp;
-    static char*            errorMessage = "Page generation terminated by thread_exit command";
 
-    ap_assert (apr_threadkey_private_get ((void **)&private,rivet_thread_key) == APR_SUCCESS);
-    ap_assert (private != NULL);
+    RIVET_PRIVATE_DATA_NOT_NULL(rivet_thread_key,private)
 
-    interp = private->interps[private->running_conf->idx]->interp;
-    private->keep_going = 0;
+    /* This is not strictly necessary, because this command will 
+     * eventually terminate the whole processes */
 
-    Tcl_AddErrorInfo (interp, errorMessage);
-    Tcl_SetErrorCode (interp, "RIVET", THREAD_EXIT_CODE, errorMessage, (char *)NULL);
+    /* This will force the current thread to exit */
 
-    return TCL_ERROR;
+    private->keep_going = 0;
+
+    /* We now tell the whole process to shutdown */
+ 
+    Worker_MPM_Finalize (private->r->server);
+    return TCL_OK;
 }
 
 rivet_bridge_table bridge_jump_table = {
     NULL,
-    Rivet_MPM_ChildInit,
-    Rivet_MPM_Request,
-    Rivet_MPM_Finalize,
-    Rivet_MPM_MasterInterp,
-    Rivet_MPM_ExitHandler
+    Worker_MPM_ChildInit,
+    Worker_MPM_Request,
+    Worker_MPM_Finalize,
+    Worker_MPM_MasterInterp,
+    Worker_MPM_ExitHandler
 };




---------------------------------------------------------------------
To unsubscribe, e-mail: site-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: site-cvs-help@tcl.apache.org