Use preload file in hydra loader (#241) accepted/tizen/5.5/unified/20200608.142148 accepted/tizen/unified/20200608.144752 submit/tizen/20200607.233857 submit/tizen_5.5/20200607.233848
author조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Sun, 7 Jun 2020 23:30:35 +0000 (08:30 +0900)
committer이형주/Common Platform Lab(SR)/Staff Engineer/삼성전자 <leee.lee@samsung.com>
Sun, 7 Jun 2020 23:30:35 +0000 (08:30 +0900)
The preloading list of candidate processes is obtained through the preload file.
The hydra loader has been modified to obtain the preloading assembly list through the same method.

libdotnet-launcher-util.so should not be linked to hydra loader because some
linked libraries create socket in the static initializer and that makes
problem after forking.
So, some functions (absolutePath, isFileExist, replaceAll) is copied
from utils.cc to hydra_main.cc

Know issue :
When System.Private.CoreLib.dll is preloaded in the current hydra loader,
System.Private.CoreLib.dll is loaded again in the candidate process, and that is not shared.
This issus should be checked later.

NativeLauncher/CMakeLists.txt
NativeLauncher/hydra/hydra_main.cc
NativeLauncher/inc/launcher_env.h
packaging/dotnet-launcher.spec

index d565548..773686c 100644 (file)
@@ -169,6 +169,7 @@ SET(${DOTNET_HYDRA_LOADER}_SOURCE_FILES
 ADD_EXECUTABLE(${DOTNET_HYDRA_LOADER} ${${DOTNET_HYDRA_LOADER}_SOURCE_FILES})
 TARGET_LINK_LIBRARIES(${DOTNET_HYDRA_LOADER} ${${target_hydra}_LDFLAGS} "-pie -ldl")
 SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LOADER} PROPERTIES COMPILE_FLAGS  ${EXTRA_CFLAGS_HYDRA})
+
 SET_TARGET_PROPERTIES(${DOTNET_HYDRA_LOADER}
     PROPERTIES SKIP_BUILD_RPATH TRUE
 ) # remove rpath option that is automatically generated by cmake.
@@ -254,4 +255,4 @@ INSTALL(FILES inc/ni_common.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES inc/tac_common.h DESTINATION ${INCLUDEDIR})
 INSTALL(FILES ../dotnet-launcher.pc DESTINATION ${LIBDIR}/pkgconfig)
 INSTALL(FILES dotnet-launcher.info DESTINATION /usr/share/parser-plugins)
-INSTALL(FILES dotnet.preload.list DESTINATION ${LOADERDIR})
+
index f446e36..b0e7671 100644 (file)
 #include <fstream>
 #include <limits.h>
 #include <stdlib.h>
+#include <set>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include "log.h"
 #include "launcher_env.h"
@@ -44,6 +49,51 @@ static std::string absolutePath(const std::string& path)
        return absPath;
 }
 
+static bool isFileExist(const std::string& path)
+{
+       struct stat sb;
+       return stat(path.c_str(), &sb) == 0;
+}
+
+static std::string replaceAll(const std::string& str, const std::string& pattern, const std::string& replace)
+{
+       std::string result = str;
+       std::string::size_type pos = 0;
+       std::string::size_type offset = 0;
+
+       while ((pos = result.find(pattern, offset)) != std::string::npos) {
+               result.replace(result.begin() + pos, result.begin() + pos + pattern.size(), replace);
+               offset = pos + replace.size();
+       }
+
+       return result;
+}
+
+static std::string findDllPath(const std::string& filename)
+{
+       const std::string netcoreappDir = "/usr/share/dotnet.tizen/netcoreapp/";
+       const std::string frameworkDir = "/usr/share/dotnet.tizen/framework/";
+
+       std::string result;
+
+       // check whether the target file exist under netcoreapp directory
+       result = netcoreappDir + filename;
+       if (isFileExist(result)) {
+               return result;
+       }
+
+       // check whether the target file exist under framework directory
+       result = frameworkDir + filename;
+       if (isFileExist(result)) {
+               return result;
+       }
+
+       // dll file is not found. return empty string
+       result.clear();
+
+       return result;
+}
+
 static void preloadAssemblies()
 {
 #ifdef USE_DEFAULT_BASE_ADDR
@@ -63,18 +113,75 @@ static void preloadAssemblies()
                return;
        }
 
