diff --git a/backend/BackendConnector.cpp b/backend/BackendConnector.cpp
new file mode 100644
index 0000000..f7a63fe
--- /dev/null
+++ b/backend/BackendConnector.cpp
@@ -0,0 +1,90 @@
+/*
+ * This program 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
+ * any later version.
+ *
+ * This program 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 this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "IBackend.hpp"
+#include "BackendConnector.hpp"
+
+#include "cpu/minethd.h"
+#ifndef CONF_NO_CUDA
+# include "nvidia/minethd.h"
+#endif
+#ifndef CONF_NO_OPENCL
+# include "amd/minethd.h"
+#endif
+#include "miner_work.h"
+#include "GlobalStates.hpp"
+ #include
+
+#include "Plugin.hpp"
+
+namespace xmrstak
+{
+
+
+bool BackendConnector::self_test()
+{
+
+ return true;
+}
+
+std::vector* BackendConnector::thread_starter(miner_work& pWork)
+{
+ GlobalStates::iGlobalJobNo = 0;
+ GlobalStates::iConsumeCnt = 0;
+
+
+ std::vector* pvThreads = new std::vector;
+
+ auto cpuThreads = cpu::minethd::thread_starter(pvThreads->size(), pWork);
+ pvThreads->insert(std::end(*pvThreads), std::begin(cpuThreads), std::end(cpuThreads));
+ if(cpuThreads.size() == 0)
+ printer::inst()->print_msg(L0, "WARNING: backend CPU disabled.");
+
+#ifndef CONF_NO_CUDA
+ Plugin nvidiaPlugin("NVIDIA", "./libxmrstak_cuda_backend");
+ std::vector* nvidiaThreads = nvidiaPlugin.startBackend(pvThreads->size(), pWork);
+ pvThreads->insert(std::end(*pvThreads), std::begin(*nvidiaThreads), std::end(*nvidiaThreads));
+ if(nvidiaThreads->size() == 0)
+ printer::inst()->print_msg(L0, "WARNING: backend NVIDIA disabled.");
+#endif
+
+#ifndef CONF_NO_OPENCL
+ Plugin amdPlugin("AMD", "./libxmrstak_opencl_backend");
+ std::vector* amdThreads = amdPlugin.startBackend(pvThreads->size(), pWork);
+ pvThreads->insert(std::end(*pvThreads), std::begin(*amdThreads), std::end(*amdThreads));
+ if(amdThreads->size() == 0)
+ printer::inst()->print_msg(L0, "WARNING: backend AMD disabled.");
+#endif
+
+ GlobalStates::iThreadCount = pvThreads->size();
+ return pvThreads;
+}
+
+} // namepsace xmrstak
diff --git a/backend/BackendConnector.hpp b/backend/BackendConnector.hpp
new file mode 100644
index 0000000..024d9b1
--- /dev/null
+++ b/backend/BackendConnector.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include "IBackend.hpp"
+#include "miner_work.h"
+
+namespace xmrstak
+{
+
+ struct BackendConnector
+ {
+ static std::vector* thread_starter(miner_work& pWork);
+ static bool self_test();
+ };
+
+} // namepsace xmrstak
diff --git a/backend/GlobalStates.cpp b/backend/GlobalStates.cpp
new file mode 100644
index 0000000..99356b5
--- /dev/null
+++ b/backend/GlobalStates.cpp
@@ -0,0 +1,55 @@
+/*
+ * This program 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
+ * any later version.
+ *
+ * This program 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 this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+
+#include "miner_work.h"
+#include "GlobalStates.hpp"
+
+namespace xmrstak
+{
+
+std::atomic GlobalStates::iGlobalJobNo;
+std::atomic GlobalStates::iConsumeCnt; //Threads get jobs as they are initialized
+miner_work GlobalStates::oGlobalWork;
+uint64_t GlobalStates::iThreadCount = 0;
+
+void GlobalStates::switch_work(miner_work& pWork)
+{
+ // iConsumeCnt is a basic lock-like polling mechanism just in case we happen to push work
+ // faster than threads can consume them. This should never happen in real life.
+ // Pool cant physically send jobs faster than every 250ms or so due to net latency.
+
+ while (iConsumeCnt.load(std::memory_order_seq_cst) < iThreadCount)
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ oGlobalWork = pWork;
+ iConsumeCnt.store(0, std::memory_order_seq_cst);
+ iGlobalJobNo++;
+}
+
+} // namepsace xmrstak
diff --git a/backend/GlobalStates.hpp b/backend/GlobalStates.hpp
new file mode 100644
index 0000000..293009d
--- /dev/null
+++ b/backend/GlobalStates.hpp
@@ -0,0 +1,20 @@
+#pragma once
+#include
+#include "miner_work.h"
+
+namespace xmrstak
+{
+
+struct GlobalStates
+{
+
+ static void switch_work(miner_work& pWork);
+
+ static miner_work oGlobalWork;
+ static std::atomic iGlobalJobNo;
+ static std::atomic iConsumeCnt;
+ static uint64_t iThreadCount;
+
+};
+
+} // namepsace xmrstak
diff --git a/backend/IBackend.hpp b/backend/IBackend.hpp
new file mode 100644
index 0000000..5037028
--- /dev/null
+++ b/backend/IBackend.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include
+#include
+
+
+namespace xmrstak
+{
+
+ struct IBackend
+ {
+ std::atomic iHashCount;
+ std::atomic iTimestamp;
+
+ IBackend() : iHashCount(0), iTimestamp(0)
+ {
+ }
+ };
+
+} // namepsace xmrstak
diff --git a/backend/Plugin.hpp b/backend/Plugin.hpp
new file mode 100644
index 0000000..762f955
--- /dev/null
+++ b/backend/Plugin.hpp
@@ -0,0 +1,90 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include "IBackend.hpp"
+#include
+
+#ifndef USE_PRECOMPILED_HEADERS
+#ifdef WIN32
+#include
+#include
+#else
+#include
+#include
+#endif
+#include
+#endif
+
+namespace xmrstak
+{
+
+struct Plugin
+{
+
+ Plugin(const std::string backendName, const std::string libName) : fn_starterBackend(nullptr), m_backendName(backendName)
+ {
+#ifdef WIN32
+ libBackend = LoadLibrary(TEXT((libName + ".dll").c_str()));
+#else
+ libBackend = dlopen((libName + ".so").c_str(), RTLD_LAZY);
+#endif
+ if (!libBackend)
+ {
+ std::cerr << "WARNING: "<< m_backendName <<" cannot load backend library: " << dlerror() << std::endl;
+ return;
+ }
+
+#ifdef WIN32
+ fn_starterBackend = (func_t*) GetProcAddress(libBackend, "xmrstak_start_backend");
+ if (!fn_starterBackend)
+ {
+ std::cerr << "WARNING: backend plugin " << libName << " contains no entry 'xmrstak_start_backend'" << std::endl;
+ }
+#else
+ // reset last error
+ dlerror();
+ fn_starterBackend = (starterBackend_t) dlsym(libBackend, "xmrstak_start_backend");
+ const char* dlsym_error = dlerror();
+ if (dlsym_error)
+ {
+ std::cerr << "WARNING: backend plugin " << libName << " contains no entry 'xmrstak_start_backend'" << std::endl;
+ }
+#endif
+ }
+
+ std::vector* startBackend(uint32_t threadOffset, miner_work& pWork)
+ {
+ if(fn_starterBackend == nullptr)
+ {
+ std::vector* pvThreads = new std::vector();
+ std::cerr << "WARNING: " << m_backendName << " Backend disabled"<< std::endl;
+ return pvThreads;
+ }
+
+ return fn_starterBackend(threadOffset, pWork);
+ }
+
+ std::string m_backendName;
+
+ typedef std::vector* (*starterBackend_t)(uint32_t threadOffset, miner_work& pWork);
+
+ starterBackend_t fn_starterBackend;
+
+#ifdef WIN32
+ HINSTANCE libBackend;
+#else
+ void *libBackend;
+#endif
+
+/* \todo add unload to destructor and change usage of Plugin that libs keeped open until the miner endss
+#ifdef WIN32
+ FreeLibrary(libBackend);
+#else
+ dlclose(libBackend);
+#endif
+ * */
+};
+
+} // namepsace xmrstak
diff --git a/backend/miner_work.h b/backend/miner_work.h
new file mode 100644
index 0000000..b922f4a
--- /dev/null
+++ b/backend/miner_work.h
@@ -0,0 +1,102 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace xmrstak
+{
+ // only allowed for unsigned value \todo add static assert
+ template
+ T reverseBits(T value)
+ {
+ /* init with value (to get LSB) */
+ T result = value;
+ /* extra shift needed at end */
+ int s = sizeof(T) * CHAR_BIT - 1;
+ for (value >>= 1; value; value >>= 1)
+ {
+ result <<= 1;
+ result |= value & 1;
+ s--;
+ }
+ /* shift when values highest bits are zero */
+ result <<= s;
+ return result;
+ }
+
+ struct miner_work
+ {
+ char sJobID[64];
+ uint8_t bWorkBlob[112];
+ uint32_t iWorkSize;
+ uint32_t iResumeCnt;
+ uint64_t iTarget;
+ // \todo remove workaround needed for amd
+ uint32_t iTarget32;
+ bool bNiceHash;
+ bool bStall;
+ size_t iPoolId;
+
+ miner_work() : iWorkSize(0), bNiceHash(false), bStall(true), iPoolId(0) { }
+
+ miner_work(const char* sJobID, const uint8_t* bWork, uint32_t iWorkSize, uint32_t iResumeCnt,
+ uint64_t iTarget, size_t iPoolId) : iWorkSize(iWorkSize), iResumeCnt(iResumeCnt),
+ iTarget(iTarget), bNiceHash(false), bStall(false), iPoolId(iPoolId)
+ {
+ assert(iWorkSize <= sizeof(bWorkBlob));
+ memcpy(this->sJobID, sJobID, sizeof(miner_work::sJobID));
+ memcpy(this->bWorkBlob, bWork, iWorkSize);
+ }
+
+ miner_work(miner_work const&) = delete;
+
+ miner_work& operator=(miner_work const& from)
+ {
+ assert(this != &from);
+
+ iWorkSize = from.iWorkSize;
+ iResumeCnt = from.iResumeCnt;
+ iTarget = from.iTarget;
+ iTarget32 = from.iTarget32;
+ bNiceHash = from.bNiceHash;
+ bStall = from.bStall;
+ iPoolId = from.iPoolId;
+
+ assert(iWorkSize <= sizeof(bWorkBlob));
+ memcpy(sJobID, from.sJobID, sizeof(sJobID));
+ memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
+
+ return *this;
+ }
+
+ miner_work(miner_work&& from) : iWorkSize(from.iWorkSize), iTarget(from.iTarget),iTarget32(from.iTarget32),
+ bStall(from.bStall), iPoolId(from.iPoolId)
+ {
+ assert(iWorkSize <= sizeof(bWorkBlob));
+ memcpy(sJobID, from.sJobID, sizeof(sJobID));
+ memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
+ }
+
+ miner_work& operator=(miner_work&& from)
+ {
+ assert(this != &from);
+
+ iWorkSize = from.iWorkSize;
+ iResumeCnt = from.iResumeCnt;
+ iTarget = from.iTarget;
+ iTarget32 = from.iTarget32;
+ bNiceHash = from.bNiceHash;
+ bStall = from.bStall;
+ iPoolId = from.iPoolId;
+
+ assert(iWorkSize <= sizeof(bWorkBlob));
+ memcpy(sJobID, from.sJobID, sizeof(sJobID));
+ memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
+
+ return *this;
+ }
+ };
+} // namepsace xmrstak