Make the microtask queue thread-local
Previously, all the threads tried to share a common queue without a lock.
Change-Id: I85d444e950da565dc8fa6b1d1a28c8ad255212b1
diff --git a/dart_microtask_queue.cc b/dart_microtask_queue.cc
index 6a97d79..6e7ba04 100644
--- a/dart_microtask_queue.cc
+++ b/dart_microtask_queue.cc
@@ -4,36 +4,39 @@
#include "lib/tonic/dart_microtask_queue.h"
-#include <vector>
-
#include "lib/tonic/logging/dart_invoke.h"
-#include "lib/tonic/dart_persistent_value.h"
#include "lib/tonic/dart_state.h"
#include "lib/tonic/dart_sticky_error.h"
namespace tonic {
namespace {
-typedef std::vector<DartPersistentValue> MicrotaskQueue;
+thread_local DartMicrotaskQueue* g_queue = nullptr;
-DartErrorHandleType g_last_error = kNoError;
-
-static MicrotaskQueue& GetQueue() {
- static MicrotaskQueue* queue = new MicrotaskQueue();
- return *queue;
}
-} // namespace
+DartMicrotaskQueue::DartMicrotaskQueue() : last_error_(kNoError) {}
+
+DartMicrotaskQueue::~DartMicrotaskQueue() = default;
+
+void DartMicrotaskQueue::StartForCurrentThread() {
+ FTL_CHECK(!g_queue);
+ g_queue = new DartMicrotaskQueue();
+}
+
+DartMicrotaskQueue* DartMicrotaskQueue::GetForCurrentThread() {
+ FTL_DCHECK(g_queue);
+ return g_queue;
+}
void DartMicrotaskQueue::ScheduleMicrotask(Dart_Handle callback) {
- GetQueue().emplace_back(DartState::Current(), callback);
+ queue_.emplace_back(DartState::Current(), callback);
}
void DartMicrotaskQueue::RunMicrotasks() {
- MicrotaskQueue& queue = GetQueue();
- while (!queue.empty()) {
+ while (!queue_.empty()) {
MicrotaskQueue local;
- std::swap(queue, local);
+ std::swap(queue_, local);
for (const auto& callback : local) {
ftl::WeakPtr<DartState> dart_state = callback.dart_state();
if (!dart_state.get())
@@ -42,13 +45,19 @@
Dart_Handle result = DartInvokeVoid(callback.value());
DartErrorHandleType error = GetErrorHandleType(result);
if (error != kNoError)
- g_last_error = error;
+ last_error_ = error;
}
}
}
+void DartMicrotaskQueue::Destroy() {
+ FTL_DCHECK(g_queue);
+ delete g_queue;
+ g_queue = nullptr;
+}
+
DartErrorHandleType DartMicrotaskQueue::GetLastError() {
- return g_last_error;
+ return last_error_;
}
}
diff --git a/dart_microtask_queue.h b/dart_microtask_queue.h
index 34b4db4..a759daf 100644
--- a/dart_microtask_queue.h
+++ b/dart_microtask_queue.h
@@ -5,16 +5,33 @@
#ifndef LIB_TONIC_DART_MICROTASK_QUEUE_H_
#define LIB_TONIC_DART_MICROTASK_QUEUE_H_
+#include <vector>
+
#include "dart/runtime/include/dart_api.h"
+#include "lib/tonic/dart_persistent_value.h"
#include "lib/tonic/logging/dart_error.h"
namespace tonic {
class DartMicrotaskQueue {
public:
- static void ScheduleMicrotask(Dart_Handle callback);
- static void RunMicrotasks();
- static DartErrorHandleType GetLastError();
+ static void StartForCurrentThread();
+ static DartMicrotaskQueue* GetForCurrentThread();
+
+ void ScheduleMicrotask(Dart_Handle callback);
+ void RunMicrotasks();
+ void Destroy();
+
+ DartErrorHandleType GetLastError();
+
+ private:
+ DartMicrotaskQueue();
+ ~DartMicrotaskQueue();
+
+ typedef std::vector<DartPersistentValue> MicrotaskQueue;
+
+ DartErrorHandleType last_error_;
+ MicrotaskQueue queue_;
};
} // namespace tonic