Browse Source

Merge pull request #829 from jenik1/fix_crash_during_handler_removal

* Fix issue 828: Make sure the thread specific storage is available d…
bel2125 5 years ago
parent
commit
ad0920f8a1
1 changed files with 46 additions and 1 deletions
  1. 46 1
      src/civetweb.c

+ 46 - 1
src/civetweb.c

@@ -2692,6 +2692,7 @@ struct mg_context {
 	unsigned int
 	    cfg_worker_threads;      /* The number of configured worker threads. */
 	pthread_t *worker_threadids; /* The worker thread IDs */
+    unsigned long starter_thread_idx; /* thread index which called mg_start */
 
 /* Connection to thread dispatching */
 #if defined(ALTERNATIVE_QUEUE)
@@ -13467,6 +13468,8 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 {
 	struct mg_handler_info *tmp_rh, **lastref;
 	size_t urilen = strlen(uri);
+    struct mg_workerTLS tls;
+    int is_tls_set = 0;
 
 	if (handler_type == WEBSOCKET_HANDLER) {
 		DEBUG_ASSERT(handler == NULL);
@@ -13523,6 +13526,23 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 		return;
 	}
 
+    /* Internal callbacks have their contexts set 
+     * if called from non-related thread, context must be set
+     * since internal function assumes it exists.
+     * For an example see how handler_info_wait_unused()
+     * waits for reference to become zero
+     */
+    if (NULL == pthread_getspecific(sTlsKey))
+    {
+        is_tls_set = 1;
+        tls.is_master = -1;
+        tls.thread_idx = phys_ctx->starter_thread_idx;
+#if defined(_WIN32)
+        tls.pthread_cond_helper_mutex = NULL;
+#endif
+        pthread_setspecific(sTlsKey, &tls);
+    }
+
 	mg_lock_context(phys_ctx);
 
 	/* first try to find an existing handler */
@@ -13564,6 +13584,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 					mg_free(tmp_rh);
 				}
 				mg_unlock_context(phys_ctx);
+                if (is_tls_set) {
+                    pthread_setspecific(sTlsKey, NULL);
+                }
 				return;
 			}
 		}
@@ -13574,6 +13597,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 		/* no handler to set, this was a remove request to a non-existing
 		 * handler */
 		mg_unlock_context(phys_ctx);
+        if (is_tls_set) {
+            pthread_setspecific(sTlsKey, NULL);
+        }
 		return;
 	}
 
@@ -13586,6 +13612,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 		mg_cry_ctx_internal(phys_ctx,
 		                    "%s",
 		                    "Cannot create new request handler struct, OOM");
+        if (is_tls_set) {
+            pthread_setspecific(sTlsKey, NULL);
+        }
 		return;
 	}
 	tmp_rh->uri = mg_strdup_ctx(uri, phys_ctx);
@@ -13595,6 +13624,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 		mg_cry_ctx_internal(phys_ctx,
 		                    "%s",
 		                    "Cannot create new request handler struct, OOM");
+        if (is_tls_set) {
+            pthread_setspecific(sTlsKey, NULL);
+        }
 		return;
 	}
 	tmp_rh->uri_len = urilen;
@@ -13604,6 +13636,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 			mg_unlock_context(phys_ctx);
 			mg_free(tmp_rh);
 			mg_cry_ctx_internal(phys_ctx, "%s", "Cannot init refcount mutex");
+            if (is_tls_set) {
+                pthread_setspecific(sTlsKey, NULL);
+            }
 			return;
 		}
 		if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
@@ -13611,6 +13646,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 			pthread_mutex_destroy(&tmp_rh->refcount_mutex);
 			mg_free(tmp_rh);
 			mg_cry_ctx_internal(phys_ctx, "%s", "Cannot init refcount cond");
+            if (is_tls_set) {
+                pthread_setspecific(sTlsKey, NULL);
+            }
 			return;
 		}
 		tmp_rh->refcount = 0;
@@ -13630,6 +13668,9 @@ mg_set_handler_type(struct mg_context *phys_ctx,
 
 	*lastref = tmp_rh;
 	mg_unlock_context(phys_ctx);
+    if (is_tls_set) {
+        pthread_setspecific(sTlsKey, NULL);
+    }
 }
 
 
@@ -18915,8 +18956,12 @@ static
 	ctx->dd.auth_nonce_mask =
 	    (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
 
+    /* Save started thread index to reuse in other external API calls
+     * For the sake of thread synchronization all non-civetweb threads 
+     * can be considered as single external thread */
+    ctx->starter_thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
 	tls.is_master = -1; /* Thread calling mg_start */
-	tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
+    tls.thread_idx = ctx->starter_thread_idx;
 #if defined(_WIN32)
 	tls.pthread_cond_helper_mutex = NULL;
 #endif