You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2017/05/30 17:48:42 UTC

[trafficserver] branch master updated: Change locking for spawning dedicated threads to avoid race conditions.

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

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  ed49508   Change locking for spawning dedicated threads to avoid race conditions.
ed49508 is described below

commit ed49508a0f1fd457a5f234073b3e51ad9f4b7097
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Tue May 30 11:31:54 2017 -0500

    Change locking for spawning dedicated threads to avoid race conditions.
---
 iocore/eventsystem/I_EventProcessor.h     |  1 +
 iocore/eventsystem/P_UnixEventProcessor.h |  1 +
 iocore/eventsystem/UnixEventProcessor.cc  | 32 +++++++++++++++++++++++--------
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/iocore/eventsystem/I_EventProcessor.h b/iocore/eventsystem/I_EventProcessor.h
index 5e1d112..f86d335 100644
--- a/iocore/eventsystem/I_EventProcessor.h
+++ b/iocore/eventsystem/I_EventProcessor.h
@@ -309,6 +309,7 @@ public:
   EThread *all_dthreads[MAX_EVENT_THREADS];
   volatile int n_dthreads; // No. of dedicated threads
   volatile int thread_data_used;
+  ink_mutex dedicated_spawn_thread_mutex;
 };
 
 extern inkcoreapi class EventProcessor eventProcessor;
diff --git a/iocore/eventsystem/P_UnixEventProcessor.h b/iocore/eventsystem/P_UnixEventProcessor.h
index 5ee4867..1f18ed7 100644
--- a/iocore/eventsystem/P_UnixEventProcessor.h
+++ b/iocore/eventsystem/P_UnixEventProcessor.h
@@ -36,6 +36,7 @@ EventProcessor::EventProcessor() : n_ethreads(0), n_thread_groups(0), n_dthreads
   memset(all_dthreads, 0, sizeof(all_dthreads));
   memset(n_threads_for_type, 0, sizeof(n_threads_for_type));
   memset(next_thread_for_type, 0, sizeof(next_thread_for_type));
+  ink_mutex_init(&dedicated_spawn_thread_mutex, "EventProcessorDedicatedThreadSpawn");
 }
 
 TS_INLINE off_t
diff --git a/iocore/eventsystem/UnixEventProcessor.cc b/iocore/eventsystem/UnixEventProcessor.cc
index 2b06c84..19f3850 100644
--- a/iocore/eventsystem/UnixEventProcessor.cc
+++ b/iocore/eventsystem/UnixEventProcessor.cc
@@ -265,17 +265,33 @@ EventProcessor::shutdown()
 Event *
 EventProcessor::spawn_thread(Continuation *cont, const char *thr_name, size_t stacksize)
 {
-  ink_release_assert(n_dthreads < MAX_EVENT_THREADS);
-  int n = ink_atomic_increment((int *)&n_dthreads, 1);
-  ink_release_assert(n < MAX_EVENT_THREADS);
-
+  /* Spawning threads in a live system - There are two potential race conditions in this logic. The
+     first is multiple calls to this method.  In that case @a all_dthreads can end up in a bad state
+     as the same entry is overwritten while another is left unitialized.
+     The other is read/write contention where another thread (e.g. the stats collection thread) is
+     iterating over the threads while the active count (@a n_dthreads) is being updated causing use
+     of not yet initialized array element.
+     This logic covers both situations. For write/write the actual array update is locked. The
+     potentially expensive set up is done outside the lock making the time spent locked small For
+     read/write it suffices to do the active count increment after initializing the array
+     element. It's not a problem if, for one cycle, a new thread is skipped.
+  */
+
+  // Do as much as possible outside the lock. Until the array element and count is changed
+  // this is thread safe.
   Event *e = eventAllocator.alloc();
 
   e->init(cont, 0, 0);
-  all_dthreads[n] = new EThread(DEDICATED, e);
-  e->ethread      = all_dthreads[n];
-  e->mutex        = all_dthreads[n]->mutex;
-  cont->mutex     = all_dthreads[n]->mutex;
+  e->ethread  = new EThread(DEDICATED, e);
+  e->mutex    = e->ethread->mutex;
+  cont->mutex = e->ethread->mutex;
+  {
+    ink_mutex_acquire(&dedicated_spawn_thread_mutex);
+    ink_release_assert(n_dthreads < MAX_EVENT_THREADS);
+    all_dthreads[n_dthreads] = e->ethread;
+    ++n_dthreads; // Be very sure this is after the array element update.
+    ink_mutex_release(&dedicated_spawn_thread_mutex);
+  }
 
   e->ethread->start(thr_name, stacksize, nullptr, nullptr, nullptr);
 

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].