On Wed, Apr 15, 2020 at 09:50:01AM -0400, Jim Jagielski wrote:
> very, very elegant.

Thank you Jim!

I wonder if the new state variable is redundant with the other state 
variables in the watchdog structure?  I don't understand the watchdog 
model well enough to be confident here.

 struct ap_watchdog_t
{
    apr_uint32_t          thread_started; /* set to 1 once thread running */
...
    int                   singleton;
    int                   active;


Also reviewing this module more, in the post_config hook:

http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/core/mod_watchdog.c?annotate=1876619#l434

it looks to me like the ap_state_query() call correctly guards against 
multiple post_config runs during start, so there will never be a point 
where the wd_server_conf attached to pconf is reused or reusable.

- in initial startup you get only one post_config invocation if the 
_PRE_CONFIG phase is skipped

- during subsequent server reloads pconf is cleared each time

I may be missing something.

Regards, Joe

> 
> > On Apr 14, 2020, at 8:37 AM, jor...@apache.org wrote:
> > 
> > Author: jorton
> > Date: Tue Apr 14 12:37:17 2020
> > New Revision: 1876511
> > 
> > URL: http://svn.apache.org/viewvc?rev=1876511&view=rev
> > Log:
> > * modules/core/mod_watchdog.c: Switch to simpler logic to avoid the
> >  thread cleanup running before the thread has started, avoiding
> >  mutex operations which both have undefined behaviour:
> > 
> >  a) double-locking an UNNESTED (non-recursive) mutex twice in the parent
> >  b) unlocking a mutex in the spawned thread which was locked by the parent
> > 
> >  (wd_startup, wd_worker_cleanup, wd_worker): Use a boolean to ensure
> >  the cleanup does nothing if the thread wasn't started, drop the mutex.
> > 
> > Modified:
> >    httpd/httpd/trunk/modules/core/mod_watchdog.c
> > 
> > Modified: httpd/httpd/trunk/modules/core/mod_watchdog.c
> > URL: 
> > http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/core/mod_watchdog.c?rev=1876511&r1=1876510&r2=1876511&view=diff
> > ==============================================================================
> > --- httpd/httpd/trunk/modules/core/mod_watchdog.c (original)
> > +++ httpd/httpd/trunk/modules/core/mod_watchdog.c Tue Apr 14 12:37:17 2020
> > @@ -24,6 +24,8 @@
> > #include "http_core.h"
> > #include "util_mutex.h"
> > 
> > +#include "apr_atomic.h"
> > +
> > #define AP_WATCHDOG_PGROUP    "watchdog"
> > #define AP_WATCHDOG_PVERSION  "parent"
> > #define AP_WATCHDOG_CVERSION  "child"
> > @@ -43,7 +45,7 @@ struct watchdog_list_t
> > 
> > struct ap_watchdog_t
> > {
> > -    apr_thread_mutex_t   *startup;
> > +    apr_uint32_t          thread_started; /* set to 1 once thread running 
> > */
> >     apr_proc_mutex_t     *mutex;
> >     const char           *name;
> >     watchdog_list_t      *callbacks;
> > @@ -74,6 +76,10 @@ static apr_status_t wd_worker_cleanup(vo
> >     apr_status_t rv;
> >     ap_watchdog_t *w = (ap_watchdog_t *)data;
> > 
> > +    /* Do nothing if the thread wasn't started. */
> > +    if (apr_atomic_read32(&w->thread_started) != 1)
> > +        return APR_SUCCESS;
> > +
> >     if (w->is_running) {
> >         watchdog_list_t *wl = w->callbacks;
> >         while (wl) {
> > @@ -110,7 +116,8 @@ static void* APR_THREAD_FUNC wd_worker(a
> >     w->pool = apr_thread_pool_get(thread);
> >     w->is_running = 1;
> > 
> > -    apr_thread_mutex_unlock(w->startup);
> > +    apr_atomic_set32(&w->thread_started, 1); /* thread started */
> > +
> >     if (w->mutex) {
> >         while (w->is_running) {
> >             if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpmq_s) != APR_SUCCESS) {
> > @@ -264,10 +271,7 @@ static apr_status_t wd_startup(ap_watchd
> > {
> >     apr_status_t rc;
> > 
> > -    /* Create thread startup mutex */
> > -    rc = apr_thread_mutex_create(&w->startup, APR_THREAD_MUTEX_UNNESTED, 
> > p);
> > -    if (rc != APR_SUCCESS)
> > -        return rc;
> > +    apr_atomic_set32(&w->thread_started, 0);
> > 
> >     if (w->singleton) {
> >         /* Initialize singleton mutex in child */
> > @@ -277,22 +281,12 @@ static apr_status_t wd_startup(ap_watchd
> >             return rc;
> >     }
> > 
> > -    /* This mutex fixes problems with a fast start/fast end, where the pool
> > -     * cleanup was being invoked before the thread completely spawned.
> > -     */
> > -    apr_thread_mutex_lock(w->startup);
> > -    apr_pool_pre_cleanup_register(p, w, wd_worker_cleanup);
> > -
> >     /* Start the newly created watchdog */
> >     rc = apr_thread_create(&w->thread, NULL, wd_worker, w, p);
> > -    if (rc) {
> > -        apr_pool_cleanup_kill(p, w, wd_worker_cleanup);
> > +    if (rc == APR_SUCCESS) {
> > +        apr_pool_pre_cleanup_register(p, w, wd_worker_cleanup);
> >     }
> > 
> > -    apr_thread_mutex_lock(w->startup);
> > -    apr_thread_mutex_unlock(w->startup);
> > -    apr_thread_mutex_destroy(w->startup);
> > -
> >     return rc;
> > }
> > 
> > 
> > 
> 

Reply via email to