[modular] Fix race condition in PseudoDirServer

Sometimes, the child thread was calling .signal() even before parent
thread kicked off a .wait().

The fix is to use condition variables the correct way -- have the child
use use the lock :)

Test: Verified that it doesnt flake by running:
fx run-test peridot_tests -- --gtest_filter='ModularConfigReaderTest.OverrideConfigDir' --gtest_repeat=2000

MF-419 #done

Change-Id: Ib74317da4478d9539070a74815b3b8ad5f08a45c
diff --git a/peridot/lib/util/pseudo_dir_server.cc b/peridot/lib/util/pseudo_dir_server.cc
index e9662be..65439d9 100644
--- a/peridot/lib/util/pseudo_dir_server.cc
+++ b/peridot/lib/util/pseudo_dir_server.cc
@@ -13,10 +13,10 @@
             StartThread(std::move(request));
           },
           dir_.NewRequest()) {
-  // The thread (owned by |serving_thread_|) kicked off, but lets wait until
-  // it's run loop is ready.
+  // Block until the run loop in |serving_thread_| is ready before returning
+  // control to the caller.
   std::unique_lock<std::mutex> lock(ready_mutex_);
-  thread_loop_ready_.wait(lock);
+  thread_loop_ready_.wait(lock, [this] { return thread_loop_ != nullptr; });
 }
 
 PseudoDirServer::~PseudoDirServer() {
@@ -43,14 +43,17 @@
 void PseudoDirServer::StartThread(
     fidl::InterfaceRequest<fuchsia::io::Directory> request) {
   async::Loop loop(&kAsyncLoopConfigAttachToThread);
-  thread_loop_ = &loop;
 
-  // The owner's thread is currently blocked waiting for this thread to
-  // initialize a valid |thread_loop_|. Notify the owner thread that it's now
-  // safe to manipulate this thread's run loop:
-  thread_loop_ready_.notify_all();
+  {
+    std::lock_guard<std::mutex> lock(ready_mutex_);
 
-  pseudo_dir_->Serve(fuchsia::io::OPEN_RIGHT_READABLE, request.TakeChannel());
+    // Setting this will let |thread_loop_ready_.wait()| proceed.
+    thread_loop_ = &loop;
+
+    pseudo_dir_->Serve(fuchsia::io::OPEN_RIGHT_READABLE, request.TakeChannel());
+    thread_loop_ready_.notify_one();
+  }
+
   thread_loop_->Run();
   // This thread exits when the owner thread calls thread_loop_->Quit().
 }