#include <sys/wait.h>
#include <unistd.h>
#include <linux/limits.h>
+#include <pthread.h>
#include <storage.h>
#include <vconf.h>
static coreclr_shutdown_ptr shutdown = nullptr;
static coreclr_create_delegate_ptr createDelegate = nullptr;
static set_environment_variable_ptr setEnvironmentVariable = nullptr;
+static stop_profile_after_delay_ptr stopProfileAfterDelay = nullptr;
+static set_switch_ptr setSwitch = nullptr;
static void* __coreclrLib = nullptr;
static void* __hostHandle = nullptr;
static unsigned int __domainId = -1;
static bool __isProfileMode = false;
PathManager* CoreRuntime::__pm = nullptr;
+#define MAX_DELAY_SEC 100
+
static std::vector<std::string> __envList;
static void setEnvFromFile()
return true;
}
-static void initEnvForSpecialFolder()
+static void setSpecialFolder(storage_directory_e type, const char* key)
{
- int storageId;
int error;
- char *path = NULL;
+ char* path = NULL;
+ static int __storageId = -1;
- error = storage_foreach_device_supported(storage_cb, &storageId);
- if (error != STORAGE_ERROR_NONE) {
- return;
+ if (__storageId < 0) {
+ error = storage_foreach_device_supported(storage_cb, &__storageId);
+ if (error != STORAGE_ERROR_NONE) {
+ return;
+ }
}
- error = storage_get_directory(storageId, STORAGE_DIRECTORY_IMAGES, &path);
+ error = storage_get_directory(__storageId, type, &path);
if (error == STORAGE_ERROR_NONE && path != NULL) {
- setenv("XDG_PICTURES_DIR", const_cast<char *>(path), 1);
+ setenv(key, const_cast<char *>(path), 1);
free(path);
- path = NULL;
}
+}
- error = storage_get_directory(storageId, STORAGE_DIRECTORY_MUSIC, &path);
- if (error == STORAGE_ERROR_NONE && path != NULL) {
- setenv("XDG_MUSIC_DIR", const_cast<char *>(path), 1);
- free(path);
- path = NULL;
+static void initEnvForSpecialFolder()
+{
+ if (getenv("XDG_PICTURES_DIR") == NULL) {
+ setSpecialFolder(STORAGE_DIRECTORY_IMAGES, "XDG_PICTURES_DIR");
}
- error = storage_get_directory(storageId, STORAGE_DIRECTORY_VIDEOS, &path);
- if (error == STORAGE_ERROR_NONE && path != NULL) {
- setenv("XDG_VIDEOS_DIR", const_cast<char *>(path), 1);
- free(path);
- path = NULL;
+ if (getenv("XDG_MUSIC_DIR") == NULL) {
+ setSpecialFolder(STORAGE_DIRECTORY_MUSIC, "XDG_MUSIC_DIR");
}
-}
-// terminate candidate process when language changed
-// icu related data (CultureInfo, etc) should be recreated.
-static void langChangedCB(keynode_t *key, void* data)
-{
- _INFO("terminiate candidate process to update language.");
- exit(0);
+ if (getenv("XDG_VIDEOS_DIR") == NULL) {
+ setSpecialFolder(STORAGE_DIRECTORY_VIDEOS, "XDG_VIDEOS_DIR");
+ }
}
static void setLang()
{
+ //To reduce search overhead of libicuuc.so.xx
+ setenv("CLR_ICU_VERSION_OVERRIDE", "build", 1);
+
char* lang = vconf_get_str(VCONFKEY_LANGSET);
if (!lang) {
_ERR("Fail to get language from vconf");
bool initializeCoreClr(PathManager* pm, const std::string& tpa)
{
+ bool ncdbStartupHook = isNCDBStartupHookProvided();
+
const char *propertyKeys[] = {
"TRUSTED_PLATFORM_ASSEMBLIES",
"APP_PATHS",
"APP_NI_PATHS",
"NATIVE_DLL_SEARCH_DIRECTORIES",
- "AppDomainCompatSwitch"
+ "AppDomainCompatSwitch",
+ ncdbStartupHook ? "STARTUP_HOOKS" : "" // must be the last one
};
const char *propertyValues[] = {
pm->getAppPaths().c_str(),
pm->getAppNIPaths().c_str(),
pm->getNativeDllSearchingPaths().c_str(),
- "UseLatestBehaviorWhenTFMNotSpecified"
+ "UseLatestBehaviorWhenTFMNotSpecified",
+ ncdbStartupHook ? getNCDBStartupHook() : "" // must be the last one
};
std::string selfPath = readSelfPath();
int st = initializeClr(selfPath.c_str(),
"TizenDotnetApp",
- sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+ sizeof(propertyKeys) / sizeof(propertyKeys[0]) - (ncdbStartupHook ? 0 : 1),
propertyKeys,
propertyValues,
&__hostHandle,
return -1;
}
- // Intiailize ecore first (signal handlers, etc.) before runtime init.
- ecore_init();
-
// set language environment to support ICU
setLang();
// So, plugin initialize should be called before creating threads.
if (initializePluginManager(appType) < 0) {
_ERR("Failed to initialize PluginManager");
+ return -1;
}
// checkInjection checks dotnet-launcher run mode
// See https://github.com/dotnet/coreclr/issues/6698
//
// libunwind use following methods to unwind stack frame.
- // UNW_ARM_METHOD_ALL 0xFF
- // UNW_ARM_METHOD_DWARF 0x01
- // UNW_ARM_METHOD_FRAME 0x02
- // UNW_ARM_METHOD_EXIDX 0x04
+ // UNW_ARM_METHOD_ALL 0xFF
+ // UNW_ARM_METHOD_DWARF 0x01
+ // UNW_ARM_METHOD_FRAME 0x02
+ // UNW_ARM_METHOD_EXIDX 0x04
putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
#endif // __arm__
putenv(const_cast<char *>("COMPlus_UseDefaultBaseAddr=1"));
#endif // USE_DEFAULT_BASE_ADDR
+ // Disable config cache to set environment after coreclr_initialize()
+ putenv(const_cast<char *>("COMPlus_DisableConfigCache=1"));
+
// read string from external file and set them to environment value.
setEnvFromFile();
return -1;
}
- char* pluginPath = pluginGetDllPath();
- if (pluginPath) {
- __pm->addPlatformAssembliesPaths(pluginPath);
+ char* pluginDllPaths = pluginGetDllPath();
+ if (pluginDllPaths && pluginDllPaths[0] != '\0') {
+ __pm->addPlatformAssembliesPaths(pluginDllPaths, true);
+ }
+
+ char* pluginNativePaths = pluginGetNativeDllSearchingPath();
+ if (pluginNativePaths && pluginNativePaths[0] != '\0') {
+ __pm->addNativeDllSearchingPaths(pluginNativePaths, true);
}
- pluginHasLogControl();
+ char* pluginExtraDllPaths = pluginGetExtraDllPath();
+ if (pluginExtraDllPaths && pluginExtraDllPaths[0] != '\0') {
+ __pm->setExtraDllPaths(pluginExtraDllPaths);
+ }
std::string libCoreclr(concatPath(__pm->getRuntimePath(), "libcoreclr.so"));
std::string tpa;
char* pluginTPA = pluginGetTPA();
- if (pluginTPA) {
+ if (pluginTPA && pluginTPA[0] != '\0') {
tpa = std::string(pluginTPA);
} else {
addAssembliesFromDirectories(__pm->getPlatformAssembliesPaths(), tpa);
return -1;
}
- if (launchMode == LaunchMode::loader) {
- // terminate candidate process if language is changed.
- // CurrentCulture created for preloaded dlls should be updated.
- vconf_notify_key_changed(VCONFKEY_LANGSET, langChangedCB, NULL);
+ st = createDelegate(__hostHandle, __domainId, "Tizen.Runtime", "Tizen.Runtime.Profiler", "StopProfileAfterDelay", (void**)&stopProfileAfterDelay);
+ if (st < 0 || stopProfileAfterDelay == nullptr) {
+ _ERR("Create delegate for Tizen.Runtime.dll -> Tizen.Runtime.Profiler -> StopProfileAfterDelay failed (0x%08x)", st);
+ return -1;
+ }
+
+ st = createDelegate(__hostHandle, __domainId, "Tizen.Runtime", "Tizen.Runtime.AppSetting", "SetSwitch", (void**)&setSwitch);
+ if (st < 0 || setSwitch == nullptr) {
+ _ERR("Create delegate for Tizen.Runtime.dll -> Tizen.Runtime.AppSetting -> SetSwitch failed (0x%08x)", st);
+ return -1;
+ }
+ if (launchMode == LaunchMode::loader) {
// preload libraries and manage dlls for optimizing startup time
preload();
checkOnTerminate = true;
// workaround : to prevent crash while process terminate on profiling mode,
- // kill process immediately.
+ // kill process immediately.
// see https://github.com/dotnet/coreclr/issues/26687
if (__isProfileMode) {
_INFO("shutdown process immediately.");
// set profile.data path and collect/use it if it non-exists/exists.
if (profile) {
- char multiCoreJitProfile[strlen(localDataPath) + strlen(PROFILE_BASENAME)];
- strcpy(multiCoreJitProfile, localDataPath);
- strcat(multiCoreJitProfile, PROFILE_BASENAME);
+ char multiCoreJitProfile[strlen(localDataPath) + strlen(PROFILE_BASENAME) + 1];
+ memcpy(multiCoreJitProfile, localDataPath, strlen(localDataPath) + 1);
+ strncat(multiCoreJitProfile, PROFILE_BASENAME, strlen(PROFILE_BASENAME));
setEnvironmentVariable("COMPlus_MultiCoreJitProfile", multiCoreJitProfile);
- if (!access(multiCoreJitProfile, R_OK)) {
+ setEnvironmentVariable("COMPlus_MultiCoreJitMinNumCpus", "1");
+
+ if (exist(multiCoreJitProfile)) {
setEnvironmentVariable("COMPlus_MultiCoreJitNoProfileGather", "1");
+ _INFO("MCJ playing start for %s", appId);
+ } else {
+ setEnvironmentVariable("COMPlus_MultiCoreJitNoProfileGather", "0");
+ // stop profiling and write collected data after delay if env value is set.
+ char *env = getenv("CLR_MCJ_PROFILE_WRITE_DELAY");
+ if (env != nullptr) {
+ int delay = std::atoi(env);
+ // To avoid undefined behavior by out-of-range input(atoi), set max delay value to 100.
+ if (delay > 0) {
+ if (delay > MAX_DELAY_SEC) delay = MAX_DELAY_SEC;
+ stopProfileAfterDelay(delay);
+ }
+ }
+ _INFO("MCJ recording start for %s", appId);
}
}
free(localDataPath);
}
- vconf_ignore_key_changed(VCONFKEY_LANGSET, langChangedCB);
+ if (exist(__pm->getAppRootPath() + "/bin/" + DISABLE_IPV6_FILE)) {
+ setSwitch("System.Net.DisableIPv6", true);
+ }
+
+ setSwitch("Switch.System.Diagnostics.StackTrace.ShowILOffsets", true);
pluginBeforeExecute();