remove all windows stuff from Master

This commit is contained in:
sirjonasxx 2018-10-13 23:01:15 +02:00
parent 43d6d4c80c
commit e9705b6e0e
12 changed files with 0 additions and 811 deletions

3
.gitignore vendored
View File

@ -2,7 +2,4 @@
out/
bin/
**/target/
/G-WinMem/.vs
/G-WinMem/x64
/G-WinMem/G-WinMem/x64
*.iml

View File

@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2018
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "G-WinMem", "G-WinMem\G-WinMem.vcxproj", "{D445BBD6-23E4-40AD-BB05-39E0401D7421}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x64.ActiveCfg = Debug|x64
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x64.Build.0 = Debug|x64
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x86.ActiveCfg = Debug|Win32
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x86.Build.0 = Debug|Win32
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x64.ActiveCfg = Release|x64
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x64.Build.0 = Release|x64
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x86.ActiveCfg = Release|Win32
{D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CDDBAEFF-CFB7-4167-88D9-015827207E0C}
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D445BBD6-23E4-40AD-BB05-39E0401D7421}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GWinMem</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ctpl_stl.h" />
<ClInclude Include="Process.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="thread_pool.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="G-WinMem.cpp" />
<ClCompile Include="Process.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Process.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ctpl_stl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="thread_pool.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="G-WinMem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Process.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@ -1,263 +0,0 @@
#include "ctpl_stl.h"
#include "Process.h"
#include <iostream>
#include <stdio.h>
Process::Process() : Process(0)
{}
Process::Process(int pid)
: mPid(pid),
mHandle(nullptr)
{}
bool Process::Open()
{
mHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_OPERATION, false, mPid);
return true;
}
std::vector<MemoryChunk*> Process::GetChunks()
{
return mChunks;
}
void Process::Close()
{
CloseHandle(mHandle);
}
void Process::PrintCachedResults(std::vector<u_char *> cache)
{
const auto offset = 4;
static std::mutex m;
Open();
for (auto addr : cache) {
u_char rawMem[1024] = { 0 };
if (!ReadProcessMemory(mHandle, addr, rawMem, 1024, nullptr))
{
std::cerr << "Failed to read memory at " << addr << std::endl;
return;
}
for (auto i = 0; i < (1024 - ((256 - 1) * offset)); i += offset)
{
unsigned char wannabeRC4data[1024] = { 0 };
unsigned char data[256] = { 0 };
memcpy(wannabeRC4data, rawMem + i, 1024);
auto isvalid = true;
for (auto j = 0; j < 1024; j++)
{
if (j % 4 != 0 && wannabeRC4data[j] != 0)
{
isvalid = false;
break;
}
if (j % 4 == 0)
{
data[j / 4] = wannabeRC4data[j];
}
}
if (isvalid)
{
m.lock();
for (auto idx : data)
printf("%02X", static_cast<signed char>(idx) & 0xFF);
std::cout << std::endl;
m.unlock();
}
}
}
Close();
}
void Process::PrintRC4Possibilities()
{
SYSTEM_INFO sys_info;
static std::mutex m;
GetSystemInfo(&sys_info);
Open();
FindMaps(sys_info);
const auto offset = 4;
CreateMapsForRC4();
for (auto k = 0; k < mRC4Maps.size(); k++)
{
auto mem = mRC4Maps[k];
if (mem->mSize >= 1024 && mem->mSize <= 1024 + 2 * offset)
{
for (auto i = 0; i < (mem->mSize - ((256 - 1) * offset)); i += offset)
{
unsigned char wannabeRC4data[1024] = { 0 };
unsigned char data[256] = { 0 };
memcpy(wannabeRC4data, static_cast<unsigned char *>(mem->mStart) + i, 1024);
auto isvalid = true;
for (auto j = 0; j < 1024; j++)
{
if (j % 4 != 0 && wannabeRC4data[j] != 0)
{
isvalid = false;
break;
}
if (j % 4 == 0)
{
data[j / 4] = wannabeRC4data[j];
}
}
if (isvalid)
{
m.lock();
printf("%llx\n",reinterpret_cast<unsigned long long>(mOutCache[k]));
for (auto idx : data)
printf("%02X", static_cast<signed char>(idx) & 0xFF);
std::cout << std::endl;
m.unlock();
}
}
}
delete mem;
}
Close();
}
void Process::CreateMapFromChunk(MemoryChunk *chunk)
{
const auto offset = 4;
const auto dump = new unsigned char[chunk->mSize + 1];
memset(dump, 0, chunk->mSize + 1);
if (!ReadProcessMemory(mHandle, chunk->mStart, dump, chunk->mSize, nullptr))
{
std::cerr << "Failed to read memory at: " << chunk->mStart << std::endl;
return;
}
auto maskCount = 0;
int nToMap[256] = { 0 };
int removeMap[256] = { 0 };
for (auto i = 0; i < 256; i++) {
nToMap[i] = -1;
removeMap[i] = -1;
}
auto matchStart = -1;
auto matchEnd = -1;
for (auto i = 0; i < chunk->mSize; i += offset)
{
const auto b = (static_cast<int>(dump[i]) + 128) % 256;
const auto indInMap = (i / 4) % 256;
const auto deletedNumber = removeMap[indInMap];
if (deletedNumber != -1)
{
nToMap[deletedNumber] = -1;
maskCount--;
removeMap[indInMap] = -1;
}
if (nToMap[b] == -1)
{
maskCount++;
removeMap[indInMap] = b;
nToMap[b] = indInMap;
}
else
{
removeMap[nToMap[b]] = -1;
removeMap[indInMap] = b;
nToMap[b] = indInMap;
}
if (maskCount == 256)
{
if (matchStart == -1)
{
matchStart = i - ((256 - 1) * offset);
matchEnd = i;
}
if (matchEnd < i - ((256 - 1) * offset))
{
//printf("maybeValid -> %p\n", static_cast<u_char*>(chunk->mStart) + matchStart);
mOutCache.push_back(static_cast<u_char *>(chunk->mStart) + matchStart);
mRC4Maps.push_back(new MemoryChunk(dump + matchStart, matchEnd - matchStart + 4));
matchStart = i - ((256 - 1) * offset);
}
matchEnd = i;
}
}
if (matchStart != -1)
{
mOutCache.push_back(static_cast<u_char*>(chunk->mStart) + matchStart);
mRC4Maps.push_back(new MemoryChunk(dump + matchStart, matchEnd - matchStart + 4));
}
delete chunk;
}
void Process::CreateMapsForRC4()
{
ctpl::thread_pool p(5);
for (auto chunk : mChunks) {
p.push(std::bind(&Process::CreateMapFromChunk, this, chunk));
}
p.stop(true);
}
void Process::FindMaps(SYSTEM_INFO sys_info)
{
auto addr = reinterpret_cast<uintptr_t>(sys_info.lpMinimumApplicationAddress);
const auto end = reinterpret_cast<uintptr_t>(sys_info.lpMaximumApplicationAddress);
MEMORY_BASIC_INFORMATION mbi;
while (addr < end) {
if (!VirtualQueryEx(mHandle, reinterpret_cast<LPCVOID>(addr), &mbi, sizeof(mbi))) {
std::cerr << "Failed to get memory maps\n";
return;
}
if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_GUARD) == 0) && ((mbi.Protect & PAGE_NOACCESS) == 0)) {
mChunks.push_back(new MemoryChunk(reinterpret_cast<LPVOID>(addr), mbi.RegionSize));
}
addr += mbi.RegionSize;
}
}
Process::~Process()
{
for (auto m : mChunks)
delete m;
for (auto m : mRC4Maps)
delete m;
}

