From eff66ca105b259c2c0d6af424142a8313c99b4a1 Mon Sep 17 00:00:00 2001 From: psychocrypt Date: Tue, 9 Oct 2018 22:08:50 +0200 Subject: [PATCH 1/3] clean memoy on miner shutdown - free host and device memory on shutdown - catch exeptions and try to do a clean shurdown (free mem) - add key `q` to close the miner --- xmrstak/backend/amd/amd_gpu/gpu.cpp | 30 +++ xmrstak/backend/amd/amd_gpu/gpu.hpp | 1 + xmrstak/backend/amd/minethd.cpp | 187 +++++++++------- xmrstak/backend/amd/minethd.hpp | 3 +- xmrstak/backend/cpu/minethd.cpp | 207 ++++++++++-------- xmrstak/backend/cpu/minethd.hpp | 1 - xmrstak/backend/iBackend.hpp | 12 + xmrstak/backend/nvidia/minethd.cpp | 196 +++++++++-------- xmrstak/backend/nvidia/minethd.hpp | 2 - .../backend/nvidia/nvcc_code/cryptonight.hpp | 25 ++- .../backend/nvidia/nvcc_code/cuda_extra.cu | 16 ++ xmrstak/cli/cli-miner.cpp | 28 ++- xmrstak/misc/console.cpp | 3 + xmrstak/misc/executor.cpp | 48 +++- xmrstak/misc/executor.hpp | 5 + xmrstak/net/msgstruct.hpp | 2 +- 16 files changed, 476 insertions(+), 290 deletions(-) diff --git a/xmrstak/backend/amd/amd_gpu/gpu.cpp b/xmrstak/backend/amd/amd_gpu/gpu.cpp index 7c7aff788..d12622f88 100644 --- a/xmrstak/backend/amd/amd_gpu/gpu.cpp +++ b/xmrstak/backend/amd/amd_gpu/gpu.cpp @@ -607,6 +607,36 @@ size_t InitOpenCLGpu(cl_context opencl_ctx, GpuContext* ctx, const char* source_ return 0; } +size_t FinalizeOpenCL(GpuContext* ctx) +{ + xmrstak_algo miner_algo[2] = { + ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgo(), + ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot() + }; + int num_algos = miner_algo[0] == miner_algo[1] ? 1 : 2; + + for(int ii = 0; ii < num_algos; ++ii) + { + if(ii == 0) + for(int i = 0; i < 7; ++i) + clReleaseKernel(ctx->Kernels[ii][i]); + else + for(int i = 0; i < 3; ++i) + clReleaseKernel(ctx->Kernels[ii][i]); + } + + for(size_t i = 0; i < 6; ++i) + clReleaseMemObject(ctx->ExtraBuffers[i]); + clReleaseMemObject(ctx->InputBuffer); + clReleaseMemObject(ctx->OutputBuffer); + + for(size_t i = 0; i < 2; ++i) + clReleaseProgram(ctx->Program[i]); + + clReleaseCommandQueue(ctx->CommandQueues); + clReleaseDevice(ctx->DeviceID); +} + const cl_platform_info attributeTypes[5] = { CL_PLATFORM_NAME, CL_PLATFORM_VENDOR, diff --git a/xmrstak/backend/amd/amd_gpu/gpu.hpp b/xmrstak/backend/amd/amd_gpu/gpu.hpp index 63c5029d7..20f78ba34 100644 --- a/xmrstak/backend/amd/amd_gpu/gpu.hpp +++ b/xmrstak/backend/amd/amd_gpu/gpu.hpp @@ -52,6 +52,7 @@ int getAMDPlatformIdx(); std::vector getAMDDevices(int index); size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx); +size_t FinalizeOpenCL(GpuContext* ctx); size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint64_t target, xmrstak_algo miner_algo); size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput, xmrstak_algo miner_algo); diff --git a/xmrstak/backend/amd/minethd.cpp b/xmrstak/backend/amd/minethd.cpp index 5e70f25a6..d314785d0 100644 --- a/xmrstak/backend/amd/minethd.cpp +++ b/xmrstak/backend/amd/minethd.cpp @@ -162,118 +162,137 @@ std::vector* minethd::thread_starter(uint32_t threadOffset, miner_wor void minethd::work_main() { - if(affinity >= 0) //-1 means no affinity - bindMemoryToNUMANode(affinity); + cryptonight_ctx* cpu_ctx = nullptr; + try + { + if(affinity >= 0) //-1 means no affinity + bindMemoryToNUMANode(affinity); - order_fix.set_value(); - std::unique_lock lck(thd_aff_set); - lck.release(); - std::this_thread::yield(); + order_fix.set_value(); + std::unique_lock lck(thd_aff_set); + lck.release(); + std::this_thread::yield(); - uint64_t iCount = 0; - cryptonight_ctx* cpu_ctx; - cpu_ctx = cpu::minethd::minethd_alloc_ctx(); + uint64_t iCount = 0; + cpu_ctx = cpu::minethd::minethd_alloc_ctx(); if(cpu_ctx == nullptr) { printer::inst()->print_msg(L0, "ERROR: miner was not able to allocate memory, miner will be stopped."); win_exit(1); } - // start with root algorithm and switch later if fork version is reached - auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); - cn_hash_fun hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + // start with root algorithm and switch later if fork version is reached + auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); + cn_hash_fun hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); - uint8_t version = 0; - size_t lastPoolId = 0; + uint8_t version = 0; + size_t lastPoolId = 0; - while (bQuit == 0) - { - if (oWork.bStall) + while (!bQuit) { - /* We are stalled here because the executor didn't find a job for us yet, - * either because of network latency, or a socket problem. Since we are - * raison d'etre of this software it us sensible to just wait until we have something - */ - - while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (oWork.bStall) + { + /* We are stalled here because the executor didn't find a job for us yet, + * either because of network latency, or a socket problem. Since we are + * raison d'etre of this software it us sensible to just wait until we have something + */ - globalStates::inst().consume_work(oWork, iJobNo); - continue; - } + while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); - uint8_t new_version = oWork.getVersion(); - if(new_version != version || oWork.iPoolId != lastPoolId) - { - coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); - if(new_version >= coinDesc.GetMiningForkVersion()) - { - miner_algo = coinDesc.GetMiningAlgo(); - hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + globalStates::inst().consume_work(oWork, iJobNo); + continue; } else - { - miner_algo = coinDesc.GetMiningAlgoRoot(); - hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); - } - lastPoolId = oWork.iPoolId; - version = new_version; - } - - uint32_t h_per_round = pGpuCtx->rawIntensity; - size_t round_ctr = 0; - - assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); - uint64_t target = oWork.iTarget; - - XMRSetJob(pGpuCtx, oWork.bWorkBlob, oWork.iWorkSize, target, miner_algo); - - if(oWork.bNiceHash) - pGpuCtx->Nonce = *(uint32_t*)(oWork.bWorkBlob + 39); + globalStates::inst().consume_work(oWork, iJobNo); - while(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - { - //Allocate a new nonce every 16 rounds - if((round_ctr++ & 0xF) == 0) + uint8_t new_version = oWork.getVersion(); + if(new_version != version || oWork.iPoolId != lastPoolId) { - globalStates::inst().calc_start_nonce(pGpuCtx->Nonce, oWork.bNiceHash, h_per_round * 16); - // check if the job is still valid, there is a small possibility that the job is switched - if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) - break; + coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); + if(new_version >= coinDesc.GetMiningForkVersion()) + { + miner_algo = coinDesc.GetMiningAlgo(); + hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + } + else + { + miner_algo = coinDesc.GetMiningAlgoRoot(); + hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + } + lastPoolId = oWork.iPoolId; + version = new_version; } + uint32_t h_per_round = pGpuCtx->rawIntensity; + size_t round_ctr = 0; - cl_uint results[0x100]; - memset(results,0,sizeof(cl_uint)*(0x100)); - - XMRRunJob(pGpuCtx, results, miner_algo); - - for(size_t i = 0; i < results[0xFF]; i++) - { - uint8_t bWorkBlob[112]; - uint8_t bResult[32]; + assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); + uint64_t target = oWork.iTarget; - memcpy(bWorkBlob, oWork.bWorkBlob, oWork.iWorkSize); - memset(bResult, 0, sizeof(job_result::bResult)); + XMRSetJob(pGpuCtx, oWork.bWorkBlob, oWork.iWorkSize, target, miner_algo); - *(uint32_t*)(bWorkBlob + 39) = results[i]; + if(oWork.bNiceHash) + pGpuCtx->Nonce = *(uint32_t*)(oWork.bWorkBlob + 39); - hash_fun(bWorkBlob, oWork.iWorkSize, bResult, &cpu_ctx); - if ( (*((uint64_t*)(bResult + 24))) < oWork.iTarget) - executor::inst()->push_event(ex_event(job_result(oWork.sJobID, results[i], bResult, iThreadNo, miner_algo), oWork.iPoolId)); - else - executor::inst()->push_event(ex_event("AMD Invalid Result", pGpuCtx->deviceIdx, oWork.iPoolId)); + while(!bQuit && globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) + { + //Allocate a new nonce every 16 rounds + if((round_ctr++ & 0xF) == 0) + { + globalStates::inst().calc_start_nonce(pGpuCtx->Nonce, oWork.bNiceHash, h_per_round * 16); + // check if the job is still valid, there is a small possibility that the job is switched + if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) + break; + } + + + cl_uint results[0x100]; + memset(results,0,sizeof(cl_uint)*(0x100)); + + XMRRunJob(pGpuCtx, results, miner_algo); + + for(size_t i = 0; i < results[0xFF]; i++) + { + uint8_t bWorkBlob[112]; + uint8_t bResult[32]; + + memcpy(bWorkBlob, oWork.bWorkBlob, oWork.iWorkSize); + memset(bResult, 0, sizeof(job_result::bResult)); + + *(uint32_t*)(bWorkBlob + 39) = results[i]; + + hash_fun(bWorkBlob, oWork.iWorkSize, bResult, &cpu_ctx); + if ( (*((uint64_t*)(bResult + 24))) < oWork.iTarget) + executor::inst()->push_event(ex_event(job_result(oWork.sJobID, results[i], bResult, iThreadNo, miner_algo), oWork.iPoolId)); + else + executor::inst()->push_event(ex_event("AMD Invalid Result", pGpuCtx->deviceIdx, oWork.iPoolId)); + } + + iCount += pGpuCtx->rawIntensity; + uint64_t iStamp = get_timestamp_ms(); + iHashCount.store(iCount, std::memory_order_relaxed); + iTimestamp.store(iStamp, std::memory_order_relaxed); + std::this_thread::yield(); } - iCount += pGpuCtx->rawIntensity; - uint64_t iStamp = get_timestamp_ms(); - iHashCount.store(iCount, std::memory_order_relaxed); - iTimestamp.store(iStamp, std::memory_order_relaxed); - std::this_thread::yield(); } + } + catch(...) + { + win_exit(1); + } - globalStates::inst().consume_work(oWork, iJobNo); + try + { + cryptonight_free_ctx(cpu_ctx); + FinalizeOpenCL(pGpuCtx); + } + catch(...) + { + win_exit(1); } + shutdownFinished = true; } } // namespace amd diff --git a/xmrstak/backend/amd/minethd.hpp b/xmrstak/backend/amd/minethd.hpp index 32e66ec87..ddba5eb75 100644 --- a/xmrstak/backend/amd/minethd.hpp +++ b/xmrstak/backend/amd/minethd.hpp @@ -40,11 +40,10 @@ class minethd : public iBackend std::thread oWorkThd; int64_t affinity; - bool bQuit; bool bNoPrefetch; //Mutable ptr to vector below, different for each thread - GpuContext* pGpuCtx; + GpuContext* pGpuCtx = nullptr; // WARNING - this vector (but not its contents) must be immutable // once the threads are started diff --git a/xmrstak/backend/cpu/minethd.cpp b/xmrstak/backend/cpu/minethd.cpp index a9f18d1b0..fd2ee6f45 100644 --- a/xmrstak/backend/cpu/minethd.cpp +++ b/xmrstak/backend/cpu/minethd.cpp @@ -665,26 +665,30 @@ void minethd::prep_multiway_work(uint8_t *bWorkBlob, uint32_t **piNonce) template void minethd::multiway_work_main() { - if(affinity >= 0) //-1 means no affinity - bindMemoryToNUMANode(affinity); - - order_fix.set_value(); - std::unique_lock lck(thd_aff_set); - lck.release(); - std::this_thread::yield(); - cryptonight_ctx *ctx[MAX_N]; - uint64_t iCount = 0; - uint64_t *piHashVal[MAX_N]; - uint32_t *piNonce[MAX_N]; - uint8_t bHashOut[MAX_N * 32]; - uint8_t bWorkBlob[sizeof(miner_work::bWorkBlob) * MAX_N]; - uint32_t iNonce; - job_result res; - - for (size_t i = 0; i < N; i++) + for(size_t i = 0; i < MAX_N; ++i) + ctx[i] = nullptr; + try { - ctx[i] = minethd_alloc_ctx(); + if(affinity >= 0) //-1 means no affinity + bindMemoryToNUMANode(affinity); + order_fix.set_value(); + std::unique_lock lck(thd_aff_set); + lck.release(); + std::this_thread::yield(); + + + uint64_t iCount = 0; + uint64_t *piHashVal[MAX_N]; + uint32_t *piNonce[MAX_N]; + uint8_t bHashOut[MAX_N * 32]; + uint8_t bWorkBlob[sizeof(miner_work::bWorkBlob) * MAX_N]; + uint32_t iNonce; + job_result res; + + for (size_t i = 0; i < N; i++) + { + ctx[i] = minethd_alloc_ctx(); if(ctx[i] == nullptr) { printer::inst()->print_msg(L0, "ERROR: miner was not able to allocate memory."); @@ -692,107 +696,124 @@ void minethd::multiway_work_main() cryptonight_free_ctx(ctx[j]); win_exit(1); } - piHashVal[i] = (uint64_t*)(bHashOut + 32 * i + 24); - piNonce[i] = (i == 0) ? (uint32_t*)(bWorkBlob + 39) : nullptr; - } - - if(!oWork.bStall) - prep_multiway_work(bWorkBlob, piNonce); - - globalStates::inst().iConsumeCnt++; - - // start with root algorithm and switch later if fork version is reached - auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); - cn_hash_fun hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); - uint8_t version = 0; - size_t lastPoolId = 0; - - while (bQuit == 0) - { - if (oWork.bStall) - { - /* We are stalled here because the executor didn't find a job for us yet, - either because of network latency, or a socket problem. Since we are - raison d'etre of this software it us sensible to just wait until we have something*/ - - while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - globalStates::inst().consume_work(oWork, iJobNo); - prep_multiway_work(bWorkBlob, piNonce); - continue; + piHashVal[i] = (uint64_t*)(bHashOut + 32 * i + 24); + piNonce[i] = (i == 0) ? (uint32_t*)(bWorkBlob + 39) : nullptr; } - constexpr uint32_t nonce_chunk = 4096; - int64_t nonce_ctr = 0; + if(!oWork.bStall) + prep_multiway_work(bWorkBlob, piNonce); - assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); + globalStates::inst().iConsumeCnt++; - if(oWork.bNiceHash) - iNonce = *piNonce[0]; + // start with root algorithm and switch later if fork version is reached + auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); + cn_hash_fun hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); + uint8_t version = 0; + size_t lastPoolId = 0; - uint8_t new_version = oWork.getVersion(); - if(new_version != version || oWork.iPoolId != lastPoolId) + while(!bQuit) { - coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); - if(new_version >= coinDesc.GetMiningForkVersion()) + if (oWork.bStall) { - miner_algo = coinDesc.GetMiningAlgo(); - hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); + /* We are stalled here because the executor didn't find a job for us yet, + either because of network latency, or a socket problem. Since we are + raison d'etre of this software it us sensible to just wait until we have something*/ + + while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + globalStates::inst().consume_work(oWork, iJobNo); + prep_multiway_work(bWorkBlob, piNonce); + continue; } else { - miner_algo = coinDesc.GetMiningAlgoRoot(); - hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); + globalStates::inst().consume_work(oWork, iJobNo); + prep_multiway_work(bWorkBlob, piNonce); } - lastPoolId = oWork.iPoolId; - version = new_version; - } - while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - { - if ((iCount++ & 0x7) == 0) //Store stats every 8*N hashes + constexpr uint32_t nonce_chunk = 4096; + int64_t nonce_ctr = 0; + + assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); + + if(oWork.bNiceHash) + iNonce = *piNonce[0]; + + uint8_t new_version = oWork.getVersion(); + if(new_version != version || oWork.iPoolId != lastPoolId) { - uint64_t iStamp = get_timestamp_ms(); - iHashCount.store(iCount * N, std::memory_order_relaxed); - iTimestamp.store(iStamp, std::memory_order_relaxed); + coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); + if(new_version >= coinDesc.GetMiningForkVersion()) + { + miner_algo = coinDesc.GetMiningAlgo(); + hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); + } + else + { + miner_algo = coinDesc.GetMiningAlgoRoot(); + hash_fun_multi = func_multi_selector(::jconf::inst()->HaveHardwareAes(), bNoPrefetch, miner_algo, asm_version_str); + } + lastPoolId = oWork.iPoolId; + version = new_version; } - nonce_ctr -= N; - if(nonce_ctr <= 0) + while(!bQuit && globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) { - globalStates::inst().calc_start_nonce(iNonce, oWork.bNiceHash, nonce_chunk); - nonce_ctr = nonce_chunk; - // check if the job is still valid, there is a small posibility that the job is switched - if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) - break; - } + if ((iCount++ & 0x7) == 0) //Store stats every 8*N hashes + { + uint64_t iStamp = get_timestamp_ms(); + iHashCount.store(iCount * N, std::memory_order_relaxed); + iTimestamp.store(iStamp, std::memory_order_relaxed); + } - for (size_t i = 0; i < N; i++) - *piNonce[i] = iNonce++; + nonce_ctr -= N; + if(nonce_ctr <= 0) + { + globalStates::inst().calc_start_nonce(iNonce, oWork.bNiceHash, nonce_chunk); + nonce_ctr = nonce_chunk; + // check if the job is still valid, there is a small posibility that the job is switched + if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) + break; + } - hash_fun_multi(bWorkBlob, oWork.iWorkSize, bHashOut, ctx); + for (size_t i = 0; i < N; i++) + *piNonce[i] = iNonce++; - for (size_t i = 0; i < N; i++) - { - if (*piHashVal[i] < oWork.iTarget) + hash_fun_multi(bWorkBlob, oWork.iWorkSize, bHashOut, ctx); + + for (size_t i = 0; i < N; i++) { - executor::inst()->push_event( - ex_event(job_result(oWork.sJobID, iNonce - N + i, bHashOut + 32 * i, iThreadNo, miner_algo), - oWork.iPoolId) - ); + if (*piHashVal[i] < oWork.iTarget) + { + executor::inst()->push_event( + ex_event(job_result(oWork.sJobID, iNonce - N + i, bHashOut + 32 * i, iThreadNo, miner_algo), + oWork.iPoolId) + ); + } } - } - std::this_thread::yield(); + std::this_thread::yield(); + } } - globalStates::inst().consume_work(oWork, iJobNo); - prep_multiway_work(bWorkBlob, piNonce); + } + catch(...) + { + win_exit(1); } - for (int i = 0; i < N; i++) - cryptonight_free_ctx(ctx[i]); + try + { + for (int i = 0; i < N; i++) + cryptonight_free_ctx(ctx[i]); + } + catch(...) + { + win_exit(1); + } + shutdownFinished = true; + } } // namespace cpu diff --git a/xmrstak/backend/cpu/minethd.hpp b/xmrstak/backend/cpu/minethd.hpp index eb77749f6..c2cd773a3 100644 --- a/xmrstak/backend/cpu/minethd.hpp +++ b/xmrstak/backend/cpu/minethd.hpp @@ -58,7 +58,6 @@ class minethd : public iBackend std::thread oWorkThd; int64_t affinity; - bool bQuit; bool bNoPrefetch; std::string asm_version_str = "off"; }; diff --git a/xmrstak/backend/iBackend.hpp b/xmrstak/backend/iBackend.hpp index 18411b79c..d105b778d 100644 --- a/xmrstak/backend/iBackend.hpp +++ b/xmrstak/backend/iBackend.hpp @@ -41,10 +41,22 @@ namespace xmrstak std::atomic iTimestamp; uint32_t iThreadNo; BackendType backendType = UNKNOWN; + volatile bool bQuit = false; + volatile bool shutdownFinished = false; iBackend() : iHashCount(0), iTimestamp(0) { } + + void shutdown() + { + bQuit = true; + } + + bool isShutdownFinished() + { + return shutdownFinished; + } }; } // namespace xmrstak diff --git a/xmrstak/backend/nvidia/minethd.cpp b/xmrstak/backend/nvidia/minethd.cpp index 135f26ea9..52158933b 100644 --- a/xmrstak/backend/nvidia/minethd.cpp +++ b/xmrstak/backend/nvidia/minethd.cpp @@ -200,128 +200,150 @@ std::vector* minethd::thread_starter(uint32_t threadOffset, miner_wor void minethd::work_main() { - if(affinity >= 0) //-1 means no affinity - bindMemoryToNUMANode(affinity); - - if(cuda_get_deviceinfo(&ctx) != 0 || cryptonight_extra_cpu_init(&ctx) != 1) + cryptonight_ctx* cpu_ctx = nullptr; + try { - printer::inst()->print_msg(L0, "Setup failed for GPU %d. Exiting.\n", (int)iThreadNo); - std::exit(0); - } + if(affinity >= 0) //-1 means no affinity + bindMemoryToNUMANode(affinity); - // numa memory bind and gpu memory is initialized - numa_promise.set_value(); - - std::this_thread::yield(); - // wait until all NVIDIA devices are initialized - thread_work_guard.wait(); + if(cuda_get_deviceinfo(&ctx) != 0 || cryptonight_extra_cpu_init(&ctx) != 1) + { + printer::inst()->print_msg(L0, "Setup failed for GPU %d. Exiting.\n", (int)iThreadNo); + std::exit(0); + } - uint64_t iCount = 0; - cryptonight_ctx* cpu_ctx; - cpu_ctx = cpu::minethd::minethd_alloc_ctx(); + // numa memory bind and gpu memory is initialized + numa_promise.set_value(); - // start with root algorithm and switch later if fork version is reached - auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); - cn_hash_fun hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + std::this_thread::yield(); + // wait until all NVIDIA devices are initialized + thread_work_guard.wait(); - uint32_t iNonce; + uint64_t iCount = 0; + + cpu_ctx = cpu::minethd::minethd_alloc_ctx(); - uint8_t version = 0; - size_t lastPoolId = 0; + // start with root algorithm and switch later if fork version is reached + auto miner_algo = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgoRoot(); + cn_hash_fun hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); - while (bQuit == 0) - { - if (oWork.bStall) - { - /* We are stalled here because the executor didn't find a job for us yet, - * either because of network latency, or a socket problem. Since we are - * raison d'etre of this software it us sensible to just wait until we have something - */ + uint32_t iNonce; - while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + uint8_t version = 0; + size_t lastPoolId = 0; - globalStates::inst().consume_work(oWork, iJobNo); - continue; - } - uint8_t new_version = oWork.getVersion(); - if(new_version != version || oWork.iPoolId != lastPoolId) + while (!bQuit) { - coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); - if(new_version >= coinDesc.GetMiningForkVersion()) + if (oWork.bStall) { - miner_algo = coinDesc.GetMiningAlgo(); - hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + /* We are stalled here because the executor didn't find a job for us yet, + * either because of network latency, or a socket problem. Since we are + * raison d'etre of this software it us sensible to just wait until we have something + */ + + while (globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + globalStates::inst().consume_work(oWork, iJobNo); + continue; } else + globalStates::inst().consume_work(oWork, iJobNo); + + + uint8_t new_version = oWork.getVersion(); + if(new_version != version || oWork.iPoolId != lastPoolId) { - miner_algo = coinDesc.GetMiningAlgoRoot(); - hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + coinDescription coinDesc = ::jconf::inst()->GetCurrentCoinSelection().GetDescription(oWork.iPoolId); + if(new_version >= coinDesc.GetMiningForkVersion()) + { + miner_algo = coinDesc.GetMiningAlgo(); + hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + } + else + { + miner_algo = coinDesc.GetMiningAlgoRoot(); + hash_fun = cpu::minethd::func_selector(::jconf::inst()->HaveHardwareAes(), true /*bNoPrefetch*/, miner_algo); + } + lastPoolId = oWork.iPoolId; + version = new_version; } - lastPoolId = oWork.iPoolId; - version = new_version; - } - cryptonight_extra_cpu_set_data(&ctx, oWork.bWorkBlob, oWork.iWorkSize); + cryptonight_extra_cpu_set_data(&ctx, oWork.bWorkBlob, oWork.iWorkSize); - uint32_t h_per_round = ctx.device_blocks * ctx.device_threads; - size_t round_ctr = 0; + uint32_t h_per_round = ctx.device_blocks * ctx.device_threads; + size_t round_ctr = 0; - assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); + assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID)); - if(oWork.bNiceHash) - iNonce = *(uint32_t*)(oWork.bWorkBlob + 39); + if(oWork.bNiceHash) + iNonce = *(uint32_t*)(oWork.bWorkBlob + 39); - while(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) - { - //Allocate a new nonce every 16 rounds - if((round_ctr++ & 0xF) == 0) + while(!bQuit && globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo) { - globalStates::inst().calc_start_nonce(iNonce, oWork.bNiceHash, h_per_round * 16); - // check if the job is still valid, there is a small possibility that the job is switched - if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) - break; - } + //Allocate a new nonce every 16 rounds + if((round_ctr++ & 0xF) == 0) + { + globalStates::inst().calc_start_nonce(iNonce, oWork.bNiceHash, h_per_round * 16); + // check if the job is still valid, there is a small possibility that the job is switched + if(globalStates::inst().iGlobalJobNo.load(std::memory_order_relaxed) != iJobNo) + break; + } - uint32_t foundNonce[10]; - uint32_t foundCount; + uint32_t foundNonce[10]; + uint32_t foundCount; - cryptonight_extra_cpu_prepare(&ctx, iNonce, miner_algo); + cryptonight_extra_cpu_prepare(&ctx, iNonce, miner_algo); - cryptonight_core_cpu_hash(&ctx, miner_algo, iNonce); + cryptonight_core_cpu_hash(&ctx, miner_algo, iNonce); - cryptonight_extra_cpu_final(&ctx, iNonce, oWork.iTarget, &foundCount, foundNonce, miner_algo); + cryptonight_extra_cpu_final(&ctx, iNonce, oWork.iTarget, &foundCount, foundNonce, miner_algo); - for(size_t i = 0; i < foundCount; i++) - { + for(size_t i = 0; i < foundCount; i++) + { - uint8_t bWorkBlob[112]; - uint8_t bResult[32]; + uint8_t bWorkBlob[112]; + uint8_t bResult[32]; - memcpy(bWorkBlob, oWork.bWorkBlob, oWork.iWorkSize); - memset(bResult, 0, sizeof(job_result::bResult)); + memcpy(bWorkBlob, oWork.bWorkBlob, oWork.iWorkSize); + memset(bResult, 0, sizeof(job_result::bResult)); - *(uint32_t*)(bWorkBlob + 39) = foundNonce[i]; + *(uint32_t*)(bWorkBlob + 39) = foundNonce[i]; - hash_fun(bWorkBlob, oWork.iWorkSize, bResult, &cpu_ctx); - if ( (*((uint64_t*)(bResult + 24))) < oWork.iTarget) - executor::inst()->push_event(ex_event(job_result(oWork.sJobID, foundNonce[i], bResult, iThreadNo, miner_algo), oWork.iPoolId)); - else - executor::inst()->push_event(ex_event("NVIDIA Invalid Result", ctx.device_id, oWork.iPoolId)); - } + hash_fun(bWorkBlob, oWork.iWorkSize, bResult, &cpu_ctx); + if ( (*((uint64_t*)(bResult + 24))) < oWork.iTarget) + executor::inst()->push_event(ex_event(job_result(oWork.sJobID, foundNonce[i], bResult, iThreadNo, miner_algo), oWork.iPoolId)); + else + executor::inst()->push_event(ex_event("NVIDIA Invalid Result", ctx.device_id, oWork.iPoolId)); + } - iCount += h_per_round; - iNonce += h_per_round; + iCount += h_per_round; + iNonce += h_per_round; - using namespace std::chrono; - uint64_t iStamp = get_timestamp_ms(); - iHashCount.store(iCount, std::memory_order_relaxed); - iTimestamp.store(iStamp, std::memory_order_relaxed); - std::this_thread::yield(); + using namespace std::chrono; + uint64_t iStamp = get_timestamp_ms(); + iHashCount.store(iCount, std::memory_order_relaxed); + iTimestamp.store(iStamp, std::memory_order_relaxed); + std::this_thread::yield(); + } } + } + catch(...) + { + win_exit(1); + } - globalStates::inst().consume_work(oWork, iJobNo); + try + { + cryptonight_free_ctx(cpu_ctx); + cryptonight_extra_cpu_finalize(&ctx); } + catch(...) + { + win_exit(1); + } + + shutdownFinished = true; } } // namespace xmrstak diff --git a/xmrstak/backend/nvidia/minethd.hpp b/xmrstak/backend/nvidia/minethd.hpp index 389356842..6dc8f5dfb 100644 --- a/xmrstak/backend/nvidia/minethd.hpp +++ b/xmrstak/backend/nvidia/minethd.hpp @@ -52,8 +52,6 @@ class minethd : public iBackend int64_t affinity; nvid_ctx ctx; - - bool bQuit; }; } // namespace nvidia diff --git a/xmrstak/backend/nvidia/nvcc_code/cryptonight.hpp b/xmrstak/backend/nvidia/nvcc_code/cryptonight.hpp index 8167395e3..124129578 100644 --- a/xmrstak/backend/nvidia/nvcc_code/cryptonight.hpp +++ b/xmrstak/backend/nvidia/nvcc_code/cryptonight.hpp @@ -8,7 +8,7 @@ typedef struct { int device_id; - const char *device_name; + const char *device_name = nullptr; int device_arch[2]; int device_mpcount; int device_blocks; @@ -18,18 +18,18 @@ typedef struct { int syncMode; bool compMode; - uint32_t *d_input; + uint32_t *d_input = nullptr; uint32_t inputlen; - uint32_t *d_result_count; - uint32_t *d_result_nonce; - uint32_t *d_long_state; - uint32_t *d_ctx_state; - uint32_t *d_ctx_state2; - uint32_t *d_ctx_a; - uint32_t *d_ctx_b; - uint32_t *d_ctx_key1; - uint32_t *d_ctx_key2; - uint32_t *d_ctx_text; + uint32_t *d_result_count = nullptr; + uint32_t *d_result_nonce = nullptr; + uint32_t *d_long_state = nullptr; + uint32_t *d_ctx_state = nullptr; + uint32_t *d_ctx_state2 = nullptr; + uint32_t *d_ctx_a = nullptr; + uint32_t *d_ctx_b = nullptr; + uint32_t *d_ctx_key1 = nullptr; + uint32_t *d_ctx_key2 = nullptr; + uint32_t *d_ctx_text = nullptr; std::string name; size_t free_device_memory; size_t total_device_memory; @@ -48,6 +48,7 @@ int cryptonight_extra_cpu_init(nvid_ctx *ctx); void cryptonight_extra_cpu_set_data( nvid_ctx* ctx, const void *data, uint32_t len); void cryptonight_extra_cpu_prepare(nvid_ctx* ctx, uint32_t startNonce, xmrstak_algo miner_algo); void cryptonight_extra_cpu_final(nvid_ctx* ctx, uint32_t startNonce, uint64_t target, uint32_t* rescount, uint32_t *resnonce,xmrstak_algo miner_algo); +void cryptonight_extra_cpu_finalize(nvid_ctx *ctx); } void cryptonight_core_cpu_hash(nvid_ctx* ctx, xmrstak_algo miner_algo, uint32_t startNonce); diff --git a/xmrstak/backend/nvidia/nvcc_code/cuda_extra.cu b/xmrstak/backend/nvidia/nvcc_code/cuda_extra.cu index 433e175dd..3343f3e8a 100644 --- a/xmrstak/backend/nvidia/nvcc_code/cuda_extra.cu +++ b/xmrstak/backend/nvidia/nvcc_code/cuda_extra.cu @@ -331,6 +331,22 @@ extern "C" int cryptonight_extra_cpu_init(nvid_ctx* ctx) return 1; } +extern "C" void cryptonight_extra_cpu_finalize(nvid_ctx *ctx) +{ + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_state)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_state2)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_key1)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_key2)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_text)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_a)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_ctx_b)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_input)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_result_count)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_result_nonce)); + CUDA_CHECK(ctx->device_id, cudaFree(ctx->d_long_state)); + CUDA_CHECK(ctx->device_id, cudaDeviceReset()); +} + extern "C" void cryptonight_extra_cpu_prepare(nvid_ctx* ctx, uint32_t startNonce, xmrstak_algo miner_algo) { int threadsperblock = 128; diff --git a/xmrstak/cli/cli-miner.cpp b/xmrstak/cli/cli-miner.cpp index 428952b1b..9d9c174cd 100644 --- a/xmrstak/cli/cli-miner.cpp +++ b/xmrstak/cli/cli-miner.cpp @@ -787,6 +787,7 @@ int main(int argc, char *argv[]) printer::inst()->print_str("'h' - hashrate\n"); printer::inst()->print_str("'r' - results\n"); printer::inst()->print_str("'c' - connection\n"); + printer::inst()->print_str("'q' - shutdown/exit\n"); printer::inst()->print_str("-------------------------------------------------------------------\n"); printer::inst()->print_msg(L0, "Mining coin: %s", jconf::inst()->GetMiningCoin().c_str()); @@ -796,24 +797,38 @@ int main(int argc, char *argv[]) return do_benchmark(params::inst().benchmark_block_version, params::inst().benchmark_wait_sec, params::inst().benchmark_work_sec); } - executor::inst()->ex_start(jconf::inst()->DaemonMode()); + auto exec = executor::inst(); + exec->ex_start(jconf::inst()->DaemonMode()); + if(jconf::inst()->DaemonMode()) + { + executor::inst()->shutdown(); + return 0; + } uint64_t lastTime = get_timestamp_ms(); int key; - while(true) + bool stopMiner = false; + + + bool forceQuit = false; + while(!forceQuit && !exec->isShutdownFinished()) { key = get_key(); switch(key) { case 'h': - executor::inst()->push_event(ex_event(EV_USR_HASHRATE)); + exec->push_event(ex_event(EV_USR_HASHRATE)); break; case 'r': - executor::inst()->push_event(ex_event(EV_USR_RESULTS)); + exec->push_event(ex_event(EV_USR_RESULTS)); break; case 'c': - executor::inst()->push_event(ex_event(EV_USR_CONNSTAT)); + exec->push_event(ex_event(EV_USR_CONNSTAT)); + break; + case 'q': + exec->push_event(ex_event(EV_USR_SHUTDOWN)); + forceQuit = true; break; default: break; @@ -826,7 +841,8 @@ int main(int argc, char *argv[]) std::this_thread::sleep_for(std::chrono::milliseconds(500 - (currentTime - lastTime))); lastTime = currentTime; } - + + exec->shutdown(); return 0; } diff --git a/xmrstak/misc/console.cpp b/xmrstak/misc/console.cpp index c39237eab..b30785bc3 100644 --- a/xmrstak/misc/console.cpp +++ b/xmrstak/misc/console.cpp @@ -22,6 +22,7 @@ */ #include "xmrstak/misc/console.hpp" +#include "xmrstak/misc/executor.hpp" #include #include @@ -212,6 +213,7 @@ void printer::print_str(const char* str) #ifdef _WIN32 void win_exit(int code) { + executor::inst()->shutdown(); size_t envSize = 0; getenv_s(&envSize, nullptr, 0, "XMRSTAK_NOWAIT"); if(envSize == 0) @@ -225,6 +227,7 @@ void win_exit(int code) #else void win_exit(int code) { + executor::inst()->shutdown(); std::exit(code); } #endif // _WIN32 diff --git a/xmrstak/misc/executor.cpp b/xmrstak/misc/executor.cpp index 4fcce1f97..c50e119c6 100644 --- a/xmrstak/misc/executor.cpp +++ b/xmrstak/misc/executor.cpp @@ -63,7 +63,7 @@ void executor::push_timed_event(ex_event&& ev, size_t sec) void executor::ex_clock_thd() { size_t tick = 0; - while (true) + while(!bQuit) { std::this_thread::sleep_for(std::chrono::milliseconds(size_t(iTickTime))); @@ -601,7 +601,7 @@ void executor::ex_main() push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime()); size_t cnt = 0; - while (true) + while(!bQuit) { ev = oEventQ.pop(); switch (ev.iName) @@ -677,6 +677,9 @@ void executor::ex_main() print_report(EV_USR_HASHRATE); push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime()); break; + case EV_USR_SHUTDOWN: + shutdown(); + break; case EV_INVALID_VAL: default: @@ -684,6 +687,8 @@ void executor::ex_main() break; } } + // wait until thread is finished + clock_thd.join(); } inline const char* hps_format(double h, char* buf, size_t l) @@ -997,6 +1002,45 @@ void executor::print_report(ex_event_name ev) printer::inst()->print_str(out.c_str()); } +void executor::shutdown() +{ + // if shutdown is called the first time + if(!bQuit) + { + bQuit = true; + std::cout<<"Shutdown miner, this takes up to 15 sec ..."<shutdown(); + + bool canClose = true; + size_t round = 0u; + do + { + canClose = true; + for(auto& backend : *pvThreads) + { + if(!backend->isShutdownFinished()) + { + canClose = false; + break; + } + } + + if(!canClose) + std::this_thread::sleep_for(std::chrono::milliseconds(500u)); + ++round; + } + while(!canClose && round < 30); // wait max 15 sec + shutdownFinished = true; + } +} + +bool executor::isShutdownFinished() +{ + return shutdownFinished; +} + void executor::http_hashrate_report(std::string& out) { char num_a[32], num_b[32], num_c[32], num_d[32]; diff --git a/xmrstak/misc/executor.hpp b/xmrstak/misc/executor.hpp index be5ee6c2f..de88697b0 100644 --- a/xmrstak/misc/executor.hpp +++ b/xmrstak/misc/executor.hpp @@ -42,8 +42,13 @@ class executor inline void push_event(ex_event&& ev) { oEventQ.push(std::move(ev)); } void push_timed_event(ex_event&& ev, size_t sec); + void shutdown(); + bool isShutdownFinished(); + private: + bool bQuit = false; + bool shutdownFinished = false; struct timed_event { ex_event event; diff --git a/xmrstak/net/msgstruct.hpp b/xmrstak/net/msgstruct.hpp index 6a05eb9d5..31163b3ca 100644 --- a/xmrstak/net/msgstruct.hpp +++ b/xmrstak/net/msgstruct.hpp @@ -77,7 +77,7 @@ struct gpu_res_err enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR, EV_GPU_RES_ERROR, EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_EVAL_POOL_CHOICE, - EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT, EV_HASHRATE_LOOP, + EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT, EV_USR_SHUTDOWN, EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT, EV_HTML_JSON }; /* From b772eed0fda3a1a0a4b6699b3aecb3a349d9ecaa Mon Sep 17 00:00:00 2001 From: psychocrypt Date: Tue, 9 Oct 2018 23:40:36 +0200 Subject: [PATCH 2/3] handle signals HAndle signals to close the miner --- xmrstak/backend/amd/amd_gpu/gpu.cpp | 2 +- xmrstak/backend/amd/amd_gpu/gpu.hpp | 2 +- xmrstak/cli/cli-miner.cpp | 13 ++++++++++++- xmrstak/misc/executor.cpp | 5 ++--- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/xmrstak/backend/amd/amd_gpu/gpu.cpp b/xmrstak/backend/amd/amd_gpu/gpu.cpp index d12622f88..d53586add 100644 --- a/xmrstak/backend/amd/amd_gpu/gpu.cpp +++ b/xmrstak/backend/amd/amd_gpu/gpu.cpp @@ -607,7 +607,7 @@ size_t InitOpenCLGpu(cl_context opencl_ctx, GpuContext* ctx, const char* source_ return 0; } -size_t FinalizeOpenCL(GpuContext* ctx) +void FinalizeOpenCL(GpuContext* ctx) { xmrstak_algo miner_algo[2] = { ::jconf::inst()->GetCurrentCoinSelection().GetDescription(1).GetMiningAlgo(), diff --git a/xmrstak/backend/amd/amd_gpu/gpu.hpp b/xmrstak/backend/amd/amd_gpu/gpu.hpp index 20f78ba34..e5af64ff5 100644 --- a/xmrstak/backend/amd/amd_gpu/gpu.hpp +++ b/xmrstak/backend/amd/amd_gpu/gpu.hpp @@ -52,7 +52,7 @@ int getAMDPlatformIdx(); std::vector getAMDDevices(int index); size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx); -size_t FinalizeOpenCL(GpuContext* ctx); +void FinalizeOpenCL(GpuContext* ctx); size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint64_t target, xmrstak_algo miner_algo); size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput, xmrstak_algo miner_algo); diff --git a/xmrstak/cli/cli-miner.cpp b/xmrstak/cli/cli-miner.cpp index 9d9c174cd..7aca5ceb5 100644 --- a/xmrstak/cli/cli-miner.cpp +++ b/xmrstak/cli/cli-miner.cpp @@ -55,6 +55,14 @@ # include "xmrstak/misc/uac.hpp" #endif // _WIN32 +#include + +// exit miner if we receive a signal e.g. CTRL+C +void signal_handler(int signal) +{ + executor::inst()->shutdown(); +} + int do_benchmark(int block_version, int wait_sec, int work_sec); void help() @@ -747,6 +755,10 @@ int main(int argc, char *argv[]) if(strlen(jconf::inst()->GetOutputFile()) != 0) printer::inst()->open_logfile(jconf::inst()->GetOutputFile()); + std::signal(SIGINT, signal_handler); + std::signal(SIGABRT, signal_handler); + std::signal(SIGTERM, signal_handler); + if (!BackendConnector::self_test()) { printer::inst()->print_msg(L0, "Self test not passed!"); @@ -814,7 +826,6 @@ int main(int argc, char *argv[]) while(!forceQuit && !exec->isShutdownFinished()) { key = get_key(); - switch(key) { case 'h': diff --git a/xmrstak/misc/executor.cpp b/xmrstak/misc/executor.cpp index c50e119c6..d30c082ba 100644 --- a/xmrstak/misc/executor.cpp +++ b/xmrstak/misc/executor.cpp @@ -45,7 +45,6 @@ #include #include - #ifdef _WIN32 #define strncasecmp _strnicmp #endif // _WIN32 @@ -488,7 +487,7 @@ inline void disable_sigpipe() {} #endif void executor::ex_main() -{ +{ disable_sigpipe(); assert(1000 % iTickTime == 0); @@ -599,7 +598,7 @@ void executor::ex_main() // If the user requested it, start the autohash printer if(jconf::inst()->GetVerboseLevel() >= 4) push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime()); - + size_t cnt = 0; while(!bQuit) { From 22a7ce9fa7a9502424294f18ca03f46e7da644df Mon Sep 17 00:00:00 2001 From: psychocrypt Date: Wed, 10 Oct 2018 11:49:21 +0200 Subject: [PATCH 3/3] fix segfault --- xmrstak/misc/executor.cpp | 21 ++++++++++++++------- xmrstak/misc/executor.hpp | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/xmrstak/misc/executor.cpp b/xmrstak/misc/executor.cpp index d30c082ba..8be28b2c9 100644 --- a/xmrstak/misc/executor.cpp +++ b/xmrstak/misc/executor.cpp @@ -1008,21 +1008,28 @@ void executor::shutdown() { bQuit = true; std::cout<<"Shutdown miner, this takes up to 15 sec ..."<shutdown(); + + if(pvThreads != nullptr) + { + // notify all backend threads + for(auto& backend : *pvThreads) + backend->shutdown(); + } bool canClose = true; size_t round = 0u; do { canClose = true; - for(auto& backend : *pvThreads) + if(pvThreads != nullptr) { - if(!backend->isShutdownFinished()) + for(auto& backend : *pvThreads) { - canClose = false; - break; + if(!backend->isShutdownFinished()) + { + canClose = false; + break; + } } } diff --git a/xmrstak/misc/executor.hpp b/xmrstak/misc/executor.hpp index de88697b0..a0287f700 100644 --- a/xmrstak/misc/executor.hpp +++ b/xmrstak/misc/executor.hpp @@ -82,7 +82,7 @@ class executor thdq oEventQ; xmrstak::telemetry* telem; - std::vector* pvThreads; + std::vector* pvThreads = nullptr; size_t current_pool_id = invalid_pool_id; size_t last_usr_pool_id = invalid_pool_id;