fix typos, broken links and add extended lazy bridge documentation
diff --git a/rivet/manual3.0/index.html b/rivet/manual3.0/index.html
index b9dfc0c..22a2751 100644
--- a/rivet/manual3.0/index.html
+++ b/rivet/manual3.0/index.html
@@ -1,6 +1,6 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Apache Rivet 3.0</title><link rel="stylesheet" type="text/css" href="rivet.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="index.html" title="Apache Rivet 3.0"><link rel="next" href="installation.html" title="Apache Rivet 3.0 Installation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Apache Rivet 3.0</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="installation.html"><img src="images/next.png" alt="Next"></a></td></tr></table></div><div class="article"><div class="titlepage"><div><div><h2 class="title"><a name="idm1"></a>Apache Rivet 3.0</h2></div><div><div class="author"><h3 class="author"><span class="firstname">The Rivet Team</span></h3><div class="affiliation"><span class="orgname">The Apache Software Foundation<br></span><div class="address"><p><br>
<code class="email"><<a class="email" href="mailto:rivet-dev@tcl.apache.org">rivet-dev@tcl.apache.org</a>></code><br>
- </p></div></div></div></div><div><p class="copyright">Copyright © 2002-2017 Apache Software Foundation</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="index.html#introduction">Introduction to Apache Rivet version 3.0</a></span></dt><dt><span class="section"><a href="installation.html">Apache Rivet 3.0 Installation</a></span></dt><dt><span class="section"><a href="cmake.html">Building Rivet 3.0 with CMake</a></span></dt><dd><dl><dt><span class="section"><a href="cmake.html#idm185">CMake build procedure and examples</a></span></dt></dl></dd><dt><span class="section"><a href="directives.html">Apache Rivet 3.0 Configuration</a></span></dt><dd><dl><dt><span class="section"><a href="directives.html#idm200">Apache Rivet Configuration lines</a></span></dt><dt><span class="section"><a href="directives.html#idm212">Configuration Directives</a></span></dt></dl></dd><dt><span class="section"><a href="processing.html">Apache Rivet HTTP Request Processing</a></span></dt><dd><dl><dt><span class="section"><a href="processing.html#idm574">Tcl Scripts Processing</a></span></dt><dt><span class="section"><a href="processing.html#idm583">Example: basic OO Rivet Application</a></span></dt></dl></dd><dt><span class="section"><a href="request.html">Apache Child Processes Lifecycle and Request Processing</a></span></dt><dt><span class="section"><a href="commands.html">Rivet Tcl Commands and Variables</a></span></dt><dd><dl><dt><span class="section"><a href="commands.html#idm719"></a></span></dt><dt><span class="refentrytitle"><a href="shorthand.html"><?= ... ?></a></span><span class="refpurpose"> —
+ </p></div></div></div></div><div><p class="copyright">Copyright © 2002-2018 Apache Software Foundation</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="index.html#introduction">Introduction to Apache Rivet version 3.0</a></span></dt><dt><span class="section"><a href="installation.html">Apache Rivet 3.0 Installation</a></span></dt><dt><span class="section"><a href="cmake.html">Building Rivet 3.0 with CMake</a></span></dt><dd><dl><dt><span class="section"><a href="cmake.html#idm185">CMake build procedure and examples</a></span></dt></dl></dd><dt><span class="section"><a href="directives.html">Apache Rivet 3.0 Configuration</a></span></dt><dd><dl><dt><span class="section"><a href="directives.html#idm200">Apache Rivet Configuration lines</a></span></dt><dt><span class="section"><a href="directives.html#idm212">Configuration Directives</a></span></dt></dl></dd><dt><span class="section"><a href="processing.html">Apache Rivet HTTP Request Processing</a></span></dt><dd><dl><dt><span class="section"><a href="processing.html#idm574">Tcl Scripts Processing</a></span></dt><dt><span class="section"><a href="processing.html#idm583">Example: basic OO Rivet Application</a></span></dt></dl></dd><dt><span class="section"><a href="request.html">Apache Child Processes Lifecycle and Request Processing</a></span></dt><dt><span class="section"><a href="commands.html">Rivet Tcl Commands and Variables</a></span></dt><dd><dl><dt><span class="section"><a href="commands.html#idm719"></a></span></dt><dt><span class="refentrytitle"><a href="shorthand.html"><?= ... ?></a></span><span class="refpurpose"> —
Shorthand construct for single strings output
</span></dt><dt><span class="refentrytitle"><a href="abort_code.html">abort_code</a></span><span class="refpurpose"> —
Returns the code passed to <span style="font-family:monospace"><span class="command"><strong>abort_page</strong></span></span>
@@ -39,7 +39,7 @@
</span></dt><dt><span class="section"><a href="asciiglyphs.html#idm4177">Example</a></span></dt></dl></dd><dt><span class="section"><a href="formbroker.html">The Form Broker</a></span></dt><dd><dl><dt><span class="section"><a href="formbroker.html#idm4182">Introduction</a></span></dt><dt><span class="refentrytitle"><a href="fb.html">FormBroker</a></span><span class="refpurpose"> —
Form broker object creator
</span></dt></dl></dd><dt><span class="section"><a href="help.html">Resources - How to Get Help</a></span></dt><dd><dl><dt><span class="section"><a href="help.html#idm4310">Mailing Lists</a></span></dt><dt><span class="section"><a href="help.html#idm4317">Newsgroup</a></span></dt><dt><span class="section"><a href="help.html#websites">Web Sites</a></span></dt><dt><span class="section"><a href="help.html#idm4337">Bug Tracking System</a></span></dt><dt><span class="section"><a href="help.html#idm4341">IRC</a></span></dt><dt><span class="section"><a href="help.html#idm4344">Editing Rivet Template Files</a></span></dt></dl></dd><dt><span class="section"><a href="internals.html">Rivet Internals</a></span></dt><dd><dl><dt><span class="section"><a href="internals.html#idm4356">Rivet approach to Apache Multiprocessing Models</a></span></dt><dt><span class="section"><a href="internals.html#idm4369">mod_rivet MPM Bridge callbacks</a></span></dt><dt><span class="section"><a href="internals.html#idm4403">Server Initialization and MPM Bridge</a></span></dt><dt><span class="section"><a href="internals.html#idm4406">RivetChan</a></span></dt><dt><span class="section"><a href="internals.html#idm4411">The <span style="font-family:monospace"><span class="command"><strong>global</strong></span></span> Command</a></span></dt><dt><span class="section"><a href="internals.html#idm4419">Page Parsing, Execution and Caching</a></span></dt><dt><span class="section"><a href="internals.html#idm4427">Extending Rivet by developing C code procedures</a></span></dt><dt><span class="section"><a href="internals.html#idm4451">Debugging Rivet and Apache</a></span></dt></dl></dd><dt><span class="section"><a href="lazybridge.html">Example: the <span class="quote">“<span class="quote">Lazy</span>”</span> bridge</a></span></dt><dd><dl><dt><span class="section"><a href="lazybridge.html#idm4481">The rationale of threaded bridges</a></span></dt><dt><span class="section"><a href="lazybridge.html#idm4485">Lazy bridge data structures</a></span></dt><dt><span class="section"><a href="lazybridge.html#idm4500">Handling Tcl's exit core command</a></span></dt><dt><span class="section"><a href="lazybridge.html#idm4519">HTTP request processing with the lazy bridge</a></span></dt></dl></dd></dl></div><div class="list-of-examples"><p><b>List of Examples</b></p><dl><dt>1. <a href="examples.html#hello_world">Hello World</a></dt><dt>2. <a href="examples.html#idm1925">Generate a Colorful Table</a></dt><dt>3. <a href="examples.html#variable_access">Variable Access</a></dt><dt>4. <a href="examples.html#file_upload">File Upload</a></dt><dt>5. <a href="examples.html#file_download">File Download</a></dt><dt>6. <a href="examples.html#ajax_xml_messaging">XML Messages and Ajax</a></dt><dt>7. <a href="examples.html#calendar_example">A Calendar Utility</a></dt></dl></div><p style="width:90%">
- Document revision: $Revision: 1819787 $, last modified 2018-01-09 23:03:42+01:00$ by $Author: mxmanghi $.
+ Document revision: $Revision: 1821687 $, last modified 2018-01-19 22:03:12+01:00$ by $Author: mxmanghi $.
</p><div class="section"><div class="titlepage"><div><div><hr><h2 class="title" style="clear: both"><a name="introduction"></a>Introduction to Apache Rivet version 3.0</h2></div></div></div><p style="width:90%">
Apache Rivet is a system for creating dynamic web content by
integrating the
@@ -75,7 +75,7 @@
modular itself, introducing the MPM-module bridge concept.
We developed a set of loadable modules
which are supposed not only to overcome the issues related to threading but also
- the best possible MPM mod_rivet integration.
+ to offer the best possible MPM mod_rivet integration.
As a side effect of this modular design mod_rivet is not only able to integrate
with its environment but also to work as a framework for writing more MPM bridges
designed along different multi-threading schemes and workload management models.
diff --git a/rivet/manual3.0/installation.html b/rivet/manual3.0/installation.html
index 31f9481..10fd4b9 100644
--- a/rivet/manual3.0/installation.html
+++ b/rivet/manual3.0/installation.html
@@ -3,7 +3,7 @@
It is known to build and run on various Linux distributions
(Debian & Ubuntu, Redhat, SuSE and CentOS), FreeBSD and OpenBSD. For some
of these Unix-like operative systems
- <a class="ulink" href="http://tcl.apache.org/rivet/static/download.html" target="_top">binary packages</a>
+ <a class="ulink" href="http://tcl.apache.org/rivet/html/download.html" target="_top">binary packages</a>
are already available for download.
</p><p style="width:90%">
Rivet 2.x was restricted to work with the
@@ -45,11 +45,11 @@
to build mod_rivet
</p><p style="width:90%">
The
- <a class="ulink" href="" target="_top">Apache HTTP Webserver</a> development
+ <a class="ulink" href="http://httpd.apache.org/" target="_top">Apache HTTP Webserver</a> development
files and libraries are required along with the
- <a class="ulink" href="" target="_top">Apache Portable Runtime</a>
+ <a class="ulink" href="http://apr.apache.org/" target="_top">Apache Portable Runtime</a>
and the
- <a class="ulink" href="" target="_top">libapreq</a> library.
+ <a class="ulink" href="http://httpd.apache.org/apreq/" target="_top">libapreq</a> library.
</p></li><li class="step"><p class="title"><b>Building Rivet</b></p></li><li class="step"><p class="title"><b>Getting and Installing the Apache Sources</b></p><p style="width:90%">
You can build Rivet either statically (compiled into the Apache web
server) or dynamically (as a loadable shared library).
diff --git a/rivet/manual3.0/internals.html b/rivet/manual3.0/internals.html
index 0ac2cbf..7f5984c 100644
--- a/rivet/manual3.0/internals.html
+++ b/rivet/manual3.0/internals.html
@@ -30,14 +30,14 @@
loadable modules that are responsible to adapt the module procedural design to
a given class of Apache MPMs. This design is open to the development of more
MPM bridges coping with different multi-processing models but also to the development of
- different approaches to resource consumption and workload balance. By now we have only 2 bridges:
+ different approaches to resource consumption and workload balance. By now we have 3 bridges:
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">rivet_prefork_mpm.c: a bridge for the prefork MPM</li><li class="listitem">rivet_worker_mpm.c: a threaded bridge creating a pool of threads
each running Tcl interpreters and communicating with the worker MPM threads
through a thread safe queue. This bridge is needed by the worker MPM.</li><li class="listitem">rivet_lazy_mpm.c: a threaded bridge where Tcl threads are
started <span class="quote">“<span class="quote">on demand</span>”</span>. The bridge creates no threads and Tcl interpreters
at start up and only when requests come in Tcl execution threads are created.
This bridge is explained in detail in the <a class="xref" href="lazybridge.html" title="Example: the “Lazy” bridge">the section called “Example: the <span class="quote">“<span class="quote">Lazy</span>”</span> bridge”</a>.
- Since the resource demand at startup is minimal this bridge should work well on
+ Since the resource demand at startup is minimal this bridge should suite
development machines that go through frequent web server restarts.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4369"></a>mod_rivet MPM Bridge callbacks</h3></div></div></div><p style="width:90%">
A bridge is a loadable library implementing different ways to handle
specific features needed to mod_rivet. It was originally meant as a way
@@ -104,7 +104,7 @@
the <span class="emphasis"><em>worker</em></span> MPM bridge the finalize function
is called after the current thread itself is set up for termination.
See function Rivet_ExitCmd in
- <a class="ulink" href="http://svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet/rivetCore.c" target="_top">rivetCore.c</a>
+ <a class="ulink" href="https://svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet_ng/rivetCore.c" target="_top">rivetCore.c</a>
to have details on how and at what stage this callback is invoked.
</li><li class="listitem"><span class="emphasis"><em>mpm_thread_interp</em></span> must be a function returning
the interpreter object (a pointer to record of type
@@ -200,12 +200,12 @@
in order to write a new C language command for mod_rivet
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
Define the command and associated C language procedure
- in src/rivetcmds/rivetCore.c using the macro
+ in src/mod_rivet_ng/rivetCore.c using the macro
RIVET_OBJ_CMD<pre class="programlisting">RIVET_OBJ_CMD("mycmd",Rivet_MyCmd,private)</pre>
This macro ensures the command is defined as <span style="font-family:monospace"><span class="command"><strong>::rivet::mycmd</strong></span></span>
and its ClientData pointer is defined with the thread private data
</li><li class="listitem">
- Add the code of Rivet_MyCmd to src/rivetcmd/rivetCore.c (in case
+ Add the code of Rivet_MyCmd to src/mod_rivet_ng/rivetCore.c (in case
the code resides in a different file also src/Makefile.am should be
changed to tell the build system how to compile the code and
link it into mod_rivet.so)
diff --git a/rivet/manual3.0/lazybridge.html b/rivet/manual3.0/lazybridge.html
index 009d0de..5c3fa66 100644
--- a/rivet/manual3.0/lazybridge.html
+++ b/rivet/manual3.0/lazybridge.html
@@ -71,13 +71,66 @@
<span style="font-family:monospace"><span class="command"><strong>mpm_child_init</strong></span></span> in
the <span style="font-family:monospace"><span class="command"><strong>rivet_bridge_table</strong></span></span> structure. For the lazy bridge this field
in the jump table points to <span style="font-family:monospace"><span class="command"><strong>Lazy_MPM_ChildInit</strong></span></span>
- </p><pre class="programlisting">void Lazy_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
+ </p><pre class="programlisting">/*
+ * -- Lazy_MPM_ChildInit
+ *
+ * child process initialization. This function prepares the process
+ * data structures for virtual hosts and threads management
+ *
+ */
+
+void Lazy_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
{
- ...
-
+ apr_status_t rv;
+ server_rec* s;
+ server_rec* root_server = module_globals->server;
+
module_globals->mpm = apr_pcalloc(pool,sizeof(mpm_bridge_status));
-
- ....
+
+ /* This mutex is only used to consistently
+ *
+ * - set the exit status of a child process (hopefully will be
+ * unnecessary when Tcl is able again of calling
+ * Tcl_DeleteInterp safely)
+ * - control the server_shutdown flag. Actually this is
+ * not entirely needed because once set this flag
+ * is never reset to 0
+ *
+ */
+
+ rv = apr_thread_mutex_create(&module_globals->mpm->mutex,
+ APR_THREAD_MUTEX_UNNESTED,pool);
+ ap_assert(rv == APR_SUCCESS);
+
+ /* the mpm->vhosts array is created with as many entries as the number of
+ * configured virtual hosts */
+
+ module_globals->mpm->vhosts =
+ (vhost *) apr_pcalloc(pool,module_globals->vhosts_count*sizeof(vhost));
+ ap_assert(module_globals->mpm->vhosts != NULL);
+
+ /*
+ * Each virtual host descriptor has its own mutex controlling
+ * the queue of available threads
+ */
+
+ for (s = root_server; s != NULL; s = s->next)
+ {
+ int vh;
+ apr_array_header_t* array;
+ rivet_server_conf* rsc = RIVET_SERVER_CONF(s->module_config);
+
+ vh = rsc->idx;
+ rv = apr_thread_mutex_create(&module_globals->mpm->vhosts[vh].mutex,
+ APR_THREAD_MUTEX_UNNESTED,pool);
+ ap_assert(rv == APR_SUCCESS);
+ array = apr_array_make(pool,0,sizeof(void*));
+ ap_assert(array != NULL);
+ module_globals->mpm->vhosts[vh].array = array;
+ module_globals->mpm->vhosts[vh].idle_threads_cnt = 0;
+ module_globals->mpm->vhosts[vh].threads_count = 0;
+ }
+ module_globals->mpm->server_shutdown = 0;
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idm4500"></a>Handling Tcl's exit core command</h3></div></div></div><p style="width:90%">
Most of the fields in the <span style="font-family:monospace"><span class="command"><strong>mpm_bridge_status</strong></span></span> are meant to deal
with the child exit process. Rivet supersedes the Tcl core's exit function
@@ -133,7 +186,7 @@
int ctype;
int ap_sts;
int nreqs;
- rivet_server_conf* conf; /* rivet_server_conf* record */
+ rivet_server_conf* conf; /* rivet_server_conf* record */
} lazy_tcl_worker;</pre><p style="width:90%">
The server field is assigned with the virtual host server record. Whereas the <span style="font-family:monospace"><span class="command"><strong>conf</strong></span></span>
field keeps the pointer to a run time computed <span style="font-family:monospace"><span class="command"><strong>rivet_server_conf</strong></span></span>. This structure
@@ -145,17 +198,34 @@
a lazy_tcl_worker pointer from the related array in the virtual hosts database or,
in case the array is empty and no threads are available, a new worker thread is
created. The code in the <span style="font-family:monospace"><span class="command"><strong>Lazy_MPM_Request</strong></span></span> function
- </p><pre class="programlisting"> lazy_tcl_worker* w;
- ...
+ </p><pre class="programlisting">/* -- Lazy_MPM_Request
+ *
+ * The lazy bridge HTTP request function. This function
+ * stores the request_rec pointer into the lazy_tcl_worker
+ * structure which is used to communicate with a worker thread.
+ * Then the array of idle threads is checked and if empty
+ * a new thread is created by calling create_worker
+ */
+
+int Lazy_MPM_Request (request_rec* r,rivet_req_ctype ctype)
+{
+ lazy_tcl_worker* w;
+ int ap_sts;
+ rivet_server_conf* conf = RIVET_SERVER_CONF(r->server->module_config);
apr_array_header_t* array;
apr_thread_mutex_t* mutex;
mutex = module_globals->mpm->vhosts[conf->idx].mutex;
array = module_globals->mpm->vhosts[conf->idx].array;
apr_thread_mutex_lock(mutex);
-
- ...
-
+
+ if (module_globals->mpm->server_shutdown == 1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
+ MODNAME ": http request aborted during child process shutdown");
+ apr_thread_mutex_unlock(mutex);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
/* If the array is empty we create a new worker thread */
if (apr_is_empty_array(array))
@@ -167,18 +237,146 @@
{
w = *(lazy_tcl_worker**) apr_array_pop(array);
}
- apr_thread_mutex_unlock(mutex);
- ...</pre><p style="width:90%">
- After a request is processed the Tcl worker thread returns its own
+ apr_thread_mutex_unlock(mutex);
+
+ apr_thread_mutex_lock(w->mutex);
+ w->r = r;
+ w->ctype = ctype;
+ w->status = init;
+ w->conf = conf;
+ apr_thread_cond_signal(w->condition);
+
+ /* we wait for the Tcl worker thread to finish its job */
+
+ while (w->status != done) {
+ apr_thread_cond_wait(w->condition,w->mutex);
+ }
+ ap_sts = w->ap_sts;
+
+ w->status = idle;
+ w->r = NULL;
+ apr_thread_cond_signal(w->condition);
+ apr_thread_mutex_unlock(w->mutex);
+
+ return ap_sts;
+}</pre><p style="width:90%">
+ After a request is processed the worker thread returns its own
lazy_tcl_worker descriptor to the array and then waits
on the condition variable used to control and synchronize the bridge
- threads with the Apache worker threads.
- </p><pre class="programlisting"> /* rescheduling itself in the array of idle threads */
+ threads with the Apache worker threads. The worker thread code
+ is the request_processor function
+ </p><pre class="programlisting">*
+ * -- request_processor
+ *
+ * The lazy bridge worker thread. This thread prepares its control data and
+ * will serve requests addressed to a given virtual host. Virtual host server
+ * data are stored in the lazy_tcl_worker structure stored in the generic
+ * pointer argument 'data'
+ *
+ */
+
+static void* APR_THREAD_FUNC request_processor (apr_thread_t *thd, void *data)
+{
+ lazy_tcl_worker* w = (lazy_tcl_worker*) data;
+ rivet_thread_private* private;
+ int idx;
+ rivet_server_conf* rsc;
+
+ /* The server configuration */
+
+ rsc = RIVET_SERVER_CONF(w->server->module_config);
+
+ /* Rivet_ExecutionThreadInit creates and returns the thread private data. */
+
+ private = Rivet_ExecutionThreadInit();
+
+ /* A bridge creates and stores in private->ext its own thread private
+ * data. The lazy bridge is no exception. We just need a flag controlling
+ * the execution and an intepreter control structure */
+
+ private->ext = apr_pcalloc(private->pool,sizeof(mpm_bridge_specific));
+ private->ext->keep_going = 1;
+ private->ext->interp = Rivet_NewVHostInterp(private->pool,w->server);
+ private->ext->interp->channel = private->channel;
+
+ /* The worker thread can respond to a single request at a time therefore
+ must handle and register its own Rivet channel */
+
+ Tcl_RegisterChannel(private->ext->interp->interp,*private->channel);
+
+ /* From the rivet_server_conf structure we determine what scripts we
+ * are using to serve requests */
+
+ private->ext->interp->scripts =
+ Rivet_RunningScripts (private->pool,private->ext->interp->scripts,rsc);
+
+ /* This is the standard Tcl interpreter initialization */
+
+ Rivet_PerInterpInit(private->ext->interp,private,w->server,private->pool);
+
+ /* The child initialization is fired. Beware of the terminologic
+ * trap: we inherited from prefork only modules the term 'child'
+ * meaning 'child process'. In this case the child init actually
+ * is a worker thread initialization, because in a threaded module
+ * this is the agent playing the same role a child process plays
+ * with the prefork bridge */
+
+ Lazy_RunConfScript(private,w,child_init);
+
+ /* The thread is now set up to serve request within the the
+ * do...while loop controlled by private->keep_going */
+
+ idx = w->conf->idx;
+ apr_thread_mutex_lock(w->mutex);
+ do
+ {
+ module_globals->mpm->vhosts[idx].idle_threads_cnt++;
+ while ((w->status != init) && (w->status != thread_exit)) {
+ apr_thread_cond_wait(w->condition,w->mutex);
+ }
+ if (w->status == thread_exit) {
+ private->ext->keep_going = 0;
+ continue;
+ }
+
+ w->status = processing;
+ module_globals->mpm->vhosts[idx].idle_threads_cnt--;
+
+ /* Content generation */
+
+ private->req_cnt++;
+ private->ctype = w->ctype;
+
+ w->ap_sts = Rivet_SendContent(private,w->r);
+
+ if (module_globals->mpm->server_shutdown) continue;
+
+ w->status = done;
+ apr_thread_cond_signal(w->condition);
+ while (w->status == done) {
+ apr_thread_cond_wait(w->condition,w->mutex);
+ }
+
+ /* rescheduling itself in the array of idle threads */
- apr_thread_mutex_lock(module_globals->mpm->vhosts[idx].mutex);
- *(lazy_tcl_worker **) apr_array_push(module_globals->mpm->vhosts[idx].array) = w;
- apr_thread_mutex_unlock(module_globals->mpm->vhosts[idx].mutex);</pre><p style="width:90%">
+ apr_thread_mutex_lock(module_globals->mpm->vhosts[idx].mutex);
+ *(lazy_tcl_worker **) apr_array_push(module_globals->mpm->vhosts[idx].array) = w;
+ apr_thread_mutex_unlock(module_globals->mpm->vhosts[idx].mutex);
+
+ } while (private->ext->keep_going);
+ apr_thread_mutex_unlock(w->mutex);
+
+ ap_log_error(APLOG_MARK,APLOG_DEBUG,APR_SUCCESS,w->server,"processor thread orderly exit");
+ Lazy_RunConfScript(private,w,child_exit);
+
+ apr_thread_mutex_lock(module_globals->mpm->vhosts[idx].mutex);
+ (module_globals->mpm->vhosts[idx].threads_count)--;
+ apr_thread_mutex_unlock(module_globals->mpm->vhosts[idx].mutex);
+
+ apr_thread_exit(thd,APR_SUCCESS);
+ return NULL;
+}</pre><p style="width:90%">
The lazy bridge <span style="font-family:monospace"><span class="command"><strong>module_globals->bridge_jump_table->mpm_thread_interp</strong></span></span>, which
is supposed to return the rivet_thread_interp structure pointer relevant to a given
request, has a straightforward task to do since by design each thread has