View File

@ -1,40 +0,0 @@
#pragma once
#include <Windows.h>
#include <vector>
class MemoryChunk
{
public:
MemoryChunk(LPVOID start, SIZE_T size);
LPVOID mStart;
SIZE_T mSize;
};
inline MemoryChunk::MemoryChunk(LPVOID start, SIZE_T size) :
mStart(start),
mSize(size)
{}
class Process
{
public:
Process();
Process(int pid);
bool Open();
void Close();
void FindMaps(SYSTEM_INFO sys_info);
void CreateMapsForRC4();
void CreateMapFromChunk(MemoryChunk *chunk);
void PrintRC4Possibilities();
void PrintCachedResults(std::vector<u_char *> cache);
~Process();
std::vector<MemoryChunk*> GetChunks();
private:
int mPid;
HANDLE mHandle;
std::vector<MemoryChunk*> mChunks;
std::vector<MemoryChunk*> mRC4Maps;
std::vector<LPVOID> mOutCache;
};

View File

@ -1,256 +0,0 @@
/*********************************************************
*
* Copyright (C) 2014 by Vitaliy Vitsentiy
*
* 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
*
* http://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 __ctpl_stl_thread_pool_H__
#define __ctpl_stl_thread_pool_H__
#include <functional>
#include <thread>
#include <atomic>
#include <vector>
#include <memory>
#include <exception>
#include <future>
#include <mutex>
#include <queue>
// thread pool to run user's functors with signature
// ret func(int id, other_params)
// where id is the index of the thread that runs the functor
// ret is some return type
namespace ctpl {
namespace detail {
template <typename T>
class Queue {
public:
bool push(T const & value) {
std::unique_lock<std::mutex> lock(this->mutex);
this->q.push(value);
return true;
}
// deletes the retrieved element, do not use for non integral types
bool pop(T & v) {
std::unique_lock<std::mutex> lock(this->mutex);
if (this->q.empty())
return false;
v = this->q.front();
this->q.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(this->mutex);
return this->q.empty();
}
private:
std::queue<T> q;
std::mutex mutex;
};
}
class thread_pool {
public:
thread_pool() { this->init(); }
thread_pool(int nThreads) { this->init(); this->resize(nThreads); }
// the destructor waits for all the functions in the queue to be finished
~thread_pool() {
this->stop(true);
}
// get the number of running threads in the pool
int size() { return static_cast<int>(this->threads.size()); }
// number of idle threads
int n_idle() { return this->nWaiting; }
int n_pending() { return this->nPending; }
std::thread & get_thread(int i) { return *this->threads[i]; }
// change the number of threads in the pool
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
// nThreads must be >= 0
void resize(int nThreads) {
if (!this->isStop && !this->isDone) {
int oldNThreads = static_cast<int>(this->threads.size());
if (oldNThreads <= nThreads) { // if the number of threads is increased
this->threads.resize(nThreads);
this->flags.resize(nThreads);
for (int i = oldNThreads; i < nThreads; ++i) {
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
this->set_thread(i);
}
}
else { // the number of threads is decreased
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
this->threads[i]->detach();
}
{
// stop the detached threads that were waiting
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
this->threads.resize(nThreads); // safe to delete because the threads are detached
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
}
}
}
// empty the queue
void clear_queue() {
std::function<void(int id)> * _f;
while (this->q.pop(_f))
delete _f; // empty the queue
}
// pops a functional wrapper to the original function
std::function<void(int)> pop() {
std::function<void(int id)> * _f = nullptr;
this->q.pop(_f);
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
std::function<void(int)> f;
if (_f)
f = *_f;
return f;
}
// wait for all computing threads to finish and stop all threads
// may be called asynchronously to not pause the calling thread while waiting
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
void stop(bool isWait = false) {
if (!isWait) {
if (this->isStop)
return;
this->isStop = true;
for (int i = 0, n = this->size(); i < n; ++i) {
*this->flags[i] = true; // command the threads to stop
}
this->clear_queue(); // empty the queue
}
else {
if (this->isDone || this->isStop)
return;
this->isDone = true; // give the waiting threads a command to finish
}
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all(); // stop all waiting threads
}
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
if (this->threads[i]->joinable())
this->threads[i]->join();
}
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
this->flags.clear();
}
template<typename F, typename... Rest>
auto push(F && f, Rest&&... rest) ->std::future<decltype(f(0, rest...))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...)
);
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
++this->nPending;
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
template<typename F>
auto push(F && f) ->std::future<decltype(f(0))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
++this->nPending;
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
private:
// deleted
thread_pool(const thread_pool &);// = delete;
thread_pool(thread_pool &&);// = delete;
thread_pool & operator=(const thread_pool &);// = delete;
thread_pool & operator=(thread_pool &&);// = delete;
void set_thread(int i) {
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
std::atomic<bool> & _flag = *flag;
std::function<void(int id)> * _f;
bool isPop = this->q.pop(_f);
while (true) {
while (isPop) { // if there is anything in the queue
--this->nPending;
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
(*_f)(i);
if (_flag)
return; // the thread is wanted to stop, return even if the queue is not empty yet
else
isPop = this->q.pop(_f);
}
// the queue is empty here, wait for the next command
std::unique_lock<std::mutex> lock(this->mutex);
++this->nWaiting;
this->cv.wait(lock, [this, &_f, &isPop, &_flag]() { isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
--this->nWaiting;
if (!isPop)
return; // if the queue is empty and this->isDone == true or *flag then return
}
};
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
}
void init() { this->nWaiting = 0; this->nPending = 0; this->isStop = false; this->isDone = false; }
std::vector<std::unique_ptr<std::thread>> threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
detail::Queue<std::function<void(int id)> *> q;
std::atomic<bool> isDone;
std::atomic<bool> isStop;
std::atomic<int> nWaiting; // how many threads are waiting
std::atomic<int> nPending; // how many tasks are waiting
std::mutex mutex;
std::condition_variable cv;
};
}
#endif // __ctpl_stl_thread_pool_H__

Binary file not shown.

Binary file not shown.

Binary file not shown.