Make mojo::RunLoop just use pthreads.

In particular, it just uses pthreads TLS stuff directly along with
pthread_once(), which allows RunLoop::{SetUp,TearDown}() to be removed.

This will allow us to make the "standalone" Environment like the
"Chromium"/base-using Environment, i.e., not require instantiation. This
will make things like ApplicationRunner more sane (since it currently
has to mix two things: instantiating the Environment -- which you need
to do once per "process", i.e., Mojo application binary instantiation --
and instantiating a RunLoop -- which you need to do once per thread).

(Really, ApplicationRunner should just be a function, but that's another
story.)

Also note that I can't just use C++11 TLS (I tried:
1c4b90d52b54811cfeeb7d72fd63ee3c33006866), since it's not supported on
iOS (which made Flutter sad). pthreads is OK though (including, AFAICT,
pthread_once()).

R=vardhan@google.com

Review URL: https://codereview.chromium.org/1996703002 .
diff --git a/mojo/public/cpp/environment/lib/environment.cc b/mojo/public/cpp/environment/lib/environment.cc
index 8224f1d..8224970 100644
--- a/mojo/public/cpp/environment/lib/environment.cc
+++ b/mojo/public/cpp/environment/lib/environment.cc
@@ -25,8 +25,6 @@
                                : &internal::kDefaultAsyncWaiter;
   g_default_logger =
       default_logger ? default_logger : &internal::kDefaultLogger;
-
-  RunLoop::SetUp();
 }
 
 }  // namespace
