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