Thread: delete racy API (Release()) and fix racy code (started()).

- Thread::Release() wrote a local variable on the calling thread but read it on
  another thread, with no synchronization.  Happily it has no non-test callers
  so deleting it instead of trying to fix it (see bug for details).
- Thread::started_ similarly was racily being written to; replaced with a
  running_ Event, and hid the accessor except for tests & legacy callers,
  with a note about why it's a bad idea.

webrtc/base patched with:
git diff origin --relative=talk/base | patch -p1 -dwebrtc/base
followed by manual merge of 3 thunks that ran afoul of naming differences
between talk/base and webrtc/base.

BUG=3388
R=andrew@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/14589005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6236 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/base/signalthread_unittest.cc b/talk/base/signalthread_unittest.cc
index e5734d4..7bc73f0 100644
--- a/talk/base/signalthread_unittest.cc
+++ b/talk/base/signalthread_unittest.cc
@@ -50,19 +50,19 @@
       ASSERT_TRUE(harness_ != NULL);
       ++harness_->thread_started_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_FALSE(worker()->started());  // not started yet
+      EXPECT_FALSE(worker()->RunningForTest());  // not started yet
     }
 
     virtual void OnWorkStop() {
       ++harness_->thread_stopped_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_TRUE(worker()->started());  // not stopped yet
+      EXPECT_TRUE(worker()->RunningForTest());  // not stopped yet
     }
 
     virtual void OnWorkDone() {
       ++harness_->thread_done_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_TRUE(worker()->started());  // not stopped yet
+      EXPECT_TRUE(worker()->RunningForTest());  // not stopped yet
     }
 
     virtual void DoWork() {
diff --git a/talk/base/thread.cc b/talk/base/thread.cc
index 3fd1ca4..87e4fff 100644
--- a/talk/base/thread.cc
+++ b/talk/base/thread.cc
@@ -145,13 +145,12 @@
 Thread::Thread(SocketServer* ss)
     : MessageQueue(ss),
       priority_(PRIORITY_NORMAL),
-      started_(false),
+      running_(true, false),
 #if defined(WIN32)
       thread_(NULL),
       thread_id_(0),
 #endif
-      owned_(true),
-      delete_self_when_complete_(false) {
+      owned_(true) {
   SetName("Thread", this);  // default name
 }
 
@@ -180,7 +179,7 @@
 }
 
 bool Thread::SetName(const std::string& name, const void* obj) {
-  if (started_) return false;
+  if (running()) return false;
   name_ = name;
   if (obj) {
     char buf[16];
@@ -192,7 +191,7 @@
 
 bool Thread::SetPriority(ThreadPriority priority) {
 #if defined(WIN32)
-  if (started_) {
+  if (running()) {
     BOOL ret = FALSE;
     if (priority == PRIORITY_NORMAL) {
       ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);
@@ -211,7 +210,7 @@
   return true;
 #else
   // TODO: Implement for Linux/Mac if possible.
-  if (started_) return false;
+  if (running()) return false;
   priority_ = priority;
   return true;
 #endif
@@ -220,8 +219,8 @@
 bool Thread::Start(Runnable* runnable) {
   ASSERT(owned_);
   if (!owned_) return false;
-  ASSERT(!started_);
-  if (started_) return false;
+  ASSERT(!running());
+  if (running()) return false;
 
   Restart();  // reset fStop_ if the thread is being restarted
 
@@ -240,7 +239,7 @@
   thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags,
                          &thread_id_);
   if (thread_) {
-    started_ = true;
+    running_.Set();
     if (priority_ != PRIORITY_NORMAL) {
       SetPriority(priority_);
       ::ResumeThread(thread_);
@@ -288,13 +287,13 @@
     LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
     return false;
   }
-  started_ = true;
+  running_.Set();
 #endif
   return true;
 }
 
 void Thread::Join() {
-  if (started_) {
+  if (running()) {
     ASSERT(!IsCurrent());
 #if defined(WIN32)
     WaitForSingleObject(thread_, INFINITE);
@@ -305,7 +304,7 @@
     void *pv;
     pthread_join(thread_, &pv);
 #endif
-    started_ = false;
+    running_.Reset();
   }
 }
 
@@ -356,10 +355,6 @@
     } else {
       init->thread->Run();
     }
-    if (init->thread->delete_self_when_complete_) {
-      init->thread->started_ = false;
-      delete init->thread;
-    }
     delete init;
     return NULL;
   }
@@ -521,7 +516,7 @@
 }
 
 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager) {
-  if (started_)
+  if (running())
     return false;
 #if defined(WIN32)
   // We explicitly ask for no rights other than synchronization.
@@ -536,7 +531,7 @@
   thread_ = pthread_self();
 #endif
   owned_ = false;
-  started_ = true;
+  running_.Set();
   thread_manager->SetCurrentThread(this);
   return true;
 }
@@ -549,7 +544,7 @@
     LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
   }
 #endif
-  started_ = false;
+  running_.Reset();
 }
 
 
diff --git a/talk/base/thread.h b/talk/base/thread.h
index 316f041..4cbf721 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -37,6 +37,7 @@
 #include <pthread.h>
 #endif
 #include "talk/base/constructormagic.h"
+#include "talk/base/event.h"
 #include "talk/base/messagequeue.h"
 
 #ifdef WIN32
@@ -143,15 +144,8 @@
   bool SetPriority(ThreadPriority priority);
 
   // Starts the execution of the thread.
-  bool started() const { return started_; }
   bool Start(Runnable* runnable = NULL);
 
-  // Used for fire-and-forget threads.  Deletes this thread object when the
-  // Run method returns.
-  void Release() {
-    delete_self_when_complete_ = true;
-  }
-
   // Tells the thread to stop and waits until it is joined.
   // Never call Stop on the current thread.  Instead use the inherited Quit
   // function which will exit the base MessageQueue without terminating the
@@ -218,6 +212,19 @@
   bool WrapCurrent();
   void UnwrapCurrent();
 
+  // Expose private method running() for tests.
+  //
+  // DANGER: this is a terrible public API.  Most callers that might want to
+  // call this likely do not have enough control/knowledge of the Thread in
+  // question to guarantee that the returned value remains true for the duration
+  // of whatever code is conditionally executing because of the return value!
+  bool RunningForTest() { return running(); }
+  // This is a legacy call-site that probably doesn't need to exist in the first
+  // place.
+  // TODO(fischman): delete once the ASSERT added in channelmanager.cc sticks
+  // for a month (ETA 2014/06/22).
+  bool RunningForChannelManager() { return running(); }
+
  protected:
   // Blocks the calling thread until this thread has terminated.
   void Join();
@@ -230,10 +237,13 @@
   // being created.
   bool WrapCurrentWithThreadManager(ThreadManager* thread_manager);
 
+  // Return true if the thread was started and hasn't yet stopped.
+  bool running() { return running_.Wait(0); }
+
   std::list<_SendMessage> sendlist_;
   std::string name_;
   ThreadPriority priority_;
-  bool started_;
+  Event running_;  // Signalled means running.
 
 #ifdef POSIX
   pthread_t thread_;
@@ -245,7 +255,6 @@
 #endif
 
   bool owned_;
-  bool delete_self_when_complete_;
 
   friend class ThreadManager;
 
diff --git a/talk/base/thread_unittest.cc b/talk/base/thread_unittest.cc
index 1465d04..d7d6a01 100644
--- a/talk/base/thread_unittest.cc
+++ b/talk/base/thread_unittest.cc
@@ -261,32 +261,14 @@
   current_thread->UnwrapCurrent();
   CustomThread* cthread = new CustomThread();
   EXPECT_TRUE(cthread->WrapCurrent());
-  EXPECT_TRUE(cthread->started());
+  EXPECT_TRUE(cthread->RunningForTest());
   EXPECT_FALSE(cthread->IsOwned());
   cthread->UnwrapCurrent();
-  EXPECT_FALSE(cthread->started());
+  EXPECT_FALSE(cthread->RunningForTest());
   delete cthread;
   current_thread->WrapCurrent();
 }
 
