diff --git a/libdevcore/concurrent_queue.h b/libdevcore/concurrent_queue.h
new file mode 100644
index 000000000..2e88fc576
--- /dev/null
+++ b/libdevcore/concurrent_queue.h
@@ -0,0 +1,60 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+#pragma once
+#include
+#include
+#include
+#include
+
+
+namespace dev
+{
+
+/// Concurrent queue.
+/// You can push and pop elements to/from the queue. Pop will block until the queue is not empty.
+/// The default backend (_QueueT) is std::queue. It can be changed to any type that has
+/// proper push(), pop(), empty() and front() methods.
+template>
+class concurrent_queue
+{
+public:
+ template
+ void push(_U&& _elem)
+ {
+ {
+ std::lock_guard guard{x_mutex};
+ m_queue.push(std::forward<_U>(_elem));
+ }
+ m_cv.notify_one();
+ }
+
+ _T pop()
+ {
+ std::unique_lock lock{x_mutex};
+ m_cv.wait(lock, [this]{ return !m_queue.empty(); });
+ auto item = std::move(m_queue.front());
+ m_queue.pop();
+ return item;
+ }
+
+private:
+ _QueueT m_queue;
+ std::mutex x_mutex;
+ std::condition_variable m_cv;
+};
+
+}
diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp
index add43302e..50a548002 100644
--- a/libevm/SmartVM.cpp
+++ b/libevm/SmartVM.cpp
@@ -21,9 +21,7 @@
#include "SmartVM.h"
#include
#include
-#include
-#include
-#include
+#include
#include
#include
#include
@@ -51,34 +49,26 @@ namespace
{
bytes code;
h256 codeHash;
+
+ static JitTask createStopSentinel() { return JitTask(); }
+
+ bool isStopSentinel()
+ {
+ assert((!code.empty() || !codeHash) && "'empty code => empty hash' invariand failed");
+ return code.empty();
+ }
};
class JitWorker
{
- bool m_finished = false;
- std::mutex x_mutex;
- std::condition_variable m_cv;
std::thread m_worker;
- std::queue m_queue;
-
- bool pop(JitTask& o_task)
- {
- std::unique_lock lock{x_mutex};
- m_cv.wait(lock, [this]{ return m_finished || !m_queue.empty(); });
- if (m_finished)
- return false;
-
- assert(!m_queue.empty());
- o_task = std::move(m_queue.front());
- m_queue.pop();
- return true;
- }
+ concurrent_queue m_queue;
void work()
{
clog(JitInfo) << "JIT worker started.";
JitTask task;
- while (pop(task))
+ while (!(task = m_queue.pop()).isStopSentinel())
{
clog(JitInfo) << "Compilation... " << task.codeHash;
evmjit::JIT::compile(task.code.data(), task.code.size(), eth2jit(task.codeHash));
@@ -93,18 +83,11 @@ namespace
~JitWorker()
{
- DEV_GUARDED(x_mutex)
- m_finished = true;
- m_cv.notify_one();
+ push(JitTask::createStopSentinel());
m_worker.join();
}
- void push(JitTask&& _task)
- {
- DEV_GUARDED(x_mutex)
- m_queue.push(std::move(_task));
- m_cv.notify_one();
- }
+ void push(JitTask&& _task) { m_queue.push(std::move(_task)); }
};
}