From 438413728aa2555a11d705499c8c1bf7cb2bb797 Mon Sep 17 00:00:00 2001 From: XniceCraft Date: Sat, 9 Dec 2023 08:19:32 +0700 Subject: [PATCH 1/4] Implement multithreading --- elf-cleaner.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/elf-cleaner.cpp b/elf-cleaner.cpp index 144be0f..314fa37 100644 --- a/elf-cleaner.cpp +++ b/elf-cleaner.cpp @@ -19,7 +19,10 @@ You should have received a copy of the GNU General Public License along with termux-elf-cleaner. If not, see . */ -#include +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -29,6 +32,12 @@ along with termux-elf-cleaner. If not, see #include #include +#include +#include +#include +#include +#include + #include "arghandling.h" // Include a local elf.h copy as not all platforms have it. @@ -55,6 +64,8 @@ int api_level = 21; bool dry_run = false; bool quiet = false; +std::mutex mutex; + static char const *const usage_message[] = { "\ \n\ @@ -64,6 +75,7 @@ dynamic section entries which the Android linker warns about.\n\ Options:\n\ \n\ --api-level NN choose target api level, i.e. 21, 24, ..\n\ +--jobs N run parallel on n thread(s).\n\ --dry-run print info but but do not remove entries\n\ --quiet do not print info about removed entries\n\ --help display this help and exit\n\ @@ -299,6 +311,22 @@ int parse_file(const char *file_name) return 0; } +void parse_file_handler(std::deque* files) { + while (!files->empty()) { + mutex.lock(); + char* file = static_cast(malloc(strlen(files->front()))); + if (file == NULL) { + perror("malloc(): Failed to allocate memory!"); + continue; + } + memcpy(file, files->front(), strlen(files->front())); + files->pop_front(); + mutex.unlock(); + parse_file(file); + free(file); + } +} + int main(int argc, char **argv) { int skip_args = 0; @@ -334,9 +362,20 @@ int main(int argc, char **argv) if (argmatch(argv, argc, "-quiet", "--quiet", 3, NULL, &skip_args)) quiet = true; - for (int i = skip_args+1; i < argc; i++) { - if (parse_file(argv[i]) != 0) - return 1; - } + int threads_count = std::thread::hardware_concurrency(); + int files_count = argc - (skip_args + 1); + argmatch(argv, argc, "-jobs", "--jobs", 1, &threads_count, &skip_args); + if (argc - (skip_args + 1) <= threads_count) threads_count = files_count; + if (threads_count < 1) threads_count = 1; + + std::deque files; + std::vector threads(threads_count); + + for (int i = skip_args + 1; i < argc; i++) + files.push_back(argv[i]); + for (int i = 0; i < threads_count; i++) + threads[i] = std::thread(parse_file_handler, &files); + for (std::thread& thread : threads) + if (thread.joinable()) thread.join(); return 0; } From 04755b31885d39acbd8815954f1f8d2446f1cda7 Mon Sep 17 00:00:00 2001 From: XniceCraft Date: Sun, 10 Dec 2023 01:10:27 +0700 Subject: [PATCH 2/4] Use index instead of copying the item Instead of copying the front item then temporary store it, we create a variable that store where the thread need to access (according to std::deque docs, accessing by index require constant time O(1))" --- elf-cleaner.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/elf-cleaner.cpp b/elf-cleaner.cpp index 314fa37..feef94b 100644 --- a/elf-cleaner.cpp +++ b/elf-cleaner.cpp @@ -311,19 +311,13 @@ int parse_file(const char *file_name) return 0; } -void parse_file_handler(std::deque* files) { - while (!files->empty()) { +void parse_file_handler(std::deque* files, unsigned int pos) { + while (files->size() > pos) { mutex.lock(); - char* file = static_cast(malloc(strlen(files->front()))); - if (file == NULL) { - perror("malloc(): Failed to allocate memory!"); - continue; - } - memcpy(file, files->front(), strlen(files->front())); - files->pop_front(); + const char *file = files->at(pos); + pos++; mutex.unlock(); parse_file(file); - free(file); } } @@ -370,11 +364,12 @@ int main(int argc, char **argv) std::deque files; std::vector threads(threads_count); + unsigned int pos = 0; for (int i = skip_args + 1; i < argc; i++) files.push_back(argv[i]); for (int i = 0; i < threads_count; i++) - threads[i] = std::thread(parse_file_handler, &files); + threads[i] = std::thread(parse_file_handler, &files, pos); for (std::thread& thread : threads) if (thread.joinable()) thread.join(); return 0; From 5e679bc8d46aac5c8e3ce647b5674f998a36225c Mon Sep 17 00:00:00 2001 From: XniceCraft Date: Sun, 10 Dec 2023 01:48:33 +0700 Subject: [PATCH 3/4] Pass pos variable by reference --- elf-cleaner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elf-cleaner.cpp b/elf-cleaner.cpp index feef94b..e4c6031 100644 --- a/elf-cleaner.cpp +++ b/elf-cleaner.cpp @@ -311,7 +311,7 @@ int parse_file(const char *file_name) return 0; } -void parse_file_handler(std::deque* files, unsigned int pos) { +void parse_file_handler(std::deque* files, unsigned int &pos) { while (files->size() > pos) { mutex.lock(); const char *file = files->at(pos); @@ -369,7 +369,7 @@ int main(int argc, char **argv) for (int i = skip_args + 1; i < argc; i++) files.push_back(argv[i]); for (int i = 0; i < threads_count; i++) - threads[i] = std::thread(parse_file_handler, &files, pos); + threads[i] = std::thread(parse_file_handler, &files, std::ref(pos)); for (std::thread& thread : threads) if (thread.joinable()) thread.join(); return 0; From 2d93754d61d3166124d77e2ae2d56ee796a1927c Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Fri, 15 Dec 2023 20:57:42 +0100 Subject: [PATCH 4/4] Makefile: compile with -pthread Needed on some systems to get pthread functions. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 2ee81bd..0dc576c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # . SUBDIRS = tests -AM_CXXFLAGS = -std=c++11 -Wall -Wextra -pedantic +AM_CXXFLAGS = -std=c++11 -Wall -Wextra -pedantic -pthread bin_PROGRAMS = termux-elf-cleaner