Reland "[Support] Add a way to run a function on a detached thread""

This reverts commit 7bc7fe6b789d25d48d6dc71d533a411e9e981237.
The immediate callers have been fixed to pass nullopt where appropriate.
diff --git a/llvm/unittests/Support/Threading.cpp b/llvm/unittests/Support/Threading.cpp
index 01f1c51..21baa55 100644
--- a/llvm/unittests/Support/Threading.cpp
+++ b/llvm/unittests/Support/Threading.cpp
@@ -10,6 +10,9 @@
 #include "llvm/Support/thread.h"
 #include "gtest/gtest.h"
 
+#include <atomic>
+#include <condition_variable>
+
 using namespace llvm;
 
 namespace {
@@ -21,4 +24,55 @@
   ASSERT_LE(Num, thread::hardware_concurrency());
 }
 
+#if LLVM_ENABLE_THREADS
+
+class Notification {
+public:
+  void notify() {
+    {
+      std::lock_guard<std::mutex> Lock(M);
+      Notified = true;
+    }
+    CV.notify_all();
+  }
+
+  bool wait() {
+    std::unique_lock<std::mutex> Lock(M);
+    using steady_clock = std::chrono::steady_clock;
+    auto Deadline = steady_clock::now() +
+                    std::chrono::duration_cast<steady_clock::duration>(
+                        std::chrono::duration<double>(5));
+    return CV.wait_until(Lock, Deadline, [this] { return Notified; });
+  }
+
+private:
+  bool Notified = false;
+  mutable std::condition_variable CV;
+  mutable std::mutex M;
+};
+
+TEST(Threading, RunOnThreadSyncAsync) {
+  Notification ThreadStarted, ThreadAdvanced, ThreadFinished;
+
+  auto ThreadFunc = [&] {
+    ThreadStarted.notify();
+    ASSERT_TRUE(ThreadAdvanced.wait());
+    ThreadFinished.notify();
+  };
+
+  llvm::llvm_execute_on_thread_async(ThreadFunc);
+  ASSERT_TRUE(ThreadStarted.wait());
+  ThreadAdvanced.notify();
+  ASSERT_TRUE(ThreadFinished.wait());
+}
+
+TEST(Threading, RunOnThreadSync) {
+  std::atomic_bool Executed(false);
+  llvm::llvm_execute_on_thread(
+      [](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; },
+      &Executed);
+  ASSERT_EQ(Executed, true);
+}
+#endif
+
 } // end anon namespace