very, very elegant.

> On Apr 14, 2020, at 8:37 AM, [email protected] 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