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/12/20 19:37:11 UTC

svn commit: r1721052 - in /tcl/rivet/trunk: ChangeLog doc/xml/internals.xml src/mod_rivet/rivet_lazy_mpm.c src/mod_rivet/rivet_worker_mpm.c

Author: mxmanghi
Date: Sun Dec 20 18:37:10 2015
New Revision: 1721052

URL: http://svn.apache.org/viewvc?rev=1721052&view=rev
Log:
    * src/mod_rivet/rivet_lazy_mpm.c: first prototype of a threaded bridge with
    reduced start up time and thread number optimization


Modified:
    tcl/rivet/trunk/ChangeLog
    tcl/rivet/trunk/doc/xml/internals.xml
    tcl/rivet/trunk/src/mod_rivet/rivet_lazy_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=1721052&r1=1721051&r2=1721052&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Sun Dec 20 18:37:10 2015
@@ -1,3 +1,7 @@
+2015-12-20 Massimo Manghi <mx...@apache.org>
+    * src/mod_rivet/rivet_lazy_mpm.c: first prototype of a threaded bridge with
+    reduced start up time and thread number optimization
+
 2015-12-15 Massimo Manghi <mx...@apache.org>
     * src/mod_rivet/rivet_lazy_mpm.c: new lazy MPM bridge with a smoother workload 
     balancing (should work better for low to middle workloads)

Modified: tcl/rivet/trunk/doc/xml/internals.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/xml/internals.xml?rev=1721052&r1=1721051&r2=1721052&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/xml/internals.xml (original)
+++ tcl/rivet/trunk/doc/xml/internals.xml Sun Dec 20 18:37:10 2015
@@ -10,7 +10,7 @@
       (<command>svn</command>) can provide you with information about
       what has been happening with the code.
     </para>
-    <sect2>
+    <section>
     	<title>Rivet approach to Apache Multiprocessing Models</title>
     	<para>
     		The Apache HTTP web server has an extremely modular architecture
@@ -53,8 +53,8 @@
     		low to middle workload and many virtual hosts having a roughly uniform workload distribution.
     		This bridge should work well also for development web servers.
     	</para>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
     	<title>mod_rivet MPM Bridge callbacks</title> 
     	<para>
     		A bridge is a loadable library implementing different ways to handle
@@ -134,30 +134,15 @@
 				</listitem>
 			</itemizedlist>
 		</para>
-    </sect2>
-    <sect2>
-    	<title>MPM bridge internal status</title>
-    	<para>
-    		....
-    	</para>
-    </sect2>
+    </section>
     
-    <sect2>
-      <title>Initialization</title>
+    <section>
+      <title>Server Initialization and MPM Bridge</title>
       <para>
-			When Apache is started, (or when child Apache processes are
-			started if a threaded Tcl is used),
-			<function>Rivet_InitTclStuff</function> is called, which
-			creates a new interpreter, or one interpreter per virtual
-			host, depending on the configuration. It also initializes
-			various things, like the <structname>RivetChan</structname>
-			channel system, creates the Rivet-specific Tcl commands, and
-			executes Rivet's <filename>init.tcl</filename>.  The caching
-			system is also set up, and if there is a
-			<command>GlobalInitScript</command>, it is run.
+      	The main
       </para>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
       <title>RivetChan</title>
       <para>
 			The <structname>RivetChan</structname> system was created in
@@ -170,8 +155,8 @@
 			this channel type, so that, by default, output will go to the
 			web page. 
       </para>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
       <title>The <command>global</command> Command</title>
       <para>
 			Rivet aims to run standard Tcl code with as few surprises as
@@ -189,8 +174,8 @@
 			<command>::global</command> or add the :: namespace qualifier
 			to variables you wish to make global.
       </para>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
       <title>Page Parsing, Execution and Caching</title>
       <para>
 			When a Rivet page is requested, it is transformed into an
@@ -221,8 +206,8 @@
 	    	The number of scripts stored in memory is configurable.  This
 	    	feature can significantly improve performance.
       </para>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
         <title>Extending Rivet by developing C procedures implementing new commands</title>
         <para>
             Rivet endows the Tcl interpreter with new commands
@@ -302,8 +287,8 @@ mycmd->1</programlisting>
                 command doesn't need to test the <command>globals->r</command> pointer.
             </listitem>
         </itemizedlist>
-    </sect2>
-    <sect2>
+    </section>
+    <section>
       <title>Debugging Rivet and Apache</title>
       <para>
 			If you are interested in hacking on Rivet, you're welcome to
@@ -391,5 +376,5 @@ Starting program: /usr/sbin/apache.dbg -
 			web page with the browser, and see where things go wrong (if
 			you are dealing with a crash, for instance).
       </para>
-    </sect2>
+    </section>
   </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=1721052&r1=1721051&r2=1721052&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivet_lazy_mpm.c Sun Dec 20 18:37:10 2015
@@ -28,31 +28,170 @@
 #include <tcl.h>
 #include <ap_mpm.h>
 #include <apr_strings.h>
