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