From 34e180823c748fccfc40daa9cc2665355a8010f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=98=8A=E8=8B=8F?= Date: Thu, 13 Nov 2025 14:41:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=BA=BF=E7=A8=8B=E6=B1=A0?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=AB=E6=8F=8F=E4=BB=AA=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 刘昊苏 --- BUILD.gn | 47 +++- bundle.json | 1 + install.py | 3 +- patches/add_thread_poll.patch | 269 +++++++++++++++++++++ patches/dll.c.patch | 17 -- patches/hilog_debug.patch | 27 +++ patches/modifying_driver_search_path.patch | 25 +- threadpool/include/threadpool_c.h | 40 +++ threadpool/include/threadpool_wrapper.h | 43 ++++ threadpool/src/threadpool_c.cpp | 84 +++++++ threadpool/src/threadpool_wrapper.cpp | 50 ++++ 11 files changed, 574 insertions(+), 32 deletions(-) create mode 100644 patches/add_thread_poll.patch delete mode 100644 patches/dll.c.patch create mode 100644 patches/hilog_debug.patch create mode 100644 threadpool/include/threadpool_c.h create mode 100644 threadpool/include/threadpool_wrapper.h create mode 100644 threadpool/src/threadpool_c.cpp create mode 100644 threadpool/src/threadpool_wrapper.cpp diff --git a/BUILD.gn b/BUILD.gn index 341d924b3..1a3cf3470 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -21,6 +21,8 @@ SANE_LIB_DIR = "/data/service/el1/public/print_service/sane/backend" SANE_V_MAJOR = 1 SANE_V_MINOR = 2 enable_hilog = true +enable_thread_pool = true +enable_scan_service = true source_dir = "//third_party/backends" target_dir = "${target_gen_dir}/sane" @@ -29,7 +31,8 @@ action("backends_action") { script = "//third_party/backends/install.py" inputs = [ "${source_dir}/patches/modifying_driver_search_path.patch", - "${source_dir}/patches/dll.c.patch", + "${source_dir}/patches/add_thread_poll.patch", + "${source_dir}/patches/hilog_debug.patch", ] outputs = [ "${target_dir}/include/config.h", @@ -69,6 +72,14 @@ config("backends_private_config") { cflags += [ "-DENABLE_HILOG" ] } + if (enable_thread_pool) { + cflags += [ "-DHAVE_THREAD_POLL"] + } + + if (enable_scan_service) { + cflags += [ "-DHAVE_SCAN_SERVICE"] + } + defines = [ "PATH_SANE_CONFIG_DIR=$SANE_CONFIG_DIR", "PATH_SANE_DATA_DIR=$SANE_DATA_DIR", @@ -185,6 +196,33 @@ ohos_source_set("sane_strstatus") { part_name = "backends" } + +ohos_source_set("threadpool_c") { + sources = [ + "threadpool/src/threadpool_c.cpp", + "threadpool/src/threadpool_wrapper.cpp" + ] + + include_dirs = [ + "threadpool/include", + ] + + external_deps = [ + "c_utils:utils", + ] + + if (enable_hilog) { + external_deps += [ "hilog:libhilog" ] + } + + public_configs = [ ":backends_public_config" ] + + configs = [ ":backends_private_config" ] + + subsystem_name = "thirdparty" + part_name = "backends" +} + ohos_shared_library("sane") { sources = [ "./backend/dll.c", @@ -207,6 +245,13 @@ ohos_shared_library("sane") { ":sanei_usb", ] + include_dirs = [] + + if (enable_thread_pool) { + deps += [ ":threadpool_c" ] + include_dirs += [ "threadpool/include" ] + } + if (enable_hilog) { external_deps = [ "hilog:libhilog" ] } diff --git a/bundle.json b/bundle.json index 0cdd88e62..10240182f 100644 --- a/bundle.json +++ b/bundle.json @@ -23,6 +23,7 @@ "deps": { "components": [ "hilog", + "c_utils", "libusb" ], "third_party": [ diff --git a/install.py b/install.py index 67d067bc6..2c1565522 100755 --- a/install.py +++ b/install.py @@ -24,7 +24,8 @@ import shutil def apply_patch(source_dir): patch_list = [ 'modifying_driver_search_path.patch', - 'dll.c.patch', + 'add_thread_poll.patch', + 'hilog_debug.patch', ] for patch in patch_list: diff --git a/patches/add_thread_poll.patch b/patches/add_thread_poll.patch new file mode 100644 index 000000000..6b8fc948e --- /dev/null +++ b/patches/add_thread_poll.patch @@ -0,0 +1,269 @@ +diff --git a/backend/dll.c b/backend/dll.c +index 7a505d13f..120dcf7e5 100644 +--- a/backend/dll.c ++++ b/backend/dll.c +@@ -292,6 +292,26 @@ static const char *op_name[] = { + }; + #endif /* __BEOS__ */ + ++#ifdef HAVE_THREAD_POLL ++ ++#include "threadpool_c.h" ++ ++typedef struct backend_task { ++ struct backend *be; ++ SANE_Bool local_only; ++ const SANE_Device **be_list; ++ SANE_Status status; ++ int num_devs; ++ SANE_Device **devices; ++ int device_count; ++} backend_task_t; ++ ++static threadpool_handle_t* pool = NULL; ++ ++static const int max_thread_number = 20; ++ ++#endif // HAVE_THREAD_POLL ++ + #if defined(HAVE_SCAN_SERVICE) + static int has_suffix(const char *filename, const char *suffix) + { +@@ -1052,6 +1072,13 @@ sane_exit (void) + + DBG (2, "sane_exit: exiting\n"); + ++#ifdef HAVE_THREAD_POLL ++if (pool) { ++ threadpool_destroy(pool); ++ pool = NULL; ++} ++#endif // HAVE_THREAD_POLL ++ + for (be = first_backend; be; be = next) + { + next = be->next; +@@ -1123,6 +1150,7 @@ sane_exit (void) + DBG (3, "sane_exit: finished\n"); + } + ++#ifndef HAVE_THREAD_POLL + /* Note that a call to get_devices() implies that we'll have to load + all backends. To avoid this, you can call sane_open() directly + (assuming you know the name of the backend/device). This is +@@ -1238,6 +1266,215 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) + return SANE_STATUS_GOOD; + } + ++#else ++static void process_backend_task(void *arg) { ++ backend_task_t *task = (backend_task_t *)arg; ++ if (!task || !task->be) { ++ DBG (1, "process_backend_task: parameter is null\n"); ++ return; ++ } ++ struct backend *be = task->be; ++ SANE_Status status; ++ char *full_name; ++ int i, num_devs; ++ size_t len; ++ ++ if (!be->inited) { ++ if (init(be) != SANE_STATUS_GOOD) { ++ task->status = SANE_STATUS_INVAL; ++ return; ++ } ++ } ++ if (be->name) { ++ DBG (1, "process_backend_task: driver [%s] sane_get_devices begin\n", be->name); ++ } ++ status = (*(op_get_devs_t)be->op[OP_GET_DEVS]) (&task->be_list, task->local_only); ++ if (be->name) { ++ DBG (1, "process_backend_task: driver [%s] sane_get_devices end\n", be->name); ++ } ++ task->status = status; ++ ++ if (status != SANE_STATUS_GOOD || !task->be_list) { ++ DBG (1, "process_backend_task: driver [%s] sane_get_devices fail, ret = %d\n", be->name, (int)status); ++ return; ++ } ++ ++ for (task->num_devs = 0; task->be_list[task->num_devs]; ++task->num_devs); ++ ++ task->devices = malloc(task->num_devs * sizeof(SANE_Device*)); ++ if (!task->devices) { ++ task->status = SANE_STATUS_NO_MEM; ++ return; ++ } ++ task->device_count = 0; ++ ++ for (i = 0; i < task->num_devs; ++i) { ++ SANE_Device *dev; ++ char *mem; ++ struct alias *alias; ++ ++ for (alias = first_alias; alias != NULL; alias = alias->next) { ++ len = strlen(be->name); ++ if (strlen(alias->oldname) <= len) ++ continue; ++ if (strncmp(alias->oldname, be->name, len) == 0 ++ && alias->oldname[len] == ':' ++ && strcmp(&alias->oldname[len + 1], task->be_list[i]->name) == 0) ++ break; ++ } ++ ++ if (alias) { ++ if (!alias->newname) { ++ continue; ++ } ++ ++ len = strlen(alias->newname); ++ mem = malloc(sizeof(*dev) + len + 1); ++ if (!mem) { ++ task->status = SANE_STATUS_NO_MEM; ++ for (int j = 0; j < task->device_count; j++) { ++ free(task->devices[j]); ++ } ++ free(task->devices); ++ task->devices = NULL; ++ return; ++ } ++ ++ full_name = mem + sizeof(*dev); ++ strcpy(full_name, alias->newname); ++ } else { ++ len = strlen(be->name) + 1 + strlen(task->be_list[i]->name); ++ mem = malloc(sizeof(*dev) + len + 1); ++ if (!mem) { ++ task->status = SANE_STATUS_NO_MEM; ++ for (int j = 0; j < task->device_count; j++) { ++ free(task->devices[j]); ++ } ++ free(task->devices); ++ task->devices = NULL; ++ return; ++ } ++ ++ full_name = mem + sizeof(*dev); ++ strcpy(full_name, be->name); ++ strcat(full_name, ":"); ++ strcat(full_name, task->be_list[i]->name); ++ } ++ ++ dev = (SANE_Device *) mem; ++ dev->name = full_name; ++ dev->vendor = task->be_list[i]->vendor; ++ dev->model = task->be_list[i]->model; ++ dev->type = task->be_list[i]->type; ++ ++ task->devices[task->device_count++] = dev; ++ } ++} ++ ++SANE_Status ++sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) ++{ ++ const SANE_Device **be_list; ++ struct backend *be; ++ SANE_Status status; ++ char *full_name; ++ int i, num_devs; ++ size_t len; ++ #define ASSERT_SPACE(n) do \ ++ { \ ++ if (devlist_len + (n) > devlist_size) \ ++ { \ ++ devlist_size += (n) + 15; \ ++ if (devlist) \ ++ devlist = realloc (devlist, devlist_size * sizeof (devlist[0])); \ ++ else \ ++ devlist = malloc (devlist_size * sizeof (devlist[0])); \ ++ if (!devlist) \ ++ return SANE_STATUS_NO_MEM; \ ++ } \ ++ } while (0) ++ ++ DBG (3, "sane_get_devices\n"); ++ ++ if (devlist) ++ for (i = 0; i < devlist_len; ++i) ++ free ((void *) devlist[i]); ++ devlist_len = 0; ++ ++ int backend_count = 0; ++ for (be = first_backend; be; be = be->next) { ++ backend_count++; ++ } ++ ++ if (backend_count == 0) { ++ ASSERT_SPACE (1); ++ devlist[devlist_len++] = 0; ++ *device_list = (const SANE_Device **) devlist; ++ return SANE_STATUS_GOOD; ++ } ++ ++ backend_task_t *tasks = malloc(backend_count * sizeof(backend_task_t)); ++ if (!tasks) { ++ return SANE_STATUS_NO_MEM; ++ } ++ if (pool == NULL) { ++ int discoverThreadNum = backend_count < max_thread_number ? backend_count : max_thread_number; ++ pool = threadpool_create(discoverThreadNum); ++ } ++ int task_index = 0; ++ for (be = first_backend; be; be = be->next, task_index++) { ++ tasks[task_index].be = be; ++ tasks[task_index].local_only = local_only; ++ tasks[task_index].be_list = NULL; ++ tasks[task_index].status = SANE_STATUS_GOOD; ++ tasks[task_index].num_devs = 0; ++ tasks[task_index].devices = NULL; ++ tasks[task_index].device_count = 0; ++ ++ if (!threadpool_add_task(pool, process_backend_task, &tasks[task_index])) { ++ DBG(1, "Failed to add task for backend %s\n", be->name); ++ tasks[task_index].status = SANE_STATUS_IO_ERROR; ++ } ++ } ++ ++ threadpool_wait(pool); ++ ++ int total_devices = 0; ++ for (task_index = 0; task_index < backend_count; task_index++) { ++ if (tasks[task_index].status == SANE_STATUS_GOOD && tasks[task_index].devices) { ++ total_devices += tasks[task_index].device_count; ++ } ++ } ++ ++ ASSERT_SPACE(total_devices); ++ ++ for (task_index = 0; task_index < backend_count; task_index++) { ++ backend_task_t *task = &tasks[task_index]; ++ ++ if (task->status != SANE_STATUS_GOOD || !task->devices) { ++ continue; ++ } ++ ++ for (i = 0; i < task->device_count; i++) { ++ devlist[devlist_len++] = task->devices[i]; ++ } ++ ++ free(task->devices); ++ } ++ ++ free(tasks); ++ threadpool_destroy(pool); ++ pool = NULL; ++ ++ ASSERT_SPACE (1); ++ devlist[devlist_len++] = 0; ++ ++ *device_list = (const SANE_Device **) devlist; ++ DBG (3, "sane_get_devices: found %d devices\n", devlist_len - 1); ++ return SANE_STATUS_GOOD; ++} ++#endif // HAVE_THREAD_POLL ++ + SANE_Status + sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) + { diff --git a/patches/dll.c.patch b/patches/dll.c.patch deleted file mode 100644 index 868c98b54..000000000 --- a/patches/dll.c.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/backend/dll.c b/backend/dll.c -index 9b13d3a59..7a505d13f 100644 ---- a/backend/dll.c -+++ b/backend/dll.c -@@ -1353,6 +1353,12 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) - } - free(be_name); - -+ if (!be) -+ { -+ DBG (3, "sane_open: be is nullptr\n"); -+ return SANE_STATUS_NO_MEM; -+ } -+ - if (!be->inited) - { - status = init (be); diff --git a/patches/hilog_debug.patch b/patches/hilog_debug.patch new file mode 100644 index 000000000..5b44d6113 --- /dev/null +++ b/patches/hilog_debug.patch @@ -0,0 +1,27 @@ +diff --git a/include/sane/sanei_debug.h b/include/sane/sanei_debug.h +index 465d3e25e..b18da651c 100644 +--- a/include/sane/sanei_debug.h ++++ b/include/sane/sanei_debug.h +@@ -8,7 +8,9 @@ + #define _SANEI_DEBUG_H + + #include +- ++#ifdef ENABLE_HILOG ++#include "hilog/log.h" ++#endif // ENABLE_HILOG + #ifdef __cplusplus + extern "C" { + #endif +@@ -79,7 +81,11 @@ extern void sanei_debug_ndebug (int level, const char *msg, ...); + + # define DBG_LEVEL (0) + # define DBG_INIT() ++#ifndef ENABLE_HILOG + # define DBG sanei_debug_ndebug ++#else ++# define DBG(level, ...) ((void)HiLogPrint(LOG_APP, LOG_INFO, 0, "sanekit", __VA_ARGS__)) ++#endif // ENABLE_HILOG + # define IF_DBG(x) + + #else /* !NDEBUG */ diff --git a/patches/modifying_driver_search_path.patch b/patches/modifying_driver_search_path.patch index 32497a955..6788ff8ac 100644 --- a/patches/modifying_driver_search_path.patch +++ b/patches/modifying_driver_search_path.patch @@ -1,5 +1,5 @@ diff --git a/backend/dll.c b/backend/dll.c -index bf34c4f6d..9b13d3a59 100644 +index bf34c4f6d..7a505d13f 100644 --- a/backend/dll.c +++ b/backend/dll.c @@ -292,6 +292,46 @@ static const char *op_name[] = { @@ -102,17 +102,16 @@ index bf34c4f6d..9b13d3a59 100644 fp = sanei_config_open (DLL_ALIASES_FILE); if (!fp) return SANE_STATUS_GOOD; /* don't insist on aliases file */ -diff --git a/include/sane/config.h b/include/sane/config.h -index 20dfa104b..206a4147e 100644 ---- a/include/sane/config.h -+++ b/include/sane/config.h -@@ -209,6 +209,9 @@ - /* Define to 1 if you have libusb-1.0 */ - #define HAVE_LIBUSB 1 +@@ -1284,6 +1353,12 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) + } + free(be_name); -+/* Define to 1 if you have scan_service */ -+#define HAVE_SCAN_SERVICE 1 ++ if (!be) ++ { ++ DBG (3, "sane_open: be is nullptr\n"); ++ return SANE_STATUS_NO_MEM; ++ } + - /* Define to 1 if you have libusb-0.1 */ - /* #undef HAVE_LIBUSB_LEGACY */ - + if (!be->inited) + { + status = init (be); diff --git a/threadpool/include/threadpool_c.h b/threadpool/include/threadpool_c.h new file mode 100644 index 000000000..550277df2 --- /dev/null +++ b/threadpool/include/threadpool_c.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* +* 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 2 +* of the License, or (at your option) 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 . +*/ +#ifndef THREADPOOL_C_H +#define THREADPOOL_C_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*threadpool_task_func_t)(void* arg); + +typedef struct threadpool_handle_t threadpool_handle_t; + +threadpool_handle_t* threadpool_create(int thread_num); + +bool threadpool_add_task(threadpool_handle_t* pool, threadpool_task_func_t func, void* arg); + +void threadpool_destroy(threadpool_handle_t* pool); + +void threadpool_wait(threadpool_handle_t* pool); + +#ifdef __cplusplus +} +#endif + +#endif // THREADPOOL_C_H \ No newline at end of file diff --git a/threadpool/include/threadpool_wrapper.h b/threadpool/include/threadpool_wrapper.h new file mode 100644 index 000000000..92bc6211d --- /dev/null +++ b/threadpool/include/threadpool_wrapper.h @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* +* 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 2 +* of the License, or (at your option) 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 . +*/ +#ifndef THREADPOOL_WRAPPER +#define THREADPOOL_WRAPPER + +#include "threadpool_c.h" +#include "thread_pool.h" +#include + +class ThreadPoolWrapper { +public: + ThreadPoolWrapper() = default; + + ~ThreadPoolWrapper() = default; + + bool Start(int thread_num); + + void Stop(); + + void AddTask(threadpool_task_func_t func, void* arg); + + void Wait(); + +private: + OHOS::ThreadPool pool_; +}; + +#endif // THREADPOOL_WRAPPER + diff --git a/threadpool/src/threadpool_c.cpp b/threadpool/src/threadpool_c.cpp new file mode 100644 index 000000000..daf9d0f9b --- /dev/null +++ b/threadpool/src/threadpool_c.cpp @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* +* 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 2 +* of the License, or (at your option) 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 . +*/ +#include "threadpool_c.h" +#include "threadpool_wrapper.h" +#include "sanei_debug.h" + +#define LEVEL 1 + +struct threadpool_handle_t { + ThreadPoolWrapper* wrapper; +}; + +threadpool_handle_t* threadpool_create(int32_t thread_num) +{ + constexpr int32_t maxThreadNum = 20; + if (thread_num <= 0 || thread_num > maxThreadNum) { + DBG(LEVEL, "threadpool_create: fail\n"); + return nullptr; + } + + threadpool_handle_t* handle = new(std::nothrow) threadpool_handle_t(); + if (!handle) { + DBG(LEVEL, "threadpool_create: handle is nullptr\n"); + return nullptr; + } + + handle->wrapper = new(std::nothrow) ThreadPoolWrapper(); + if (!handle->wrapper) { + delete handle; + DBG(LEVEL, "threadpool_create: wrapper is nullptr\n"); + return nullptr; + } + + if (!handle->wrapper->Start(thread_num)) { + delete handle->wrapper; + delete handle; + DBG(LEVEL, "threadpool_create: Start fail\n"); + return nullptr; + } + + return handle; +} + +bool threadpool_add_task(threadpool_handle_t* pool, threadpool_task_func_t func, void* arg) +{ + if (!pool || !pool->wrapper || !func) { + DBG(LEVEL, "threadpool_add_task: fail\n"); + return false; + } + + pool->wrapper->AddTask(func, arg); + return true; +} + +void threadpool_destroy(threadpool_handle_t* pool) +{ + if (pool) { + if (pool->wrapper) { + delete pool->wrapper; + } + delete pool; + } +} + +void threadpool_wait(threadpool_handle_t* pool) +{ + if (pool && pool->wrapper) { + pool->wrapper->Wait(); + } +} diff --git a/threadpool/src/threadpool_wrapper.cpp b/threadpool/src/threadpool_wrapper.cpp new file mode 100644 index 000000000..b1d86be81 --- /dev/null +++ b/threadpool/src/threadpool_wrapper.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2025 Huawei Device Co., Ltd. +* +* 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 2 +* of the License, or (at your option) 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 . +*/ +#include +#include +#include "errors.h" +#include "threadpool_wrapper.h" + +bool ThreadPoolWrapper::Start(int32_t thread_num) +{ + return pool_.Start(thread_num) == OHOS::ERR_OK; +} + +void ThreadPoolWrapper::Stop() +{ + pool_.Stop(); +} + +void ThreadPoolWrapper::AddTask(threadpool_task_func_t func, void* arg) +{ + if (func) { + pool_.AddTask([func, arg]() { + func(arg); + }); + } +} + +void ThreadPoolWrapper::Wait() +{ + constexpr int32_t WAIT_TIME = 1; + int32_t curTaskNum = 0; + do { + curTaskNum = static_cast(pool_.GetCurTaskNum()); + std::this_thread::sleep_for(std::chrono::seconds(WAIT_TIME)); + } while (curTaskNum != 0); + pool_.Stop(); +}