You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tcl.apache.org by mx...@apache.org on 2019/06/25 16:05:11 UTC

[tcl-rivet] branch single-thread-exit updated: Further simplifications ported from branch quattuor

This is an automated email from the ASF dual-hosted git repository.

mxmanghi pushed a commit to branch single-thread-exit
in repository https://gitbox.apache.org/repos/asf/tcl-rivet.git


The following commit(s) were added to refs/heads/single-thread-exit by this push:
     new 1789515  Further simplifications ported from branch quattuor
1789515 is described below

commit 178951532c9cf09a6476dd63eef8f3828d808a23
Author: Massimo Manghi <mx...@apache.org>
AuthorDate: Tue Jun 25 18:04:56 2019 +0200

    Further simplifications ported from branch quattuor
---
 ChangeLog                            |   2 +
 src/mod_rivet_ng/rivet_lazy_mpm.c    |  82 ++++++++++++++++++-----
 src/mod_rivet_ng/rivet_prefork_mpm.c |  28 ++++----
 src/mod_rivet_ng/rivet_worker_mpm.c  | 126 ++++++++++++++++++++++++++---------
 4 files changed, 174 insertions(+), 64 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7d83e1a..5bbfeae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2019-06-25 Massimo Manghi <mx...@apache.org>
     * : Single thread exit implementation for mod_rivet 3.2
+    * src/mod_rivet_ng/rivet_[.*]_mpm.c: further simplified code by removing 
+    redundant flags. Changing function names scheme
 
 2019-05-24 Massimo Manghi <mx...@apache.org>
     * src/mod_rivet_ng/rivetCore.c: Add Tcl_DecrRefCnt after
diff --git a/src/mod_rivet_ng/rivet_lazy_mpm.c b/src/mod_rivet_ng/rivet_lazy_mpm.c
index f1e569d..f5bc6df 100644
--- a/src/mod_rivet_ng/rivet_lazy_mpm.c
+++ b/src/mod_rivet_ng/rivet_lazy_mpm.c
@@ -74,8 +74,6 @@ typedef struct vhost_iface {
 
 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;
@@ -221,7 +219,7 @@ static void* APR_THREAD_FUNC request_processor (apr_thread_t *thd, void *data)
 
         w->ap_sts = Rivet_SendContent(private);
 
-        if (module_globals->mpm->server_shutdown) continue;
+        // if (module_globals->mpm->server_shutdown) continue;
 
         w->status = done;
         apr_thread_cond_signal(w->condition);
@@ -276,14 +274,14 @@ static lazy_tcl_worker* create_worker (apr_pool_t* pool,server_rec* server)
 }
 
 /*
- * -- Lazy_Bridge_ChildInit
+ * -- LazyBridge_ChildInit
  * 
  * child process initialization. This function prepares the process
  * data structures for virtual hosts and threads management
  *
  */
 
-void Lazy_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
+void LazyBridge_ChildInit (apr_pool_t* pool, server_rec* server)
 {
     apr_status_t    rv;
     server_rec*     s;
@@ -338,7 +336,7 @@ void Lazy_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
     module_globals->mpm->server_shutdown = 0;
 }
 
-/* -- Lazy_Bridge_Request
+/* -- LazyBridge_Request
  *
  * The lazy bridge HTTP request function. This function 
  * stores the request_rec pointer into the lazy_tcl_worker
@@ -347,7 +345,7 @@ void Lazy_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
  * a new thread is created by calling create_worker
  */
 
-int Lazy_Bridge_Request (request_rec* r,rivet_req_ctype ctype)
+int LazyBridge_Request (request_rec* r,rivet_req_ctype ctype)
 {
     lazy_tcl_worker*    w;
     int                 ap_sts;
@@ -410,11 +408,11 @@ int Lazy_Bridge_Request (request_rec* r,rivet_req_ctype ctype)
     return ap_sts;
 }
 
-/* -- Lazy_Bridge_Interp: lazy bridge accessor to the interpreter database
+/* -- LazyBridge_Interp: lazy bridge accessor to the interpreter database
  *
  */
 
