提交 b5856528 编写于 作者: H hongbinj

Fix dynamic loading functions of libnetsys_client.z.so by saving them globally

Before this fix, every call to libnetsys_client.z.so's functions involves
loading the lib, searching symbols and unloading the lib. Assuming debugging a
process with lldb, it will hurt the debugging performance because lldb stops at
dlopen and dlcose (lldb inserts internal breakpoints to know which shared
library is loaded or unloaded). It is fixed by storing the handle to the lib and
function pointers globally.

Issue: I6XDBW
Test: passed most test cases of libc-test with 4 anticipated cases failed
Signed-off-by: Nhongbinj <jinhongbin2@huawei.com>
上级 d89c65c8
/**
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* 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
......@@ -16,6 +16,9 @@
#include <netdb.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include "functionalext.h"
......@@ -276,7 +279,7 @@ void getaddrinfo_1500(void)
EXPECT_EQ("getaddrinfo_1500", ret, SOCKTYPE_NOTSUPPORTED);
}
int main(int argc, char *argv[])
static void *test_all_cases(void *arg)
{
getaddrinfo_0100();
getaddrinfo_0200();
......@@ -293,6 +296,40 @@ int main(int argc, char *argv[])
getaddrinfo_1300();
getaddrinfo_1400();
getaddrinfo_1500();
return arg;
}
static void do_test_concurrently(void *(*test) (void *arg), size_t num_threads)
{
pthread_t *threads = (pthread_t *) malloc(sizeof(pthread_t) * num_threads);
if (threads == NULL) {
t_error("Failed to allocate memory: %s\n", strerror(errno));
return;
}
size_t last = 0;
while (last < num_threads) {
if (pthread_create(&(threads[last]), NULL, test, NULL)) {
t_error("Failed to create thread: %s\n", strerror(errno));
break;
}
last++;
}
for (size_t i = 0; i < last; i++) {
if (pthread_join(threads[i], NULL)) {
t_error("Failed to join thread: %s\n", strerror(errno));
}
}
free(threads);
return;
}
int main(int argc, char *argv[])
{
size_t num_threads = 16;
do_test_concurrently(test_all_cases, num_threads);
return t_status;
}
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* 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.
*/
#include "lookup.h"
#include "stdio_impl.h"
#include <ctype.h>
......@@ -5,8 +20,89 @@
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#define DNS_RESOLV_CONF_PATH "/etc/resolv.conf"
#if OHOS_DNS_PROXY_BY_NETSYS
#include "atomic.h"
#include <dlfcn.h>
static void *open_dns_lib(void)
{
static void *dns_lib_handle = NULL;
if (dns_lib_handle != NULL) {
a_barrier();
return dns_lib_handle;
}
void *lib = dlopen(DNS_SO_PATH, RTLD_LAZY);
if (lib == NULL) {
DNS_CONFIG_PRINT("%s: dlopen %s failed: %s",
__func__, DNS_SO_PATH, dlerror());
return NULL;
}
void *old_lib = a_cas_p(&dns_lib_handle, NULL, lib);
if (old_lib == NULL) {
DNS_CONFIG_PRINT("%s: %s loaded", __func__, DNS_SO_PATH);
return lib;
} else {
/* Another thread has already loaded the library,
* dlclose is invoked to make refcount correct */
DNS_CONFIG_PRINT("%s: %s has been loaded by another thread",
__func__, DNS_SO_PATH);
if (dlclose(lib)) {
DNS_CONFIG_PRINT("%s: dlclose %s failed: %s",
__func__, DNS_SO_PATH, dlerror());
}
return old_lib;
}
}
static void *load_from_dns_lib(const char *symbol)
{
void *lib_handle = open_dns_lib();
if (lib_handle == NULL) {
return NULL;
}
void *sym_addr = dlsym(lib_handle, symbol);
if (sym_addr == NULL) {
DNS_CONFIG_PRINT("%s: loading symbol %s with dlsym failed: %s",
__func__, symbol, dlerror());
}
return sym_addr;
}
void resolve_dns_sym(void **holder, const char *symbol)
{
if (*holder != NULL) {
a_barrier();
return;
}
void *ptr = load_from_dns_lib(symbol);
if (ptr == NULL) {
return;
}
void *old_ptr = a_cas_p(holder, NULL, ptr);
if (old_ptr != NULL) {
DNS_CONFIG_PRINT("%s: %s has been found by another thread",
__func__, symbol);
} else {
DNS_CONFIG_PRINT("%s: %s found", __func__, symbol);
}
}
static GetConfig load_config_getter(void)
{
static GetConfig config_getter = NULL;
resolve_dns_sym((void **) &config_getter, OHOS_GET_CONFIG_FUNC_NAME);
return config_getter;
}
#endif
int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
......@@ -22,22 +118,15 @@ int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
if (search) *search = 0;
#if OHOS_DNS_PROXY_BY_NETSYS
void *handle = dlopen(DNS_SO_PATH, RTLD_LAZY);
if (handle == NULL) {
DNS_CONFIG_PRINT("__get_resolv_conf dlopen err %s\n", dlerror());
goto etc_resolv_conf;
}
GetConfig func = dlsym(handle, OHOS_GET_CONFIG_FUNC_NAME);
if (func == NULL) {
DNS_CONFIG_PRINT("__get_resolv_conf dlsym err %s\n", dlerror());
dlclose(handle);
GetConfig func = load_config_getter();
if (!func) {
DNS_CONFIG_PRINT("%s: loading %s failed, use %s as a fallback",
__func__, OHOS_GET_CONFIG_FUNC_NAME, DNS_RESOLV_CONF_PATH);
goto etc_resolv_conf;
}
struct resolv_config config = {0};
int ret = func(0, &config);
dlclose(handle);
if (ret < 0) {
DNS_CONFIG_PRINT("__get_resolv_conf OHOS_GET_CONFIG_FUNC_NAME err %d\n", ret);
return EAI_NONAME;
......@@ -74,7 +163,7 @@ netsys_conf:
etc_resolv_conf:
#endif
f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
f = __fopen_rb_ca(DNS_RESOLV_CONF_PATH, &_f, _buf, sizeof _buf);
if (!f) switch (errno) {
case ENOENT:
case ENOTDIR:
......
......@@ -113,6 +113,10 @@ typedef int32_t (*GetCache)(uint16_t netId, struct param_wrapper param,
typedef int32_t (*SetCache)(uint16_t netId, struct param_wrapper param, struct addrinfo *res);
/* If the memory holder points to stores NULL value, try to load symbol from the
* dns lib into holder; otherwise, it does nothing. */
hidden void resolve_dns_sym(void **holder, const char *symbol);
void
dns_set_addr_info_to_netsys_cache(const char *__restrict host, const char *__restrict serv,
const struct addrinfo *__restrict
......
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* 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
......@@ -23,25 +23,33 @@
#if OHOS_DNS_PROXY_BY_NETSYS
#include "atomic.h"
static GetCache load_cache_getter(void)
{
static GetCache cache_getter = NULL;
resolve_dns_sym((void **) &cache_getter, OHOS_GET_CACHE_FUNC_NAME);
return cache_getter;
}
static SetCache load_cache_setter(void)
{
static SetCache cache_setter = NULL;
resolve_dns_sym((void **) &cache_setter, OHOS_SET_CACHE_FUNC_NAME);
return cache_setter;
}
void
dns_set_addr_info_to_netsys_cache(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict
hint, struct addrinfo *res) {
void *handle = dlopen(DNS_SO_PATH, RTLD_LAZY);
if (handle == NULL) {
DNS_CONFIG_PRINT("dns_set_addr_info_to_netsys_cache dlopen err %s\n", dlerror());
return;
}
SetCache func = dlsym(handle, OHOS_SET_CACHE_FUNC_NAME);
if (func == NULL) {
DNS_CONFIG_PRINT("dns_set_addr_info_to_netsys_cache dlsym err %s\n", dlerror());
dlclose(handle);
SetCache func = load_cache_setter();
if (!func) {
DNS_CONFIG_PRINT("%s: loading %s failed", __func__, OHOS_SET_CACHE_FUNC_NAME);
return;
}
struct param_wrapper param = {(char *) host, (char *) serv, (struct addrinfo *) hint};
int ret = func(0, param, res);
dlclose(handle);
if (ret < 0) {
DNS_CONFIG_PRINT("dns_set_addr_info_to_netsys_cache OHOS_SET_CACHE_FUNC_NAME err %d\n", ret);
return;
......@@ -52,16 +60,9 @@ hint, struct addrinfo *res) {
int dns_get_addr_info_from_netsys_cache(const char *restrict host, const char *restrict serv,
const struct addrinfo *restrict hint, struct addrinfo **restrict res) {
void *handle = dlopen(DNS_SO_PATH, RTLD_LAZY);
if (handle == NULL) {
DNS_CONFIG_PRINT("dns_get_addr_info_from_netsys_cache dlopen err %s\n", dlerror());
return -1;
}
GetCache func = dlsym(handle, OHOS_GET_CACHE_FUNC_NAME);
if (func == NULL) {
DNS_CONFIG_PRINT("dns_get_addr_info_from_netsys_cache dlsym err %s\n", dlerror());
dlclose(handle);
GetCache func = load_cache_getter();
if (!func) {
DNS_CONFIG_PRINT("%s: loading %s failed", __func__, OHOS_GET_CACHE_FUNC_NAME);
return -1;
}
......@@ -69,7 +70,6 @@ int dns_get_addr_info_from_netsys_cache(const char *restrict host, const char *r
uint32_t num = 0;
struct param_wrapper param = {(char *) host, (char *) serv, (struct addrinfo *) hint};
int ret = func(0, param, addr_info, &num);
dlclose(handle);
if (ret < 0) {
DNS_CONFIG_PRINT("dns_get_addr_info_from_netsys_cache OHOS_GET_CACHE_FUNC_NAME err %d\n", ret);
return -1;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册