+#include <apr_atomic.h>
 
 #include "mod_rivet.h"
 #include "mod_rivet_common.h"
 #include "rivetChannel.h"
 #include "apache_config.h"
 
-extern mod_rivet_globals* module_globals;
-extern apr_threadkey_t*  rivet_thread_key;
-extern apr_threadkey_t*  handler_thread_key;
+extern mod_rivet_globals*   module_globals;
+extern apr_threadkey_t*     rivet_thread_key;
+extern apr_threadkey_t*     handler_thread_key;
 
 rivet_thread_private* Rivet_VirtualHostsInterps (rivet_thread_private* private);
 rivet_thread_interp*  Rivet_NewVHostInterp(apr_pool_t* pool);
 
+enum
+{
+    init,
+    idle,
+    processing,
+    thread_exit,
+    done
+};
+
+typedef struct lazy_tcl_worker {
+    apr_thread_mutex_t* mutex;
+    apr_thread_cond_t*  condition;
+    int                 status;
+    apr_thread_t*       thread_id;
+    int                 idx;
+    request_rec*        r;
+    int                 ctype;
+    int                 ap_sts;
+} lazy_tcl_worker;
+
+typedef struct vhost_iface {
+    apr_uint32_t*       idle_threads_cnt;       /* */
+    apr_queue_t*        queue;                  /* available threads  */
+} vhost;
+
+typedef struct mpm_bridge_status {
+    apr_thread_mutex_t* mutex;
+    apr_thread_cond_t*  condition;
+    void**              workers;                /* thread pool ids          */
+    int                 exit_command;
+    int                 exit_command_status;
+    vhost*              vhosts;
+} mpm_bridge_status;
+
 #define DEFAULT_HEADER_TYPE "text/html"
 #define BASIC_PAGE          "<b>Lazy Bridge</b>"
 
+#define MOD_RIVET_QUEUE_SIZE        100
+
+static void* APR_THREAD_FUNC request_processor (apr_thread_t *thd, void *data)
+{
+    lazy_tcl_worker* w = (lazy_tcl_worker*) data; 
+
+    do 
+    {
+        apr_queue_push(module_globals->mpm->vhosts[w->idx].queue,w);
+        apr_atomic_inc32(module_globals->mpm->vhosts[w->idx].idle_threads_cnt);
+        apr_thread_mutex_lock(w->mutex);
+        do {
+            apr_thread_cond_wait(w->condition,w->mutex);
+        } while (w->status != init);
+
+        apr_atomic_dec32(module_globals->mpm->vhosts[w->idx].idle_threads_cnt);
+        w->status = processing;
+        apr_thread_mutex_unlock(w->mutex);
+
+        /* Content generation */
+
+        ap_set_content_type(w->r,apr_pstrdup(w->r->pool,DEFAULT_HEADER_TYPE));
+        ap_send_http_header(w->r);
+        ap_rwrite(apr_pstrdup(w->r->pool,BASIC_PAGE),strlen(BASIC_PAGE),w->r);
+        ap_rflush(w->r);
+
+        apr_thread_mutex_lock(w->mutex);
+        w->status = done;
+        w->ap_sts = OK;
+        apr_thread_cond_signal(w->condition);
+        apr_thread_mutex_unlock(w->mutex);
+
+        apr_thread_mutex_lock(w->mutex);
+        do {
+            apr_thread_cond_wait(w->condition,w->mutex);
+        } while (w->status == done);
+
+        w->status = idle;
+        w->r      = NULL;
+        apr_thread_mutex_unlock(w->mutex);
+
+    } while (1);
+
+    return NULL;
+}
+
+static lazy_tcl_worker* create_worker (apr_pool_t* pool,int idx)
+{
+    lazy_tcl_worker*    w;
+
+    w = apr_pcalloc(pool,sizeof(lazy_tcl_worker));
+
+    w->status = idle;
+    w->idx = idx;
+    ap_assert(apr_thread_mutex_create(&w->mutex,APR_THREAD_MUTEX_UNNESTED,pool) == APR_SUCCESS);
+    ap_assert(apr_thread_cond_create(&w->condition, pool) == APR_SUCCESS); 
+    apr_thread_create(&w->thread_id, NULL, request_processor, w, module_globals->pool);
+
+    return w;
+}
+
+void Lazy_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
+{
+    apr_status_t    rv;
+    int             vh;
+
+    apr_atomic_init(pool);
+    module_globals->mpm = apr_pcalloc(pool,sizeof(mpm_bridge_status));
+
+    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);
+
+    /*
+    apr_atomic_set32(module_globals->mpm->first_available,0);
+    */
+
+    for (vh = 0; vh < module_globals->vhosts_count; vh++)
+    {
+        module_globals->mpm->vhosts[vh].idle_threads_cnt = 
+                (apr_uint32_t *) apr_pcalloc(pool,sizeof(apr_uint32_t));
+
+        apr_atomic_set32(module_globals->mpm->vhosts[vh].idle_threads_cnt,0);
+        ap_assert (apr_queue_create(&module_globals->mpm->vhosts[vh].queue,
+                    MOD_RIVET_QUEUE_SIZE,module_globals->pool) != APR_SUCCESS);
+        
+        create_worker(pool,vh);
+    }
+}
+
 int Lazy_MPM_Request (request_rec* r,rivet_req_ctype ctype)
 {
-    ap_set_content_type(r,apr_pstrdup(r->pool,DEFAULT_HEADER_TYPE));
-    ap_send_http_header(r);
+    lazy_tcl_worker*    w;
+    apr_status_t        rv;
 
-    ap_rwrite(apr_pstrdup(r->pool,BASIC_PAGE),strlen(BASIC_PAGE),r);
-    ap_rflush(r);
+    do {
+        rv = apr_queue_pop(module_globals->mpm->vhosts[w->idx].queue, (void *)&w);
 
-    return OK;
+    } while (rv == APR_EINTR);
+
+    apr_thread_mutex_lock(w->mutex);
+    w->r        = r;
+    w->ctype    = ctype;
+    w->status   = init;
+    apr_thread_cond_signal(w->condition);
+
+    do {
+        apr_thread_cond_wait(w->condition,w->mutex);
+    } while (w->status != done);
+
+    apr_thread_mutex_unlock(w->mutex);
+    return w->ap_sts;
 }
 
 rivet_thread_interp* Lazy_MPM_MasterInterp(void)
