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 d56554848f8e893e2d41fd76f7d1ad98a463b443..773686c229cdef957a90856b96fe1c1fca69c71e 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 f446e36e671fdda942f024d3b1b45959d43b2563..b0e7671dae56d19da2dc56fc3f41f19b5075d651 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 8c404d0a33d69f7b304b3bb19103e952d0772400..c295f2cccd7037c105c814eb16f51322ff812870 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 9786b93a1653cddb6836583f981418416e7d547d..2d7f4028160a6d2a9d9f815b4aa43f2550b2a54a 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