-       std::ifstream preloadList(AOT_PRELOAD_PATH);
-       if (preloadList) {
-               std::string path;
-               while (getline(preloadList, path)) {
-                       int st = preloadAssembly(absolutePath(path).c_str());
-                       if (st != 0) {
-                               _DBG("preload of %s failed! (0x%08x)", path.c_str(), st);
-                       } else {
-                               _DBG("preload of %s succeded", path.c_str());
+       const std::string preloadDir = "/usr/share/dotnet.tizen/preload/";
+
+       // get file list from preload directory
+       // file is sorted by std::set
+       std::set<std::string> preloadFiles;
+       DIR* dirp = opendir(preloadDir.c_str());
+       struct dirent * dp;
+       while ((dp = readdir(dirp)) != NULL) {
+               if (dp->d_type != DT_DIR) {
+                       // Make sure that the file name follows naming conventions.
+                       if (dp->d_name &&
+                               isdigit(dp->d_name[0]) &&
+                               isdigit(dp->d_name[1]) &&
+                               (dp->d_name[2] == '.')) {
+                               preloadFiles.insert(preloadDir + dp->d_name);
                        }
                }
        }
+       closedir(dirp);
+
+       // get dll list from each preload file, and preload dll.
+       std::set<std::string> dllList;
+       std::ifstream ifs;
+       std::string in_line;
+       for (const auto& pf: preloadFiles) {
+               ifs.open(pf);
+               if (!ifs.is_open()) {
+                       _ERR("failed to open preload file (%s)", pf.c_str());
+                       continue;
+               }
+
+               while (std::getline(ifs, in_line)) {
+                       in_line = in_line.substr(0, in_line.find_first_of(" ", 0));
+
+                       // select dll file case
+                       if (in_line[0] == '#' ||
+                               in_line[0] == ' ' ||
+                               in_line.empty() ||
+                               (in_line.find(".dll") == std::string::npos)) {
+                               continue;
+                       }
+
+                       // only native image should be passed as a parameter of coreclr_preload_assembly.
+                       if (in_line.find(".ni.dll") == std::string::npos &&
+                               in_line.compare("System.Private.CoreLib.dll")) {
+                                       in_line = replaceAll(in_line, ".dll", ".ni.dll");
+                       }
+
+                       // coreclr_preload_assembly cannot ignore duplicate loading.
+                       // Therefore, only one dll should be preloaded.
+                       // dllList is used to ignore duplicated loading request
+                       if (dllList.insert(in_line).second) {
+                               // check whether the target file exist under netcoreapp directory
+                               std::string path = findDllPath(in_line);
+                               if (!path.empty()) {
+                                       int st = preloadAssembly(absolutePath(path).c_str());
+                                       if (st != 0) {
+                                               _ERR("preload of %s failed! (0x%08x)", path.c_str(), st);
+                                       } else {
+                                               _INFO("preload of %s succeeded", path.c_str());
+                                       }
+                               } else {
+                                       _ERR("preload failed : file (%s) does not eixst", in_line.c_str());
+                               }
+                       }
+               }
+
+               ifs.close();
+       }
 }
 
 int main(int argc, char** argv)
index 8c404d0..c295f2c 100644 (file)
@@ -31,6 +31,5 @@
 #define TIZEN_DOTNET_SDK_NUGET       "Tizen.NET.Sdk"
 #define NET_STANDARD_LIBRARY_NUGET   "NETStandard.Library"
 #define PLATFORM_TPA_CACHE           "/usr/share/dotnet.tizen/lib/platform_tpa_cache"
-#define AOT_PRELOAD_PATH             LOADERDIR "/dotnet.preload.list"
 
 #endif //__LAUNCHER_ENV_H_
\ No newline at end of file
index 9786b93..2d7f402 100644 (file)
@@ -167,7 +167,6 @@ chsmack -t -a User::App::Shared /opt/etc/skel/.dotnet
 %{_loaderdir}/dotnet.loader
 %{_loaderdir}/dotnet.launcher
 %{_loaderdir}/dotnet.debugger
-%{_loaderdir}/dotnet.preload.list
 %{_native_lib_dir}/libsqlite3.so
 %{_bindir}/nitool
 %{_bindir}/tpatool