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 2016/01/19 19:23:23 UTC
svn commit: r1725585 - in /tcl/rivet/trunk: ChangeLog doc/rivet.xml
doc/xml/internals.xml doc/xml/lazybridge.xml src/mod_rivet/rivet_lazy_mpm.c
Author: mxmanghi
Date: Tue Jan 19 18:23:23 2016
New Revision: 1725585
URL: http://svn.apache.org/viewvc?rev=1725585&view=rev
Log:
* src/mod_rivet/rivet_lazy_mpm.c: removed unused field structures, boolean
for process shutdown moved to process wide module status
* doc/lazybridge.xml: started documentation of the lazy bridge
Added:
tcl/rivet/trunk/doc/xml/lazybridge.xml
Modified:
tcl/rivet/trunk/ChangeLog
tcl/rivet/trunk/doc/rivet.xml
tcl/rivet/trunk/doc/xml/internals.xml
tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c
Modified: tcl/rivet/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/ChangeLog?rev=1725585&r1=1725584&r2=1725585&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Tue Jan 19 18:23:23 2016
@@ -1,5 +1,10 @@
+2016-01-19 Massimo Manghi <mx...@apache.org>
+ * src/mod_rivet/rivet_lazy_mpm.c: removed unused field structures, boolean
+ for process shutdown moved to process wide module status
+ * doc/lazybridge.xml: started documentation of the lazy bridge
+
2016-01-17 Massimo Manghi <mx...@apache.org>
- * src/trunk/rivet_worker_mpm.c: removed variable needed only when built with
+ * src/mod_rivet/rivet_worker_mpm.c: removed variable needed only when built with
the old thread communication model
2016-01-14 Massimo Manghi <mx...@apache.org>
Modified: tcl/rivet/trunk/doc/rivet.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/rivet.xml?rev=1725585&r1=1725584&r2=1725585&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/rivet.xml (original)
+++ tcl/rivet/trunk/doc/rivet.xml Tue Jan 19 18:23:23 2016
@@ -28,6 +28,7 @@
<!ENTITY request.xml SYSTEM "xml/request.xml" >
<!ENTITY entities.xml SYSTEM "xml/entities.xml" >
<!ENTITY asciiglyphs.xml SYSTEM "xml/asciiglyphs.xml" >
+ <!ENTITY lazybridge.xml SYSTEM "xml/lazybridge.xml" >
]>
<!--
@@ -66,6 +67,7 @@
<year>2013</year>
<year>2014</year>
<year>2015</year>
+ <year>2016</year>
<holder>Apache Software Foundation</holder>
</copyright>
<author>
@@ -131,6 +133,9 @@
<!-- Internals -->
&internals.xml;
+ <!-- lazybridge -->
+ &lazybridge.xml;
+
<!-- Upgrade -->
&upgrade.xml;
Modified: tcl/rivet/trunk/doc/xml/internals.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/xml/internals.xml?rev=1725585&r1=1725584&r2=1725585&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/xml/internals.xml (original)
+++ tcl/rivet/trunk/doc/xml/internals.xml Tue Jan 19 18:23:23 2016
@@ -113,15 +113,19 @@
<listitem>
<emphasis>mpm_exit_handler</emphasis>: mod_rivet replaces
the core <command>exit</command> command with a new one
- (<command>::rivet::exit</command>) with a special handling of
- the process exit allowing the current request process to be finished
- interrupting the script execution and handing execution down to
- <command>AbortScript</command>. If the bridge needs to be aware of
- the exit call this is the function where special tasks can be carried out.
- With the <emphasis>worker</emphasis> MPM bridge the finalize function
+ (<command>::rivet::exit</command>). This command must handle
+ the process exit in the best possible way for the bridge and the
+ threading model it implements (for the 2 current threaded bridges this implies
+ signaling the threads to exit). The <command>::rivet::exit</command>
+ actually doesn't terminate the process, but interrupts execution
+ returning a specific error code commands <command>::rivet::catch</command>
+ and <command>::rivet::try</command> can detect. Before the process is terminated
+ the <command>AbortScript</command> script is fired and <command>::rivet::abort_code</command>
+ returns a message describing the exit condition. For instance
+ the <emphasis>worker</emphasis> MPM bridge the finalize function
is called after the current thread itself is set up for termination.
See function Rivet_ExitCmd in
- <ulink url="svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet/rivetCore.c">rivetCore.c</ulink>
+ <ulink url="http://svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet/rivetCore.c">rivetCore.c</ulink>
to have details on how and at what stage this callback is invoked.
</listitem>
<listitem>
Added: tcl/rivet/trunk/doc/xml/lazybridge.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/xml/lazybridge.xml?rev=1725585&view=auto
==============================================================================
--- tcl/rivet/trunk/doc/xml/lazybridge.xml (added)
+++ tcl/rivet/trunk/doc/xml/lazybridge.xml Tue Jan 19 18:23:23 2016
@@ -0,0 +1,141 @@
+<section id="lazybridge">
+ <title>Example: the <quote>Lazy</quote> bridge</title>
+ <para>
+ The lazy bridge was developed to show how a threaded bridge can
+ implement a simple yet almost fully functional threading model to
+ handle requests.
+ </para>
+ <para>
+ The lazy bridge implements all the functions (except for one)
+ defined in <command>rivet_bridge_table</command>. Therefore is
+ a good starting point from which take inspiration for developing
+ other threading models to handle the server workload
+ </para>
+ <programlisting>RIVET_MPM_BRIDGE {
+ NULL,
+ Lazy_MPM_ChildInit,
+ Lazy_MPM_Request,
+ Lazy_MPM_Finalize,
+ Lazy_MPM_ExitHandler,
+ Lazy_MPM_Interp
+};</programlisting>
+ <para>
+ Let's show how the bridge works starting from the basic
+ data structures that keep the bridge internal status. First
+ off let's take a look a the structure that defined the lazy
+ bridge internal status
+ </para>
+ <programlisting>/* Lazy bridge internal status data */
+
+typedef struct mpm_bridge_status {
+ apr_thread_mutex_t* mutex;
+ int exit_command;
+ int exit_command_status;
+ int server_shutdown; /* the child process is shutting down */
+ vhost* vhosts; /* array of vhost descriptors */
+} mpm_bridge_status;</programlisting>
+ <para>
+ Most of the fields in the structure are meant to deal with the <command>::rivet::exit</command>
+ command handling and the condition of shutdown that might arise from a script calling
+ <command>::rivet::exit</command> or from a process termination issued by the Apache
+ web server framework. See function <command>Lazy_MPM_ExitHandler</command> for
+ further details.
+ When the Apache HTTP Web Server starts configuration child processes are started
+ and each of them read the configuration. A fundamental information built during this
+ stage is the database of virtual hosts. The lazy bridge keeps an array of virtual host
+ descriptor pointers <command>vhosts*</command> each of them referencing an
+ instance of the following structure.
+ </para>
+ <programlisting>/* virtual host descriptor */
+
+typedef struct vhost_iface {
+ int idle_threads_cnt; /* idle threads for the virtual hosts */
+ int threads_count; /* total number of running and idle threads */
+ apr_thread_mutex_t* mutex; /* mutex protecting 'array' */
+ apr_array_header_t* array; /* LIFO array of lazy_tcl_worker pointers */
+} vhost;</programlisting>
+ <para>
+ The virtual host descriptor keeps an array of thread descriptor pointers
+ each of them referencing an instance of the <command>lazy_tcl_worker</command> structure.
+ </para>
+ <programlisting>/* lazy bridge Tcl thread status and communication variables */
+
+typedef struct lazy_tcl_worker {
+ apr_thread_mutex_t* mutex;
+ apr_thread_cond_t* condition;
+ int status;
+ apr_thread_t* thread_id;
+ server_rec* server;
+ request_rec* r;
+ int ctype;
+ int ap_sts;
+ int nreqs;
+ rivet_server_conf* conf; /* rivet_server_conf* record */
+} lazy_tcl_worker;</programlisting>
+ <para>
+ This structure keeps the basic data needed for the inter-thread communication. As in
+ the <ulink url="http://svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c">rivet_worker_mpm.c</ulink>
+ bridge request processing is done by decoupling the the module handler thread,
+ which in <ulink url="http://svn.apache.org/repos/asf/tcl/rivet/trunk/src/mod_rivet/mod_rivet.c">mod_rivet.c</ulink>
+ calls the function <command>Rivet_Handler</command>, from the Tcl worker threads doing the real work of producing output
+ and sending it to the client.
+ </para>
+ <para>
+ The Lazy bridge will not start any Tcl worker thread at server startup, but it will
+ wait for requests to come new worker threads will be created on demand only when, for a given
+ virtual host, no threads are idle and thus available for processing a request. The code is
+ in the <command>Lazy_MPM_Request</command> function
+ </para>
+ <programlisting> lazy_tcl_worker* w;
+ ...
+ 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 the array is empty we create a new worker thread */
+
+ if (apr_is_empty_array(array))
+ {
+ w = create_worker(module_globals->pool,r->server);
+ (module_globals->mpm->vhosts[conf->idx].threads_count)++;
+ }
+ else
+ {
+ w = *(lazy_tcl_worker**) apr_array_pop(array);
+ }
+ apr_thread_mutex_unlock(mutex);
+
+ ...</programlisting>
+ <para>
+
+ </para>
+ <programlisting>
+ /* 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);</programlist>
+
+ <programlisting>/* lazy bridge thread private data extension */
+
+typedef struct mpm_bridge_specific {
+ rivet_thread_interp* interp; /* thread Tcl interpreter object */
+ int keep_going; /* thread loop controlling variable */
+ /* the request_rec and TclWebRequest *
+ * are copied here to be passed to a *
+ * channel */
+} mpm_bridge_specific;</programlisting>
+ <para>
+
+ </para>
+
+
+ <para>
+
+ </para>
+ </section>
\ No newline at end of file
Modified: tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c?rev=1725585&r1=1725584&r2=1725585&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c Tue Jan 19 18:23:23 2016
@@ -67,20 +67,20 @@ typedef struct lazy_tcl_worker {
/* virtual host descriptor */
typedef struct vhost_iface {
- int idle_threads_cnt; /* */
- int threads_count;
- apr_thread_mutex_t* mutex; /* mutex protecting 'array' */
- apr_array_header_t* array; /* LIFO array of lazy_tcl_worker pointers */
- int server_shutdown;
- rivet_server_conf* conf; /* rivet_server_conf* record */
+ int idle_threads_cnt; /* idle threads for the virtual hosts */
+ int threads_count; /* total number of running and idle threads */
+ apr_thread_mutex_t* mutex; /* mutex protecting 'array' */
+ apr_array_header_t* array; /* LIFO array of lazy_tcl_worker pointers */
} vhost;
+/* Lazy bridge internal status data */
+
typedef struct mpm_bridge_status {
apr_thread_mutex_t* mutex;
- //apr_thread_cond_t* condition;
int exit_command;
int exit_command_status;
- vhost* vhosts; /* array of vhost descriptors */
+ int server_shutdown; /* the child process is shutting down */
+ vhost* vhosts; /* array of vhost descriptors */
} mpm_bridge_status;
/* lazy bridge thread private data extension */
@@ -141,7 +141,7 @@ static void* APR_THREAD_FUNC request_pro
lazy_tcl_worker* w = (lazy_tcl_worker*) data;
rivet_thread_private* private;
int idx;
- rivet_server_conf* rsc;
+ rivet_server_conf* rsc;
private = Rivet_CreatePrivateData();
if (private == NULL)
@@ -191,7 +191,7 @@ static void* APR_THREAD_FUNC request_pro
http_code = Rivet_SendContent(private,w->r);
- if (module_globals->mpm->vhosts[idx].server_shutdown) continue;
+ if (module_globals->mpm->server_shutdown) continue;
w->status = done;
w->ap_sts = http_code;
@@ -200,7 +200,7 @@ static void* APR_THREAD_FUNC request_pro
apr_thread_cond_wait(w->condition,w->mutex);
}
- // rescheduling itself in the array of idle threads
+ /* 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;
@@ -246,9 +246,6 @@ void Lazy_MPM_ChildInit (apr_pool_t* poo
rv = apr_thread_mutex_create(&module_globals->mpm->mutex,APR_THREAD_MUTEX_UNNESTED,pool);
ap_assert(rv == APR_SUCCESS);
- // rv = apr_thread_cond_create(&module_globals->mpm->condition, pool);
- // ap_assert(rv == APR_SUCCESS);
-
module_globals->mpm->vhosts = (vhost *) apr_pcalloc(pool,module_globals->vhosts_count * sizeof(vhost));
ap_assert(module_globals->mpm->vhosts != NULL);
@@ -267,9 +264,8 @@ void Lazy_MPM_ChildInit (apr_pool_t* poo
module_globals->mpm->vhosts[vh].idle_threads_cnt = 0;
module_globals->mpm->vhosts[vh].threads_count = 0;
- module_globals->mpm->vhosts[vh].server_shutdown = 0;
- module_globals->mpm->vhosts[vh].conf = rsc;
}
+ module_globals->mpm->server_shutdown = 0;
}
int Lazy_MPM_Request (request_rec* r,rivet_req_ctype ctype)
@@ -284,7 +280,7 @@ int Lazy_MPM_Request (request_rec* r,riv
array = module_globals->mpm->vhosts[conf->idx].array;
apr_thread_mutex_lock(mutex);
- if (module_globals->mpm->vhosts[conf->idx].server_shutdown == 1) {
+ 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);
@@ -311,16 +307,14 @@ int Lazy_MPM_Request (request_rec* r,riv
w->status = init;
w->conf = conf;
apr_thread_cond_signal(w->condition);
- //apr_thread_mutex_unlock(w->mutex);
- //apr_thread_mutex_lock(w->mutex);
+ /* 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;
- //apr_thread_mutex_unlock(w->mutex);
- //apr_thread_mutex_lock(w->mutex);
w->status = idle;
w->r = NULL;
apr_thread_cond_signal(w->condition);
@@ -329,6 +323,9 @@ int Lazy_MPM_Request (request_rec* r,riv
return ap_sts;
}
+/* -- Lazy_MPM_Interp
+ */
+
rivet_thread_interp* Lazy_MPM_Interp(rivet_thread_private *private,
rivet_server_conf* conf)
{
@@ -350,7 +347,7 @@ apr_status_t Lazy_MPM_Finalize (void* da
mutex = module_globals->mpm->vhosts[vh].mutex;
array = module_globals->mpm->vhosts[vh].array;
apr_thread_mutex_lock(mutex);
- module_globals->mpm->vhosts[vh].server_shutdown = 1;
+ module_globals->mpm->server_shutdown = 1;
try = 0;
do {
@@ -390,6 +387,14 @@ int Lazy_MPM_ExitHandler(int code)
private->ext->keep_going = 0;
+ /*
+ This is the only place where exit_command and
+ exit_command_status are set, anywere alse these
+ fields are only read. We lock on writing to synchronize
+ with other threads that might try to access
+ this info
+ */
+
apr_thread_mutex_lock(module_globals->mpm->mutex);
if (module_globals->mpm->exit_command == 0)
{
---------------------------------------------------------------------
To unsubscribe, e-mail: site-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: site-cvs-help@tcl.apache.org