Reimplement std::future and std::promise to workaround TSAN false positives
diff --git a/include/dap/future.h b/include/dap/future.h
new file mode 100644
index 0000000..abc8abf
--- /dev/null
+++ b/include/dap/future.h
@@ -0,0 +1,179 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef dap_future_h
+#define dap_future_h
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+namespace dap {
+
+// internal functionality
+namespace detail {
+template <typename T>
+struct promise_state {
+  T val;
+  std::mutex mutex;
+  std::condition_variable cv;
+  bool hasVal = false;
+};
+}  // namespace detail
+
+// forward declaration
+template <typename T>
+class promise;
+
+// future_status is the enumeration returned by future::wait_for and
+// future::wait_until.
+enum class future_status {
+  ready,
+  timeout,
+};
+
+// future is a minimal reimplementation of std::future, that does not suffer
+// from TSAN false positives. See:
+// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
+template <typename T>
+class future {
+ public:
+  using State = detail::promise_state<T>;
+
+  // constructors
+  inline future() = default;
+  inline future(future&&) = default;
+
+  // valid() returns true if the future has an internal state.
+  bool valid() const;
+
+  // get() blocks until the future has a valid result, and returns it.
+  // The future must have a valid internal state to call this method.
+  inline T get();
+
+  // wait() blocks until the future has a valid result.
+  // The future must have a valid internal state to call this method.
+  void wait() const;
+
+  // wait_for() blocks until the future has a valid result, or the timeout is
+  // reached.
+  // The future must have a valid internal state to call this method.
+  template <class Rep, class Period>
+  future_status wait_for(
+      const std::chrono::duration<Rep, Period>& timeout) const;
+
+  // wait_until() blocks until the future has a valid result, or the timeout is
+  // reached.
+  // The future must have a valid internal state to call this method.
+  template <class Clock, class Duration>
+  future_status wait_until(
+      const std::chrono::time_point<Clock, Duration>& timeout) const;
+
+ private:
+  friend promise<T>;
+  future(const future&) = delete;
+  inline future(const std::shared_ptr<State>& state);
+
+  std::shared_ptr<State> state = std::make_shared<State>();
+};
+
+template <typename T>
+future<T>::future(const std::shared_ptr<State>& state) : state(state) {}
+
+template <typename T>
+bool future<T>::valid() const {
+  return state;
+}
+
+template <typename T>
+T future<T>::get() {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  state->cv.wait(lock, [&] { return state->hasVal; });
+  return state->val;
+}
+
+template <typename T>
+void future<T>::wait() const {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  state->cv.wait(lock, [&] { return state->hasVal; });
+}
+
+template <typename T>
+template <class Rep, class Period>
+future_status future<T>::wait_for(
+    const std::chrono::duration<Rep, Period>& timeout) const {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  return state->cv.wait_for(lock, timeout, [&] { return state->hasVal; })
+             ? future_status::ready
+             : future_status::timeout;
+}
+
+template <typename T>
+template <class Clock, class Duration>
+future_status future<T>::wait_until(
+    const std::chrono::time_point<Clock, Duration>& timeout) const {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  return state->cv.wait_until(lock, timeout, [&] { return state->hasVal; })
+             ? future_status::ready
+             : future_status::timeout;
+}
+
+// promise is a minimal reimplementation of std::promise, that does not suffer
+// from TSAN false positives. See:
+// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
+template <typename T>
+class promise {
+ public:
+  // constructors
+  inline promise() = default;
+  inline promise(promise&& other) = default;
+  inline promise(const promise& other) = default;
+
+  // set_value() stores value to the shared state.
+  // set_value() must only be called once.
+  inline void set_value(const T& value) const;
+  inline void set_value(T&& value) const;
+
+  // get_future() returns a future sharing this promise's state.
+  future<T> get_future();
+
+ private:
+  using State = detail::promise_state<T>;
+  std::shared_ptr<State> state = std::make_shared<State>();
+};
+
+template <typename T>
+future<T> promise<T>::get_future() {
+  return future<T>(state);
+}
+
+template <typename T>
+void promise<T>::set_value(const T& value) const {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  state->val = value;
+  state->hasVal = true;
+  state->cv.notify_all();
+}
+
+template <typename T>
+void promise<T>::set_value(T&& value) const {
+  std::unique_lock<std::mutex> lock(state->mutex);
+  state->val = std::move(value);
+  state->hasVal = true;
+  state->cv.notify_all();
+}
+
+}  // namespace dap
+
+#endif  // dap_future_h
diff --git a/include/dap/session.h b/include/dap/session.h
index 056c633..f6cbb8b 100644
--- a/include/dap/session.h
+++ b/include/dap/session.h
@@ -15,12 +15,12 @@
 #ifndef dap_session_h
 #define dap_session_h
 
+#include "future.h"
 #include "io.h"
 #include "typeinfo.h"
 #include "typeof.h"
 
 #include <functional>
-#include <future>
 
 namespace dap {
 
@@ -158,9 +158,9 @@
   inline void registerSentHandler(F&& handler);
 
   // send() sends the request to the connected endpoint and returns a
-  // std::future that is assigned the request response or error.
+  // future that is assigned the request response or error.
   template <typename T, typename = IsRequest<T>>
-  std::future<ResponseOrError<typename T::Response>> send(const T& request);
+  future<ResponseOrError<typename T::Response>> send(const T& request);
 
   // send() sends the event to the connected endpoint.
   template <typename T, typename = IsEvent<T>>
@@ -248,24 +248,23 @@
 }
 
 template <typename T, typename>
-std::future<ResponseOrError<typename T::Response>> Session::send(
-    const T& request) {
+future<ResponseOrError<typename T::Response>> Session::send(const T& request) {
   using Response = typename T::Response;
-  auto promise = std::make_shared<std::promise<ResponseOrError<Response>>>();
+  promise<ResponseOrError<Response>> promise;
   const TypeInfo* typeinfo = TypeOf<T>::type();
   auto sent =
       send(typeinfo, &request, [=](const void* result, const Error* error) {
         if (error != nullptr) {
-          promise->set_value(ResponseOrError<Response>(*error));
+          promise.set_value(ResponseOrError<Response>(*error));
         } else {
-          promise->set_value(ResponseOrError<Response>(
+          promise.set_value(ResponseOrError<Response>(
               *reinterpret_cast<const Response*>(result)));
         }
       });
   if (!sent) {
-    promise->set_value(Error("Failed to send request"));
+    promise.set_value(Error("Failed to send request"));
   }
-  return promise->get_future();
+  return promise.get_future();
 }
 
 template <typename T, typename>
diff --git a/src/session_test.cpp b/src/session_test.cpp
index 04409e5..66974fa 100644
--- a/src/session_test.cpp
+++ b/src/session_test.cpp
@@ -22,8 +22,10 @@
 #include "gtest/gtest.h"
 
 #include <array>
+#include <atomic>
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 
 namespace dap {