-// Test that calling Release on a thread causes it to self-destruct when
-// it's finished running
-TEST(ThreadTest, Release) {
-  scoped_ptr<Event> event(new Event(true, false));
-  // Ensure the event is initialized.
-  event->Reset();
-
-  Thread* thread = new SignalWhenDestroyedThread(event.get());
-  thread->Start();
-  thread->Release();
-
-  // The event should get signaled when the thread completes, which should
-  // be nearly instantaneous, since it doesn't do anything.  For safety,
-  // give it 3 seconds in case the machine is under load.
-  bool signaled = event->Wait(3000);
-  EXPECT_TRUE(signaled);
-}
-
 TEST(ThreadTest, Invoke) {
   // Create and start the thread.
   Thread thread;
diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc
index 757d804..3461a9c 100644
--- a/talk/session/media/channelmanager.cc
+++ b/talk/session/media/channelmanager.cc
@@ -217,7 +217,11 @@
   }
 
   ASSERT(worker_thread_ != NULL);
-  if (worker_thread_ && worker_thread_->started()) {
+  ASSERT(worker_thread_->RunningForChannelManager());
+  // TODO(fischman): remove the if below (and
+  // Thread::RunningForChannelManager()) once the ASSERT above has stuck for a
+  // month (2014/06/22).
+  if (worker_thread_ && worker_thread_->RunningForChannelManager()) {
     if (media_engine_->Init(worker_thread_)) {
       initialized_ = true;
 
diff --git a/webrtc/base/signalthread_unittest.cc b/webrtc/base/signalthread_unittest.cc
index 4d3e040..e0ea54e 100644
--- a/webrtc/base/signalthread_unittest.cc
+++ b/webrtc/base/signalthread_unittest.cc
@@ -33,19 +33,19 @@
       ASSERT_TRUE(harness_ != NULL);
       ++harness_->thread_started_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_FALSE(worker()->started());  // not started yet
+      EXPECT_FALSE(worker()->RunningForTest());  // not started yet
     }
 
     virtual void OnWorkStop() {
       ++harness_->thread_stopped_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_TRUE(worker()->started());  // not stopped yet
+      EXPECT_TRUE(worker()->RunningForTest());  // not stopped yet
     }
 
     virtual void OnWorkDone() {
       ++harness_->thread_done_;
       EXPECT_EQ(harness_->main_thread_, Thread::Current());
-      EXPECT_TRUE(worker()->started());  // not stopped yet
+      EXPECT_TRUE(worker()->RunningForTest());  // not stopped yet
     }
 
     virtual void DoWork() {
diff --git a/webrtc/base/thread.cc b/webrtc/base/thread.cc
index 3963b38..49a299d 100644
--- a/webrtc/base/thread.cc
+++ b/webrtc/base/thread.cc
@@ -128,13 +128,12 @@
 Thread::Thread(SocketServer* ss)
     : MessageQueue(ss),
       priority_(PRIORITY_NORMAL),
-      started_(false),
+      running_(true, false),
 #if defined(WEBRTC_WIN)
       thread_(NULL),
       thread_id_(0),
 #endif
-      owned_(true),
-      delete_self_when_complete_(false) {
+      owned_(true) {
   SetName("Thread", this);  // default name
 }
 
@@ -163,7 +162,7 @@
 }
 
 bool Thread::SetName(const std::string& name, const void* obj) {
-  if (started_) return false;
+  if (running()) return false;
   name_ = name;
   if (obj) {
     char buf[16];
@@ -175,7 +174,7 @@
 
 bool Thread::SetPriority(ThreadPriority priority) {
 #if defined(WEBRTC_WIN)
-  if (started_) {
+  if (running()) {
     BOOL ret = FALSE;
     if (priority == PRIORITY_NORMAL) {
       ret = ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);
@@ -194,7 +193,7 @@
   return true;
 #else
   // TODO: Implement for Linux/Mac if possible.
-  if (started_) return false;
+  if (running()) return false;
   priority_ = priority;
   return true;
 #endif
@@ -203,8 +202,8 @@
 bool Thread::Start(Runnable* runnable) {
   ASSERT(owned_);
   if (!owned_) return false;
-  ASSERT(!started_);
-  if (started_) return false;
+  ASSERT(!running());
+  if (running()) return false;
 
   Restart();  // reset fStop_ if the thread is being restarted
 
@@ -223,7 +222,7 @@
   thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags,
                          &thread_id_);
   if (thread_) {
-    started_ = true;
+    running_.Set();
     if (priority_ != PRIORITY_NORMAL) {
       SetPriority(priority_);
       ::ResumeThread(thread_);
@@ -271,13 +270,13 @@
     LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
     return false;
   }
-  started_ = true;
+  running_.Set();
 #endif
   return true;
 }
 
 void Thread::Join() {
-  if (started_) {
+  if (running()) {
     ASSERT(!IsCurrent());
 #if defined(WEBRTC_WIN)
     WaitForSingleObject(thread_, INFINITE);
@@ -288,7 +287,7 @@
     void *pv;
     pthread_join(thread_, &pv);
 #endif
-    started_ = false;
+    running_.Reset();
   }
 }
 
@@ -317,7 +316,7 @@
   __except(EXCEPTION_CONTINUE_EXECUTION) {
   }
 }
-#endif  // WEBRTC_WIN 
+#endif  // WEBRTC_WIN
 
 void* Thread::PreRun(void* pv) {
   ThreadInit* init = static_cast<ThreadInit*>(pv);
@@ -339,10 +338,6 @@
     } else {
       init->thread->Run();
     }
-    if (init->thread->delete_self_when_complete_) {
-      init->thread->started_ = false;
-      delete init->thread;
-    }
     delete init;
     return NULL;
   }
@@ -504,7 +499,7 @@
 }
 
 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager) {
-  if (started_)
+  if (running())
     return false;
 #if defined(WEBRTC_WIN)
   // We explicitly ask for no rights other than synchronization.
@@ -519,7 +514,7 @@
   thread_ = pthread_self();
 #endif
   owned_ = false;
-  started_ = true;
+  running_.Set();
   thread_manager->SetCurrentThread(this);
   return true;
 }
@@ -532,7 +527,7 @@
     LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
   }
 #endif
-  started_ = false;
+  running_.Reset();
 }
 
 
diff --git a/webrtc/base/thread.h b/webrtc/base/thread.h
index 986335d..3872746 100644
--- a/webrtc/base/thread.h
+++ b/webrtc/base/thread.h
@@ -20,6 +20,7 @@
 #include <pthread.h>
 #endif
 #include "webrtc/base/constructormagic.h"
+#include "webrtc/base/event.h"
 #include "webrtc/base/messagequeue.h"
 
 #if defined(WEBRTC_WIN)
@@ -126,15 +127,8 @@
   bool SetPriority(ThreadPriority priority);
 
   // Starts the execution of the thread.
-  bool started() const { return started_; }
   bool Start(Runnable* runnable = NULL);
 
-  // Used for fire-and-forget threads.  Deletes this thread object when the
-  // Run method returns.
-  void Release() {
-    delete_self_when_complete_ = true;
-  }
-
   // Tells the thread to stop and waits until it is joined.
   // Never call Stop on the current thread.  Instead use the inherited Quit
   // function which will exit the base MessageQueue without terminating the
@@ -201,6 +195,19 @@
   bool WrapCurrent();
   void UnwrapCurrent();
 
+  // Expose private method running() for tests.
+  //
+  // DANGER: this is a terrible public API.  Most callers that might want to
+  // call this likely do not have enough control/knowledge of the Thread in
+  // question to guarantee that the returned value remains true for the duration
+  // of whatever code is conditionally executing because of the return value!
+  bool RunningForTest() { return running(); }
+  // This is a legacy call-site that probably doesn't need to exist in the first
+  // place.
+  // TODO(fischman): delete once the ASSERT added in channelmanager.cc sticks
+  // for a month (ETA 2014/06/22).
+  bool RunningForChannelManager() { return running(); }
+
  protected:
   // Blocks the calling thread until this thread has terminated.
   void Join();
@@ -213,10 +220,13 @@
   // being created.
   bool WrapCurrentWithThreadManager(ThreadManager* thread_manager);
 
+  // Return true if the thread was started and hasn't yet stopped.
+  bool running() { return running_.Wait(0); }
+
   std::list<_SendMessage> sendlist_;
   std::string name_;
   ThreadPriority priority_;
-  bool started_;
+  Event running_;  // Signalled means running.
 
 #if defined(WEBRTC_POSIX)
   pthread_t thread_;
@@ -228,7 +238,6 @@
 #endif
 
   bool owned_;
-  bool delete_self_when_complete_;
 
   friend class ThreadManager;
 
diff --git a/webrtc/base/thread_unittest.cc b/webrtc/base/thread_unittest.cc
index 22eb6ba..6a54ac7 100644
--- a/webrtc/base/thread_unittest.cc
+++ b/webrtc/base/thread_unittest.cc
@@ -244,32 +244,14 @@
   current_thread->UnwrapCurrent();
   CustomThread* cthread = new CustomThread();
   EXPECT_TRUE(cthread->WrapCurrent());
-  EXPECT_TRUE(cthread->started());
+  EXPECT_TRUE(cthread->RunningForTest());
   EXPECT_FALSE(cthread->IsOwned());
   cthread->UnwrapCurrent();
-  EXPECT_FALSE(cthread->started());
+  EXPECT_FALSE(cthread->RunningForTest());
   delete cthread;
   current_thread->WrapCurrent();
 }
 
-// Test that calling Release on a thread causes it to self-destruct when
-// it's finished running
-TEST(ThreadTest, Release) {
-  scoped_ptr<Event> event(new Event(true, false));
-  // Ensure the event is initialized.
-  event->Reset();
-
-  Thread* thread = new SignalWhenDestroyedThread(event.get());
-  thread->Start();
-  thread->Release();
-
-  // The event should get signaled when the thread completes, which should
-  // be nearly instantaneous, since it doesn't do anything.  For safety,
-  // give it 3 seconds in case the machine is under load.
-  bool signaled = event->Wait(3000);
-  EXPECT_TRUE(signaled);
-}
-
 TEST(ThreadTest, Invoke) {
   // Create and start the thread.
   Thread thread;