1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifndef MINDSPORE_LITE_SRC_EXTENDRT_CXX_API_DLUTILS_H_
17 #define MINDSPORE_LITE_SRC_EXTENDRT_CXX_API_DLUTILS_H_
18 #include <string>
19 #include <vector>
20 #include "include/api/status.h"
21 #include "src/common/file_utils.h"
22 #if !defined(_WIN32) && !defined(_WIN64)
23 #include <dlfcn.h>
24 #include <string.h>
25 #include <dirent.h>
26 #include <memory>
27 #include <fstream>
28
29 namespace mindspore {
30 inline std::string FindFileWithRecursion(const std::string &parent_dir, const std::string &target_so, int depth = 0) {
31 constexpr int MAX_RECURSION_DEPTH = 5;
32 if (depth == MAX_RECURSION_DEPTH) {
33 MS_LOG(DEBUG) << "Recursion depth exceeds MAX_RECURSION_DEPTH(5).";
34 return "";
35 }
36 DIR *dir = opendir(parent_dir.c_str());
37 if (dir == nullptr) {
38 MS_LOG(ERROR) << "Can't open dir " << parent_dir;
39 return "";
40 }
41 dirent *ent = readdir(dir);
42 std::vector<std::string> child_dirs;
43 while (ent != nullptr) {
44 if (ent->d_type == DT_DIR && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) {
45 std::string dir_path = parent_dir + std::string(ent->d_name);
46 child_dirs.push_back(lite::RealPath(dir_path.c_str()) + "/");
47 ent = readdir(dir);
48 continue;
49 }
50 if (std::string(ent->d_name).find(target_so) != std::string::npos) {
51 std::string found_path = parent_dir + std::string(ent->d_name);
52 (void)closedir(dir);
53 return found_path;
54 }
55 ent = readdir(dir);
56 }
57 for (auto const &child_dir : child_dirs) {
58 if (!child_dir.empty()) {
59 std::string found_path = FindFileWithRecursion(child_dir, target_so, depth + 1);
60 if (!found_path.empty()) {
61 (void)closedir(dir);
62 return found_path;
63 }
64 }
65 }
66 (void)closedir(dir);
67 return "";
68 }
69
FindSoPath(const std::string & parent_dir,const std::string & target_so,std::string * target_so_path)70 inline Status FindSoPath(const std::string &parent_dir, const std::string &target_so, std::string *target_so_path) {
71 if (target_so_path == nullptr) {
72 return Status(kMEFailed, "Input target_so_path is nullptr.");
73 }
74 std::string found_target_so = FindFileWithRecursion(parent_dir, target_so);
75 if (found_target_so.empty()) {
76 return Status(kMEFailed, "Could not find target so " + target_so + " in " + parent_dir);
77 }
78 auto realpath = lite::RealPath(found_target_so.c_str());
79 if (realpath.empty()) {
80 return Status(kMEFailed, "Get target so " + target_so + " real path failed, path: " + found_target_so);
81 }
82 *target_so_path = realpath;
83 return kSuccess;
84 }
85
DLSoPath(const std::vector<std::string> & so_names,const std::string & target_so,std::string * target_so_path)86 inline Status DLSoPath(const std::vector<std::string> &so_names, const std::string &target_so,
87 std::string *target_so_path) {
88 if (target_so_path == nullptr) {
89 return Status(kMEFailed, "Input so_path can not be nullptr.");
90 }
91 Dl_info dl_info;
92 dladdr(reinterpret_cast<void *>(DLSoPath), &dl_info);
93 std::string cur_so_path = dl_info.dli_fname;
94 std::string::size_type pos = std::string::npos;
95 for (auto &item : so_names) {
96 pos = cur_so_path.find(item);
97 if (pos != std::string::npos) {
98 break;
99 }
100 }
101 if (pos == std::string::npos) {
102 return Status(kMEFailed, "Could not find target so " + target_so + " in check path " + cur_so_path);
103 }
104 std::string parent_dir = cur_so_path.substr(0, pos);
105 return FindSoPath(parent_dir, target_so, target_so_path);
106 }
107
108 inline Status DLSoOpen(const std::string &dl_path, const std::string &func_name, void **handle, void **function,
109 bool runtime_convert = false) {
110 // do dlopen and export functions from c_dataengine
111 if (handle == nullptr) {
112 MS_LOG(WARNING) << "Input parameter handle cannot be nullptr";
113 return Status(kMEFailed, "Input parameter handle cannot be nullptr");
114 }
115 int mode = runtime_convert ? RTLD_GLOBAL : RTLD_LOCAL;
116 *handle = dlopen(dl_path.c_str(), RTLD_LAZY | mode);
117
118 auto get_dl_error = []() -> std::string {
119 auto error = dlerror();
120 return error == nullptr ? "" : error;
121 };
122 if (*handle == nullptr) {
123 auto error = get_dl_error();
124 MS_LOG(WARNING) << "dlopen " << dl_path << " failed, error: " << error;
125 return Status(kMEFailed, "dlopen " + dl_path + " failed, error: " + error);
126 }
127 if (!func_name.empty()) {
128 if (function == nullptr) {
129 MS_LOG(WARNING) << "Input parameter function cannot be nullptr";
130 return Status(kMEFailed, "Input parameter function cannot be nullptr");
131 }
132 *function = dlsym(*handle, func_name.c_str());
133 if (*function == nullptr) {
134 auto error = get_dl_error();
135 MS_LOG(WARNING) << "Could not find " + func_name + " in " + dl_path + ", error: " << error;
136 return Status(kMEFailed, "Could not find " + func_name + " in " + dl_path + ", error: " + error);
137 }
138 }
139 return kSuccess;
140 }
141
DLSoSym(const std::string & dl_path,void * handle,const std::string & func_name,void ** function)142 inline Status DLSoSym(const std::string &dl_path, void *handle, const std::string &func_name, void **function) {
143 if (handle == nullptr) {
144 MS_LOG(WARNING) << "Input parameter handle cannot be nullptr";
145 return Status(kMEFailed, "Input parameter handle cannot be nullptr");
146 }
147 if (func_name.empty()) {
148 MS_LOG(WARNING) << "Input parameter func_name cannot be empty";
149 return Status(kMEFailed, "Input parameter func_name cannot be empty");
150 }
151 if (function == nullptr) {
152 MS_LOG(WARNING) << "Input parameter function cannot be nullptr";
153 return Status(kMEFailed, "Input parameter function cannot be nullptr");
154 }
155 auto get_dl_error = []() -> std::string {
156 auto error = dlerror();
157 return error == nullptr ? "" : error;
158 };
159 *function = dlsym(handle, func_name.c_str());
160 if (*function == nullptr) {
161 auto error = get_dl_error();
162 MS_LOG(WARNING) << "Could not find " + func_name + " in " + dl_path + ", error: " << error;
163 return Status(kMEFailed, "Could not find " + func_name + " in " + dl_path + ", error: " + error);
164 }
165 return kSuccess;
166 }
167
DLSoClose(void * handle)168 inline void DLSoClose(void *handle) {
169 if (handle != nullptr) {
170 (void)dlclose(handle);
171 }
172 }
173
174 #define CHECK_FAIL_AND_RELEASE(_s, _handle, _e) \
175 do { \
176 Status __rc = (_s); \
177 if (__rc.IsError()) { \
178 MS_LOG(ERROR) << (_e); \
179 DLSoClose((_handle)); \
180 return __rc; \
181 } \
182 } while (false)
183 } // namespace mindspore
184 #else
FindSoPath(const std::string & benchmark_so_path,const std::string & target_so,std::string * target_so_path)185 inline mindspore::Status FindSoPath(const std::string &benchmark_so_path, const std::string &target_so,
186 std::string *target_so_path) {
187 MS_LOG(ERROR) << "Not support FindSoPath";
188 return mindspore::kMEFailed;
189 }
190
DLSoPath(const std::string & benchmark_so,const std::string & target_so,std::string * target_so_path)191 inline mindspore::Status DLSoPath(const std::string &benchmark_so, const std::string &target_so,
192 std::string *target_so_path) {
193 MS_LOG(ERROR) << "Not support dlopen so";
194 return mindspore::kMEFailed;
195 }
196
197 inline mindspore::Status DLSoOpen(const std::string &dl_path, const std::string &func_name, void **handle,
198 void **function, bool runtime_convert = false) {
199 MS_LOG(ERROR) << "Not support dlopen so";
200 return mindspore::kMEFailed;
201 }
202 #endif
203 #endif // MINDSPORE_LITE_SRC_EXTENDRT_CXX_API_DLUTILS_H_
204