diff --git a/include/binary_file_packer.h b/include/binary_file_packer.h index 79d14ce..bbc6f94 100644 --- a/include/binary_file_packer.h +++ b/include/binary_file_packer.h @@ -37,7 +37,6 @@ protected: virtual bool IsDuplicated(const std::unique_ptr &entry, std::string subPath); PackageParser packageParser_; std::string moduleName_; - ThreadPool threadPool_; std::vector> copyResults_; std::atomic stopCopy_{false}; std::mutex mutex_; diff --git a/include/cmd/package_parser.h b/include/cmd/package_parser.h index 2bec953..8304036 100644 --- a/include/cmd/package_parser.h +++ b/include/cmd/package_parser.h @@ -53,6 +53,7 @@ public: const std::vector &GetSysIdDefinedPaths() const; const std::string &GetCompressionPath() const; bool IsOverlap() const; + size_t GetThreadCount() const; private: void InitCommand(); @@ -83,6 +84,7 @@ private: uint32_t IconCheck(); uint32_t ParseTargetConfig(const std::string &argValue); uint32_t AddCompressionPath(const std::string &argValue); + uint32_t ParseThread(const std::string &argValue); static const struct option CMD_OPTS[]; static const std::string CMD_PARAMS; @@ -108,6 +110,7 @@ private: bool isTtargetConfig_; std::vector sysIdDefinedPaths_; std::string compressionPath_; + size_t threadCount_{ 0 }; }; } // namespace Restool } // namespace Global diff --git a/include/resconfig_parser.h b/include/resconfig_parser.h index 5fab1ea..34c01ad 100644 --- a/include/resconfig_parser.h +++ b/include/resconfig_parser.h @@ -38,6 +38,7 @@ private: uint32_t GetArray(const cJSON *node, int c, HandleBack callback); uint32_t GetModuleNames(const cJSON *node, int c, HandleBack callback); uint32_t GetBool(const cJSON *node, int c, HandleBack callback); + uint32_t GetNumber(const cJSON *node, int c, HandleBack callback); cJSON *root_; }; } diff --git a/include/resource_data.h b/include/resource_data.h index cb5e471..61f56f3 100644 --- a/include/resource_data.h +++ b/include/resource_data.h @@ -49,11 +49,11 @@ const static std::string SOLUTIONS_ARROW = "> "; const static std::string LONG_PATH_HEAD = "\\\\?\\"; const static int32_t VERSION_MAX_LEN = 128; const static int32_t INT_TO_BYTES = sizeof(uint32_t); -static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.1.0.004" }; +static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.1.0.005" }; const static int32_t TAG_LEN = 4; +constexpr static int DEFAULT_POOL_SIZE = 8; static std::set g_resourceSet; static std::set g_hapResourceSet; -const static int8_t THREAD_POOL_SIZE = 2; const static int8_t INVALID_ID = -1; enum class KeyType { @@ -147,6 +147,7 @@ enum Option { TARGET_CONFIG = 5, DEFINED_SYSIDS = 6, COMPRESSED_CONFIG = 7, + THREAD = 8, STARTID = 'e', FORCEWRITE = 'f', HELP = 'h', diff --git a/include/thread_pool.h b/include/thread_pool.h index 0efc3df..57fcace 100644 --- a/include/thread_pool.h +++ b/include/thread_pool.h @@ -30,17 +30,13 @@ namespace Global { namespace Restool { class ThreadPool { public: - /** - * @brief Creates a thread pool with specify thread count - * @param threadCount the count of threads to be created - */ - explicit ThreadPool(const size_t threadCount); ~ThreadPool(); /** * @brief Start the thread pool + * @param threadCount the count of thread pool */ - uint32_t Start(); + uint32_t Start(const size_t &threadCount); /** * @brief Stop the thread pool @@ -55,7 +51,12 @@ public: template std::future::type> Enqueue(F &&f, Args &&...args); + static ThreadPool &GetInstance(); + private: + ThreadPool(); + ThreadPool(const ThreadPool &) = delete; + ThreadPool &operator=(const ThreadPool &) = delete; void WorkInThread(); std::vector workerThreads_; std::queue> tasks_; @@ -63,7 +64,6 @@ private: std::mutex queueMutex_; std::condition_variable condition_; bool running_{ false }; - size_t threadCount_; }; template diff --git a/src/binary_file_packer.cpp b/src/binary_file_packer.cpp index dc4c3a1..8b0522c 100644 --- a/src/binary_file_packer.cpp +++ b/src/binary_file_packer.cpp @@ -24,14 +24,12 @@ namespace Restool { using namespace std; BinaryFilePacker::BinaryFilePacker(const PackageParser &packageParser, const std::string &moduleName) - : packageParser_(packageParser), moduleName_(moduleName), threadPool_(ThreadPool(THREAD_POOL_SIZE)) + : packageParser_(packageParser), moduleName_(moduleName) { - threadPool_.Start(); } BinaryFilePacker::~BinaryFilePacker() { - threadPool_.Stop(); } void BinaryFilePacker::StopCopy() @@ -42,7 +40,7 @@ void BinaryFilePacker::StopCopy() std::future BinaryFilePacker::CopyBinaryFileAsync(const std::vector &inputs) { auto func = [this](const vector &inputs) { return this->CopyBinaryFile(inputs); }; - std::future res = threadPool_.Enqueue(func, inputs); + std::future res = ThreadPool::GetInstance().Enqueue(func, inputs); return res; } @@ -126,7 +124,7 @@ uint32_t BinaryFilePacker::CopyBinaryFileImpl(const string &src, const string &d string path = entry->GetFilePath().GetPath(); auto copyFunc = [this](const string path, string subPath) { return this->CopySingleFile(path, subPath); }; - std::future res = threadPool_.Enqueue(copyFunc, path, subPath); + std::future res = ThreadPool::GetInstance().Enqueue(copyFunc, path, subPath); copyResults_.push_back(std::move(res)); } return RESTOOL_SUCCESS; diff --git a/src/cmd/package_parser.cpp b/src/cmd/package_parser.cpp index 28732f6..7b4532d 100644 --- a/src/cmd/package_parser.cpp +++ b/src/cmd/package_parser.cpp @@ -15,6 +15,7 @@ #include "cmd/package_parser.h" #include +#include #include "resconfig_parser.h" #include "resource_util.h" #include "select_compile_parse.h" @@ -46,6 +47,7 @@ const struct option PackageParser::CMD_OPTS[] = { { "target-config", required_argument, nullptr, Option::TARGET_CONFIG}, { "defined-sysids", required_argument, nullptr, Option::DEFINED_SYSIDS}, { "compressed-config", required_argument, nullptr, Option::COMPRESSED_CONFIG}, + { "thread", required_argument, nullptr, Option::THREAD}, { 0, 0, 0, 0}, }; @@ -410,6 +412,31 @@ uint32_t PackageParser::ParseTargetConfig(const string& argValue) return RESTOOL_SUCCESS; } +uint32_t PackageParser::ParseThread(const std::string &argValue) +{ + if (argValue.empty()) { + return RESTOOL_SUCCESS; + } + char *end; + errno = 0; + int count = static_cast(strtol(argValue.c_str(), &end, 10)); + if (end == argValue.c_str() || errno == ERANGE || *end != '\0' || count == INT_MIN || count == INT_MAX) { + cerr << "Error: Invalid thread count: " << argValue << endl; + return RESTOOL_ERROR; + } + if (count <= 0) { + cerr << "Error: Invalid thread count: " << count << endl; + return RESTOOL_ERROR; + } + threadCount_ = count; + return RESTOOL_SUCCESS; +} + +size_t PackageParser::GetThreadCount() const +{ + return threadCount_; +} + const TargetConfig &PackageParser::GetTargetConfigValues() const { return targetConfig_; @@ -483,6 +510,7 @@ void PackageParser::InitCommand() handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1)); handles_.emplace(Option::DEFINED_SYSIDS, bind(&PackageParser::AddSysIdDefined, this, _1)); handles_.emplace(Option::COMPRESSED_CONFIG, bind(&PackageParser::AddCompressionPath, this, _1)); + handles_.emplace(Option::THREAD, bind(&PackageParser::ParseThread, this, _1)); } uint32_t PackageParser::HandleProcess(int c, const string& argValue) diff --git a/src/generic_compiler.cpp b/src/generic_compiler.cpp index 9a40e4e..3ad8f66 100644 --- a/src/generic_compiler.cpp +++ b/src/generic_compiler.cpp @@ -37,12 +37,10 @@ GenericCompiler::~GenericCompiler() uint32_t GenericCompiler::CompileFiles(const std::vector &fileInfos) { cout << "Info: GenericCompiler::CompileFiles" << endl; - ThreadPool pool(THREAD_POOL_SIZE); - pool.Start(); std::vector> results; for (const auto &fileInfo : fileInfos) { auto taskFunc = [this](const FileInfo &fileInfo) { return this->CompileSingleFile(fileInfo); }; - results.push_back(pool.Enqueue(taskFunc, fileInfo)); + results.push_back(ThreadPool::GetInstance().Enqueue(taskFunc, fileInfo)); } for (auto &ret : results) { if (ret.get() != RESTOOL_SUCCESS) { diff --git a/src/resconfig_parser.cpp b/src/resconfig_parser.cpp index 0efafcd..60ae763 100644 --- a/src/resconfig_parser.cpp +++ b/src/resconfig_parser.cpp @@ -92,6 +92,8 @@ void ResConfigParser::InitFileListCommand(HandleBack callback) Option::DEFINED_SYSIDS, callback)); fileListHandles_.emplace("compression", bind(&ResConfigParser::GetString, this, _1, Option::COMPRESSED_CONFIG, callback)); + fileListHandles_.emplace("thread", bind(&ResConfigParser::GetNumber, this, _1, + Option::THREAD, callback)); } uint32_t ResConfigParser::GetString(const cJSON *node, int c, HandleBack callback) @@ -163,6 +165,19 @@ uint32_t ResConfigParser::GetBool(const cJSON *node, int c, HandleBack callback) } return RESTOOL_SUCCESS; } + +uint32_t ResConfigParser::GetNumber(const cJSON *node, int c, HandleBack callback) +{ + if (!node || !cJSON_IsNumber(node)) { + cerr << "Error: GetNumber node not number. Option = " << c << endl; + return RESTOOL_ERROR; + } + + if (callback(c, std::to_string(node->valuedouble)) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} } } } diff --git a/src/resource_pack.cpp b/src/resource_pack.cpp index 1d12a2d..18ca72a 100644 --- a/src/resource_pack.cpp +++ b/src/resource_pack.cpp @@ -86,6 +86,9 @@ uint32_t ResourcePack::InitResourcePack() if (InitModule() != RESTOOL_SUCCESS) { return RESTOOL_ERROR; } + if (ThreadPool::GetInstance().Start(packageParser_.GetThreadCount()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + }; return RESTOOL_SUCCESS; } diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 9cd88b2..c7e0de3 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -24,18 +24,31 @@ namespace Global { namespace Restool { using namespace std; -ThreadPool::ThreadPool(size_t threadCount) : threadCount_(threadCount) +ThreadPool::ThreadPool() {} -uint32_t ThreadPool::Start() +ThreadPool &ThreadPool::GetInstance() { - if (!workerThreads_.empty() || threadCount_ <= 0) { - cerr << "Error: ThreadPool start failed." << endl; - return RESTOOL_ERROR; + static ThreadPool pool; + return pool; +} + +uint32_t ThreadPool::Start(const size_t &threadCount) +{ + if (!workerThreads_.empty()) { + cout << "Warning: ThreadPool is already started." << endl; + return RESTOOL_SUCCESS; } + size_t hardwareCount = std::thread::hardware_concurrency(); + cout << "Info: hardware concurrency count is : " << hardwareCount << endl; + size_t count = threadCount <= 0 ? (hardwareCount <= 0 ? DEFAULT_POOL_SIZE : hardwareCount) : threadCount; + if (count == 1) { + count++; + } + cout << "Info: thread count is : " << count << endl; running_ = true; - workerThreads_.reserve(threadCount_); - for (size_t i = 0; i < threadCount_; ++i) { + workerThreads_.reserve(count); + for (size_t i = 0; i < count; ++i) { workerThreads_.emplace_back([this] { this->WorkInThread(); }); } cout << "Info: thread pool is started" << endl;