@@ -41,8 +39,6 @@
 }
 
 Environment::~Environment() {
-  RunLoop::TearDown();
-
   // TODO(vtl): Maybe we should allow nesting, and restore previous default
   // async waiters and loggers?
   g_default_async_waiter = nullptr;
diff --git a/mojo/public/cpp/utility/BUILD.gn b/mojo/public/cpp/utility/BUILD.gn
index d47d5c4..dd2c240 100644
--- a/mojo/public/cpp/utility/BUILD.gn
+++ b/mojo/public/cpp/utility/BUILD.gn
@@ -7,9 +7,6 @@
 mojo_sdk_source_set("utility") {
   sources = [
     "lib/run_loop.cc",
-    "lib/thread_local.h",
-    "lib/thread_local_posix.cc",
-    "lib/thread_local_win.cc",
     "run_loop.h",
     "run_loop_handler.h",
   ]
diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc
index f68ad79..1fde95c 100644
--- a/mojo/public/cpp/utility/lib/run_loop.cc
+++ b/mojo/public/cpp/utility/lib/run_loop.cc
@@ -5,22 +5,44 @@
 #include "mojo/public/cpp/utility/run_loop.h"
 
 #include <assert.h>
+#include <pthread.h>
 
 #include <algorithm>
 #include <vector>
 
+#include "mojo/public/c/system/macros.h"
 #include "mojo/public/cpp/system/time.h"
 #include "mojo/public/cpp/system/wait.h"
-#include "mojo/public/cpp/utility/lib/thread_local.h"
 #include "mojo/public/cpp/utility/run_loop_handler.h"
 
 namespace mojo {
 namespace {
 
-internal::ThreadLocalPointer<RunLoop> current_run_loop;
-
 const MojoTimeTicks kInvalidTimeTicks = static_cast<MojoTimeTicks>(0);
 
+pthread_key_t g_current_run_loop_key;
+
+// Ensures that the "current run loop" functionality is available (i.e., that we
+// have a TLS slot).
+void EnsureCurrentRunLoopInitialized() {
+  static pthread_once_t current_run_loop_key_once = PTHREAD_ONCE_INIT;
+  int error = pthread_once(&current_run_loop_key_once, []() {
+    int error = pthread_key_create(&g_current_run_loop_key, nullptr);
+    MOJO_ALLOW_UNUSED_LOCAL(error);
+    assert(!error);
+  });
+  MOJO_ALLOW_UNUSED_LOCAL(error);
+  assert(!error);
+}
+
+void SetCurrentRunLoop(RunLoop* run_loop) {
+  EnsureCurrentRunLoopInitialized();
+
+  int error = pthread_setspecific(g_current_run_loop_key, run_loop);
+  MOJO_ALLOW_UNUSED_LOCAL(error);
+  assert(!error);
+}
+
 // State needed for one iteration of WaitMany().
 struct WaitState {
   std::vector<Handle> handles;
@@ -38,29 +60,19 @@
 RunLoop::RunLoop()
     : run_state_(nullptr), next_handler_id_(0), next_sequence_number_(0) {
   assert(!current());
-  current_run_loop.Set(this);
+  SetCurrentRunLoop(this);
 }
 
 RunLoop::~RunLoop() {
   assert(current() == this);
   NotifyHandlers(MOJO_RESULT_ABORTED, IGNORE_DEADLINE);
-  current_run_loop.Set(nullptr);
-}
-
-// static
-void RunLoop::SetUp() {
-  current_run_loop.Allocate();
-}
-
-// static
-void RunLoop::TearDown() {
-  assert(!current());
-  current_run_loop.Free();
+  SetCurrentRunLoop(nullptr);
 }
 
 // static
 RunLoop* RunLoop::current() {
-  return current_run_loop.Get();
+  EnsureCurrentRunLoopInitialized();
+  return static_cast<RunLoop*>(pthread_getspecific(g_current_run_loop_key));
 }
 
 void RunLoop::AddHandler(RunLoopHandler* handler,
diff --git a/mojo/public/cpp/utility/lib/thread_local.h b/mojo/public/cpp/utility/lib/thread_local.h
deleted file mode 100644
index f5461ee..0000000
--- a/mojo/public/cpp/utility/lib/thread_local.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
-#define MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
-
-#ifndef _WIN32
-#include <pthread.h>
-#endif
-
-#include "mojo/public/cpp/system/macros.h"
-
-namespace mojo {
-namespace internal {
-
-// Helper functions that abstract the cross-platform APIs.
-struct ThreadLocalPlatform {
-#ifdef _WIN32
-  typedef unsigned long SlotType;
-#else
-  typedef pthread_key_t SlotType;
-#endif
-
-  static void AllocateSlot(SlotType* slot);
-  static void FreeSlot(SlotType slot);
-  static void* GetValueFromSlot(SlotType slot);
-  static void SetValueInSlot(SlotType slot, void* value);
-};
-
-// This class is intended to be statically allocated.
-template <typename P>
-class ThreadLocalPointer {
- public:
-  ThreadLocalPointer() : slot_() {}
-
-  void Allocate() { ThreadLocalPlatform::AllocateSlot(&slot_); }
-
-  void Free() { ThreadLocalPlatform::FreeSlot(slot_); }
-
-  P* Get() {
-    return static_cast<P*>(ThreadLocalPlatform::GetValueFromSlot(slot_));
-  }
-
-  void Set(P* value) { ThreadLocalPlatform::SetValueInSlot(slot_, value); }
-
- private:
-  ThreadLocalPlatform::SlotType slot_;
-};
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_UTILITY_LIB_THREAD_LOCAL_H_
diff --git a/mojo/public/cpp/utility/lib/thread_local_posix.cc b/mojo/public/cpp/utility/lib/thread_local_posix.cc
deleted file mode 100644
index ea7343e..0000000
--- a/mojo/public/cpp/utility/lib/thread_local_posix.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/utility/lib/thread_local.h"
-
-#include <assert.h>
-
-namespace mojo {
-namespace internal {
-
-// static
-void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
-  if (pthread_key_create(slot, nullptr) != 0) {
-    assert(false);
-  }
-}
-
-// static
-void ThreadLocalPlatform::FreeSlot(SlotType slot) {
-  if (pthread_key_delete(slot) != 0) {
-    assert(false);
-  }
-}
-
-// static
-void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
-  return pthread_getspecific(slot);
-}
-
-// static
-void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
-  if (pthread_setspecific(slot, value) != 0) {
-    assert(false);
-  }
-}
-
-}  // namespace internal
-}  // namespace mojo
diff --git a/mojo/public/cpp/utility/lib/thread_local_win.cc b/mojo/public/cpp/utility/lib/thread_local_win.cc
deleted file mode 100644
index 98841f7..0000000
--- a/mojo/public/cpp/utility/lib/thread_local_win.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/utility/lib/thread_local.h"
-
-#include <assert.h>
-#include <windows.h>
-
-namespace mojo {
-namespace internal {
-
-// static
-void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
-  *slot = TlsAlloc();
-  assert(*slot != TLS_OUT_OF_INDEXES);
-}
-
-// static
-void ThreadLocalPlatform::FreeSlot(SlotType slot) {
-  if (!TlsFree(slot)) {
-    assert(false);
-  }
-}
-
-// static
-void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
-  return TlsGetValue(slot);
-}
-
-// static
-void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
-  if (!TlsSetValue(slot, value)) {
-    assert(false);
-  }
-}
-
-}  // namespace internal
-}  // namespace mojo
diff --git a/mojo/public/cpp/utility/run_loop.h b/mojo/public/cpp/utility/run_loop.h
index 42e5950..71aa74e 100644
--- a/mojo/public/cpp/utility/run_loop.h
+++ b/mojo/public/cpp/utility/run_loop.h
@@ -25,13 +25,6 @@
   RunLoop();
   ~RunLoop();
 
-  // Sets up state needed for RunLoop. This must be invoked before creating a
-  // RunLoop.
-  static void SetUp();
-
-  // Cleans state created by Setup().
-  static void TearDown();
-
   // Returns the RunLoop for the current thread. Returns null if not yet
   // created.
   static RunLoop* current();
diff --git a/mojo/public/cpp/utility/tests/run_loop_unittest.cc b/mojo/public/cpp/utility/tests/run_loop_unittest.cc
index 05d591a..fb41a41 100644
--- a/mojo/public/cpp/utility/tests/run_loop_unittest.cc
+++ b/mojo/public/cpp/utility/tests/run_loop_unittest.cc
@@ -47,25 +47,8 @@
   MOJO_DISALLOW_COPY_AND_ASSIGN(TestRunLoopHandler);
 };
 
-class RunLoopTest : public testing::Test {
- public:
-  RunLoopTest() {}
-
-  void SetUp() override {
-    Test::SetUp();
-    RunLoop::SetUp();
-  }
-  void TearDown() override {
-    RunLoop::TearDown();
-    Test::TearDown();
-  }
-
- private:
-  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
-};
-
 // Trivial test to verify Run() with no added handles returns.
-TEST_F(RunLoopTest, ExitsWithNoHandles) {
+TEST(RunLoopTest, ExitsWithNoHandles) {
   RunLoop run_loop;
   run_loop.Run();
 }
@@ -90,7 +73,7 @@
 };
 
 // Verifies RunLoop quits when no more handles (handle is removed when ready).
-TEST_F(RunLoopTest, HandleReady) {
+TEST(RunLoopTest, HandleReady) {
   RemoveOnReadyRunLoopHandler handler;
   MessagePipe test_pipe;
   EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
@@ -125,7 +108,7 @@
 };
 
 // Verifies Quit() from OnHandleReady() quits the loop.
-TEST_F(RunLoopTest, QuitFromReady) {
+TEST(RunLoopTest, QuitFromReady) {
   QuitOnReadyRunLoopHandler handler;
   MessagePipe test_pipe;
   EXPECT_TRUE(test::WriteTextMessage(test_pipe.handle1.get(), std::string()));
@@ -160,7 +143,7 @@
 };
 
 // Verifies Quit() when the deadline is reached works.
-TEST_F(RunLoopTest, QuitWhenDeadlineExpired) {
+TEST(RunLoopTest, QuitWhenDeadlineExpired) {
   QuitOnErrorRunLoopHandler handler;
   MessagePipe test_pipe;
   RunLoop run_loop;
@@ -176,7 +159,7 @@
 }
 
 // Test that handlers are notified of loop destruction.
-TEST_F(RunLoopTest, Destruction) {
+TEST(RunLoopTest, Destruction) {
   TestRunLoopHandler handler;
   MessagePipe test_pipe;
   {
@@ -213,7 +196,7 @@
 };
 
 // Test that handlers are notified of loop destruction.
-TEST_F(RunLoopTest, MultipleHandleDestruction) {
+TEST(RunLoopTest, MultipleHandleDestruction) {
   RemoveManyRunLoopHandler odd_handler;
   TestRunLoopHandler even_handler;
   MessagePipe test_pipe1, test_pipe2, test_pipe3;
@@ -262,7 +245,7 @@
   MOJO_DISALLOW_COPY_AND_ASSIGN(AddHandlerOnErrorHandler);
 };
 
-TEST_F(RunLoopTest, AddHandlerOnError) {
+TEST(RunLoopTest, AddHandlerOnError) {
   AddHandlerOnErrorHandler handler;
   MessagePipe test_pipe;
   {
@@ -277,7 +260,7 @@
   EXPECT_EQ(MOJO_RESULT_ABORTED, handler.last_error_result());
 }
 
-TEST_F(RunLoopTest, Current) {
+TEST(RunLoopTest, Current) {
   EXPECT_TRUE(RunLoop::current() == nullptr);
   {
     RunLoop run_loop;
@@ -360,7 +343,7 @@
 const size_t NestingRunLoopHandler::kDepthLimit = 10;
 const char NestingRunLoopHandler::kSignalMagic = 'X';
 
-TEST_F(RunLoopTest, NestedRun) {
+TEST(RunLoopTest, NestedRun) {
   NestingRunLoopHandler handler;
   MessagePipe test_pipe;
   RunLoop run_loop;
@@ -388,7 +371,7 @@
   std::vector<int>* sequence;
 };
 
-TEST_F(RunLoopTest, DelayedTaskOrder) {
+TEST(RunLoopTest, DelayedTaskOrder) {
   std::vector<int> sequence;
   RunLoop run_loop;
   run_loop.PostDelayedTask(Closure(Task(1, &sequence)), 0);
@@ -410,7 +393,7 @@
   RunLoop* run_loop;
 };
 
-TEST_F(RunLoopTest, QuitFromDelayedTask) {
+TEST(RunLoopTest, QuitFromDelayedTask) {
   TestRunLoopHandler handler;
   MessagePipe test_pipe;
   RunLoop run_loop;