-rivet_thread_interp* Lazy_Bridge_Interp (rivet_thread_private* private,
+rivet_thread_interp* LazyBridge_Interp (rivet_thread_private* private,
                                       rivet_server_conf*    conf,
                                       rivet_thread_interp*  interp)
 {
@@ -423,11 +421,12 @@ rivet_thread_interp* Lazy_Bridge_Interp (rivet_thread_private* private,
     return private->ext->interp;
 }
 
-apr_status_t Lazy_Bridge_Finalize (void* data)
+apr_status_t LazyBridge_Finalize (void* data)
 {
     int vh;
     rivet_server_conf* conf = RIVET_SERVER_CONF(((server_rec*) data)->module_config);
    
+    module_globals->mpm->server_shutdown = 1;
     for (vh = 0; vh < module_globals->vhosts_count; vh++)
     {
         int try;
@@ -438,7 +437,6 @@ apr_status_t Lazy_Bridge_Finalize (void* data)
         mutex = module_globals->mpm->vhosts[vh].mutex;
         array = module_globals->mpm->vhosts[vh].array;
         apr_thread_mutex_lock(mutex);
-        module_globals->mpm->server_shutdown = 1;
         try = 0;
         do {
 
@@ -465,7 +463,54 @@ apr_status_t Lazy_Bridge_Finalize (void* data)
     return APR_SUCCESS;
 }
 
-int Lazy_Bridge_ExitHandler(rivet_thread_private* private)
+int LazyBridge_ExitHandler(rivet_thread_private* private)
+{
+
+    /* This is not strictly necessary, because this command will 
+     * eventually terminate the whole processes */
+
+    /* This will force the current thread to exit */
+
+    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. That means that in the unlikely case
+     * of several threads calling ::rivet::exit 
+     * simultaneously the first sets the exit code.
+     * This is just terrible, it highlights the bad habit
+     * of calling 'exit' when programming with mod_rivet
+     * and calls out for a version of Tcl with which
+     * we could safely call Tcl_DeleteInterp and then terminate
+     * a single thread
+    
+    apr_thread_mutex_lock(module_globals->mpm->mutex);
+    if (module_globals->mpm->exit_command == 0)
+    {
+        module_globals->mpm->exit_command = 1;
+        module_globals->mpm->exit_command_status = private->exit_status;
+    }
+    apr_thread_mutex_unlock(module_globals->mpm->mutex);
+     */
+
+    if (!private->running_conf->single_thread_exit)
+    {
+        /* We now tell the supervisor to terminate the Tcl worker thread pool
+         * to exit and is sequence the whole process to shutdown 
+         * by calling exit() */
+     
+        LazyBridge_Finalize(private->r->server);
+
+    } 
+
+    return TCL_OK;
+}
+
+#if 0
+int LazyBridge_ExitHandler(rivet_thread_private* private)
 {
 
     /* This is not strictly necessary, because this command will 
@@ -504,16 +549,17 @@ int Lazy_Bridge_ExitHandler(rivet_thread_private* private)
      * to exit and is sequence the whole process to shutdown 
      * by calling exit() */
  
-    Lazy_Bridge_Finalize (private->r->server);
+    LazyBridge_Finalize (private->r->server);
     return TCL_OK;
 }
+#endif
 
 DLLEXPORT
 RIVET_MPM_BRIDGE {
     NULL,
-    Lazy_Bridge_ChildInit,
-    Lazy_Bridge_Request,
-    Lazy_Bridge_Finalize,
-    Lazy_Bridge_ExitHandler,
-    Lazy_Bridge_Interp
+    LazyBridge_ChildInit,
+    LazyBridge_Request,
+    LazyBridge_Finalize,
+    LazyBridge_ExitHandler,
+    LazyBridge_Interp
 };
diff --git a/src/mod_rivet_ng/rivet_prefork_mpm.c b/src/mod_rivet_ng/rivet_prefork_mpm.c
index 8de9adb..3c20250 100644
--- a/src/mod_rivet_ng/rivet_prefork_mpm.c
+++ b/src/mod_rivet_ng/rivet_prefork_mpm.c
@@ -36,9 +36,9 @@ extern DLLIMPORT apr_threadkey_t*   rivet_thread_key;
 
 rivet_thread_private*   Rivet_VirtualHostsInterps (rivet_thread_private* private);
 
-/* -- Prefork_Bridge_Finalize */
+/* -- PreforkBridge_Finalize */
 
-apr_status_t Prefork_Bridge_Finalize (void* data)
+apr_status_t PreforkBridge_Finalize (void* data)
 {
     rivet_thread_private*   private;
     server_rec* s = (server_rec*) data;
@@ -52,12 +52,12 @@ apr_status_t Prefork_Bridge_Finalize (void* data)
     return OK;
 }
 
-/* -- Prefork_Bridge_ChildInit: bridge child process initialization
+/* -- PreforkBridge_ChildInit: bridge child process initialization
  *
  */
 
 
-void Prefork_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
+void PreforkBridge_ChildInit (apr_pool_t* pool, server_rec* server)
 {
     rivet_thread_private*   private;
 
@@ -100,7 +100,7 @@ void Prefork_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
 }
 
 /*
- * -- Prefork_Bridge_Request
+ * -- PreforkBridge_Request
  *
  *  The prefork implementation of this function is basically a wrapper of
  *  Rivet_SendContent. The real job is fetching the thread private data
@@ -114,7 +114,7 @@ void Prefork_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
  *   HTTP status code (see the Apache HTTP web server documentation)
  */
 
-int Prefork_Bridge_Request (request_rec* r,rivet_req_ctype ctype)
+int PreforkBridge_Request (request_rec* r,rivet_req_ctype ctype)
 {
     rivet_thread_private*   private;
 
@@ -159,7 +159,7 @@ rivet_thread_interp* MPM_MasterInterp(server_rec* server)
 }
 
 /*
- * -- Prefork_Bridge_ExitHandler
+ * -- PreforkBridge_ExitHandler
  *
  *  Just calling Tcl_Exit  
  *
@@ -171,7 +171,7 @@ rivet_thread_interp* MPM_MasterInterp(server_rec* server)
  *  the thread running the Tcl script will exit 
  */
 
-int Prefork_Bridge_ExitHandler(rivet_thread_private* private)
+int PreforkBridge_ExitHandler(rivet_thread_private* private)
 {
     Tcl_Exit(private->exit_status);
 
@@ -182,7 +182,7 @@ int Prefork_Bridge_ExitHandler(rivet_thread_private* private)
     return TCL_OK;
 }
 
-rivet_thread_interp* Prefork_Bridge_Interp (rivet_thread_private* private,
+rivet_thread_interp* PreforkBridge_Interp (rivet_thread_private* private,
                                          rivet_server_conf*    conf,
                                          rivet_thread_interp*  interp)
 {
@@ -194,10 +194,10 @@ rivet_thread_interp* Prefork_Bridge_Interp (rivet_thread_private* private,
 DLLEXPORT
 RIVET_MPM_BRIDGE {
     NULL,
-    Prefork_Bridge_ChildInit,
-    Prefork_Bridge_Request,
-    Prefork_Bridge_Finalize,
-    Prefork_Bridge_ExitHandler,
-    Prefork_Bridge_Interp
+    PreforkBridge_ChildInit,
+    PreforkBridge_Request,
+    PreforkBridge_Finalize,
+    PreforkBridge_ExitHandler,
+    PreforkBridge_Interp
 };
 
diff --git a/src/mod_rivet_ng/rivet_worker_mpm.c b/src/mod_rivet_ng/rivet_worker_mpm.c
index 9fdfc23..85b4606 100644
--- a/src/mod_rivet_ng/rivet_worker_mpm.c
+++ b/src/mod_rivet_ng/rivet_worker_mpm.c
@@ -68,8 +68,6 @@ typedef struct mpm_bridge_status {
     apr_uint32_t*       running_threads_count;
     apr_queue_t*        queue;                  /* jobs queue               */
     void**              workers;                /* thread pool ids          */
-    int                 exit_command;
-    int                 exit_command_status;
     int                 max_threads;
     int                 min_spare_threads;
     int                 max_spare_threads;
@@ -127,7 +125,58 @@ enum
  * must be restared or (most likely) the child process can exit.
  *
  */
+static
+void Worker_Bridge_Shutdown (int not_to_be_waited)
+{
+    int                 waits;
+    void*               v;
+    handler_private*    thread_obj;
+    apr_status_t        rv;
+    apr_uint32_t        threads_to_stop;
+
+    apr_thread_mutex_lock(module_globals->mpm->job_mutex);
+
+    module_globals->mpm->server_shutdown = 1;
+
+    /* We wake up the supervisor who is now supposed to stop 
+     * all the Tcl worker threads
+     */
+
+    apr_thread_cond_signal(module_globals->mpm->job_cond);
+    apr_thread_mutex_unlock(module_globals->mpm->job_mutex);
+
+    waits = 5;
+    do
+    {
+
+        rv = apr_queue_trypop(module_globals->mpm->queue,&v);
+
+        /* We wait for possible threads that are taking
+         * time to serve requests and haven't had a chance to
+         * see the signal yet
+         */
+
+        if (rv == APR_EAGAIN) 
+        {
+            waits--;
+            apr_sleep(200000);
+            continue;
+        }
+
+        thread_obj = (handler_private*)v;
+        apr_thread_mutex_lock(thread_obj->mutex);
+        thread_obj->status = init;
+        apr_thread_cond_signal(thread_obj->cond);
+        apr_thread_mutex_unlock(thread_obj->mutex);
+
+        threads_to_stop = apr_atomic_read32(module_globals->mpm->threads_count);
 
+    } while ((waits > 0) && (threads_to_stop > not_to_be_waited));
+
+    return;
+}
+
+#if 0
 void Worker_Bridge_Shutdown (void)
 {
     int                 waits;
@@ -177,6 +226,7 @@ void Worker_Bridge_Shutdown (void)
 
     return;
 }
+#endif
 
 /*
  * -- request_processor
@@ -439,23 +489,12 @@ static void* APR_THREAD_FUNC threaded_bridge_supervisor (apr_thread_t *thd, void
 
     }  while (!mpm->server_shutdown);
 
-    
-    /*
-     if (module_globals->mpm->exit_command)
-     {
-        ap_log_error(APLOG_MARK,APLOG_DEBUG,APR_SUCCESS,module_globals->server,"Orderly child process exits.");
-        exit(module_globals->mpm->exit_command_status);
-    }
-    */
-
     ap_log_error(APLOG_MARK,APLOG_DEBUG,APR_SUCCESS,module_globals->server,"Worker bridge supervisor shuts down");
     apr_thread_exit(thd,APR_SUCCESS);
 
     return NULL;
 }
 
-// int Worker_Bridge_ServerInit (apr_pool_t *pPool, apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *s) { return OK; }
-
 /*
  * -- Worker_Bridge_ChildInit
  *
@@ -493,7 +532,7 @@ void Worker_Bridge_ChildInit (apr_pool_t* pool, server_rec* server)
     module_globals->mpm->max_spare_threads  = 0;
     module_globals->mpm->workers            = NULL;
     module_globals->mpm->server_shutdown    = 0;
-    module_globals->mpm->exit_command       = 0;
+    //module_globals->mpm->exit_command     = 0;
 
     /* We keep some atomic counters that could provide basic data for a workload balancer */
 
@@ -676,31 +715,21 @@ apr_status_t Worker_Bridge_Finalize (void* data)
     apr_status_t  rv;
     apr_status_t  thread_status;
     server_rec* s = (server_rec*) data;
+    rivet_thread_private* private;
 
-    /* If the Function is called by the memory pool cleanup we wait
-     * to join the supervisor, otherwise if the function was called
-     * by Worker_Bridge_Exit we skip it because this thread itself must exit
-     * to allow the supervisor to exit in the shortest possible time 
-     */
+    RIVET_PRIVATE_DATA(rivet_thread_key,private)
+    Worker_Bridge_Shutdown(private->thread_exit);
 
-    if (!module_globals->mpm->exit_command)
+    rv = apr_thread_join (&thread_status,module_globals->mpm->supervisor);
+    if (rv != APR_SUCCESS)
     {
-        Worker_Bridge_Shutdown();
-
-        rv = apr_thread_join (&thread_status,module_globals->mpm->supervisor);
-        if (rv != APR_SUCCESS)
-        {
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
-                         MODNAME ": Error joining supervisor thread");
-        }
+        ap_log_error(APLOG_MARK,APLOG_ERR,rv,s,MODNAME": Error joining supervisor thread");
     }
 
-    // apr_threadkey_private_delete (handler_thread_key);
-    exit(module_globals->mpm->exit_command_status);
-
     return OK;
 }
 
+
 /*
  * -- MPM_MasterInterp
  *
@@ -742,6 +771,39 @@ rivet_thread_interp* MPM_MasterInterp(server_rec* s)
 int Worker_Bridge_ExitHandler(rivet_thread_private* private)
 {
     /* This is not strictly necessary, because this command will 
+     * eventually terminate the whole processes */
+
+    /* This will force the current thread to exit */
+
+    private->ext->keep_going = 0;
+
+    //module_globals->mpm->exit_command = 1;
+    //module_globals->mpm->exit_command_status = private->exit_status;
+
+    if (!private->running_conf->single_thread_exit)
+    {
+
+        /* We now tell the supervisor to terminate the Tcl worker thread pool to exit
+         * and is sequence the whole process to shutdown by calling exit() */
+     
+        Worker_Bridge_Finalize (private->r->server);
+    
+        exit(private->exit_status);
+    } 
+
+    /*
+     * If single thread exit is enabled we continue and let the
+     * thread exit on its own interrupting the main loop
+     */
+
+    return TCL_OK;
+}
+
+
+#if 0
+int Worker_Bridge_ExitHandler(rivet_thread_private* private)
+{
+    /* This is not strictly necessary, because this command will 
      * eventually terminate the whole processes
      */
 
@@ -769,7 +831,7 @@ int Worker_Bridge_ExitHandler(rivet_thread_private* private)
     
     return TCL_OK;
 }
-
+#endif
 rivet_thread_interp* Worker_Bridge_Interp (rivet_thread_private* private,
                                          rivet_server_conf*    conf,
                                          rivet_thread_interp*  interp)


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