@@ -62,7 +201,7 @@ rivet_thread_interp* Lazy_MPM_MasterInte
 
 RIVET_MPM_BRIDGE {
     NULL,
-    NULL,
+    Lazy_MPM_ChildInit,
     Lazy_MPM_Request,
     NULL,
     Lazy_MPM_MasterInterp,

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=1721052&r1=1721051&r2=1721052&view=diff
==============================================================================
--- tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c (original)
+++ tcl/rivet/trunk/src/mod_rivet/rivet_worker_mpm.c Sun Dec 20 18:37:10 2015
@@ -68,7 +68,6 @@ typedef struct mpm_bridge_status {
     void**              workers;                /* thread pool ids          */
     int                 exit_command;
     int                 exit_command_status;
-
     int                 max_threads;
     int                 min_spare_threads;
     int                 max_spare_threads;
@@ -87,7 +86,7 @@ typedef struct _handler_private
     request_rec*            r;              /* request rec                 */
     int                     code;
     int                     status;
-    rivet_req_ctype         ctype;          /*                             */
+    rivet_req_ctype         ctype;
 } handler_private;
 
 typedef int rivet_thr_status;
@@ -226,7 +225,7 @@ static void* APR_THREAD_FUNC request_pro
 
             if (rv == APR_EOF) {
                 fprintf(stderr, "request_processor: queue terminated APR_EOF\n");
-                rv=APR_SUCCESS;
+                rv = APR_SUCCESS;
             }
             else 
             {
@@ -271,7 +270,6 @@ static void* APR_THREAD_FUNC request_pro
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, module_globals->server, "processor thread orderly exit");
 
     // 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);
@@ -456,9 +454,11 @@ static void* APR_THREAD_FUNC threaded_br
 void Worker_MPM_ChildInit (apr_pool_t* pool, server_rec* server)
 {
     apr_status_t        rv;
+    
+    apr_atomic_init(pool);
 
 #ifdef RIVET_SERIALIZE_HTTP_REQUESTS
-    apr_thread_mutex_create(&module_globals->req_mutex, APR_THREAD_MUTEX_UNNESTED, pChild);
+    apr_thread_mutex_create(&module_globals->req_mutex, APR_THREAD_MUTEX_UNNESTED, pool);
 #endif
 
     /* First of all we allocate and initialize the mpm status */
@@ -479,18 +479,17 @@ void Worker_MPM_ChildInit (apr_pool_t* p
 
     /* 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);
     apr_atomic_set32(module_globals->mpm->running_threads_count,0);
 
-    ap_assert(apr_thread_mutex_create(&module_globals->mpm->job_mutex, APR_THREAD_MUTEX_UNNESTED, pool) == APR_SUCCESS);
-    ap_assert(apr_thread_cond_create(&module_globals->mpm->job_cond, pool) == APR_SUCCESS);
+    ap_assert(apr_thread_mutex_create(&module_globals->mpm->job_mutex,APR_THREAD_MUTEX_UNNESTED,pool) == APR_SUCCESS);
+    ap_assert(apr_thread_cond_create(&module_globals->mpm->job_cond,pool) == APR_SUCCESS);
 
     /* This is the thread key for the framework thread calling the content generation callback */
 
-    ap_assert (apr_threadkey_private_create (&handler_thread_key, NULL, pool) == APR_SUCCESS);
+    ap_assert (apr_threadkey_private_create(&handler_thread_key,NULL,pool) == APR_SUCCESS);
 
     /* This bridge keeps an array of the ids of threads about to exit. This array is protected by
      * the mutex module_globals->job_mutex and signals through module_globals->job_cond



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