From d858bf937476ac12ec898d38b3a092c10b97006b Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Thu, 29 Dec 2016 17:45:11 +0100 Subject: [PATCH 01/13] Fix PAL double initialize --- bin/ch/ChakraRtInterface.cpp | 11 +- bin/ch/Helpers.cpp | 102 ++++++ bin/ch/WScriptJsrt.cpp | 71 ---- bin/ch/ch.cpp | 5 +- bin/ch/stdafx.h | 3 + lib/Common/Core/SysInfo.cpp | 2 +- .../Memory/RecyclerWriteBarrierManager.cpp | 2 +- lib/Jsrt/JsrtHelper.cpp | 2 +- pal/inc/pal.h | 72 +--- pal/src/exception/machexception.cpp | 25 +- pal/src/exception/machexception.h | 2 +- pal/src/init/pal.cpp | 228 ++---------- pal/src/thread/process.cpp | 345 ++++++++---------- 13 files changed, 301 insertions(+), 569 deletions(-) diff --git a/bin/ch/ChakraRtInterface.cpp b/bin/ch/ChakraRtInterface.cpp index 2c800e79984..5ae4b2dc4ca 100644 --- a/bin/ch/ChakraRtInterface.cpp +++ b/bin/ch/ChakraRtInterface.cpp @@ -49,15 +49,8 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) #ifndef CHAKRA_STATIC_LIBRARY HINSTANCE library = nullptr; - char filename[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - - char modulename[_MAX_PATH]; - GetModuleFileNameA(NULL, modulename, _MAX_PATH); - _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); - _makepath_s(filename, drive, dir, chakraDllName, nullptr); - LPCSTR dllName = filename; + char dllName[_MAX_PATH]; + GetBinaryPathWithFileNameA(dllName, _MAX_PATH, chakraDllName); library = LoadChakraCore(dllName); *outLibrary = library; diff --git a/bin/ch/Helpers.cpp b/bin/ch/Helpers.cpp index 9d3101450b3..1ed30aff675 100644 --- a/bin/ch/Helpers.cpp +++ b/bin/ch/Helpers.cpp @@ -6,6 +6,14 @@ #include +#if defined(__APPLE__) +#include // _NSGetExecutablePath +#elif defined(__linux__) +#include // readlink +#elif !defined(_WIN32) +#error "How to get the executable path for this platform?" +#endif // _WIN32 ? + //TODO: x-plat definitions #ifdef _WIN32 typedef char16 TTDHostCharType; @@ -725,3 +733,97 @@ void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, b fclose((FILE*)handle); } +#define SET_BINARY_PATH_ERROR_MESSAGE(path, msg) \ + str_len = (int) strlen(msg); \ + memcpy(path, msg, (size_t)str_len); \ + path[str_len] = char(0) + +void GetBinaryLocation(char *path, const unsigned size) +{ + AssertMsg(path != nullptr, "Path can not be nullptr"); + AssertMsg(size < INT_MAX, "Isn't it too big for a path buffer?"); +#ifdef _WIN32 + LPWSTR wpath = (WCHAR*)malloc(sizeof(WCHAR) * size); + int str_len; + if (!wpath) + { + SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed. OutOfMemory!"); + return; + } + str_len = GetModuleFileNameW(NULL, wpath, size - 1); + if (str_len <= 0) + { + SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed."); + free(wpath); + return; + } + + str_len = WideCharToMultiByte(CP_UTF8, 0, wpath, str_len, path, size, NULL, NULL); + free(wpath); + + if (str_len <= 0) + { + SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName (WideCharToMultiByte) has failed."); + return; + } + + if ((unsigned)str_len > size - 1) + { + str_len = (int) size - 1; + } + path[str_len] = char(0); +#elif defined(__APPLE__) + uint32_t path_size = (uint32_t)size; + char *tmp = nullptr; + int str_len; + if (_NSGetExecutablePath(path, &path_size)) + { + SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: _NSGetExecutablePath has failed."); + return; + } + + tmp = (char*)malloc(size); + char *result = realpath(path, tmp); + str_len = strlen(result); + memcpy(path, result, str_len); + free(tmp); + path[str_len] = char(0); +#elif defined(__linux__) + int str_len = readlink("/proc/self/exe", path, size - 1); + if (str_len <= 0) + { + SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: /proc/self/exe has failed."); + return; + } + path[str_len] = char(0); +#else +#warning "Implement GetBinaryLocation for this platform" +#endif +} + +// xplat-todo: Implement a corresponding solution for GetModuleFileNameW +// and cleanup PAL. [ https://github.com/Microsoft/ChakraCore/pull/2288 should be merged first ] +// GetModuleFileName* PAL is not reliable and forces us to explicitly double initialize PAL +// with argc / argv.... +void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename) +{ + char fullpath[_MAX_PATH]; + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + + char modulename[_MAX_PATH]; + GetBinaryLocation(modulename, _MAX_PATH); + _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0); + _makepath_s(fullpath, drive, dir, filename, nullptr); + + size_t len = strlen(fullpath); + if (len < buffer_size) + { + memcpy(path, fullpath, len * sizeof(char)); + } + else + { + len = 0; + } + path[len] = char(0); +} diff --git a/bin/ch/WScriptJsrt.cpp b/bin/ch/WScriptJsrt.cpp index 6c3b109db27..9e13ffc6a45 100644 --- a/bin/ch/WScriptJsrt.cpp +++ b/bin/ch/WScriptJsrt.cpp @@ -20,17 +20,14 @@ #define DEST_PLATFORM_TEXT "win32" #else // ! _WIN32 #if defined(__APPLE__) -#include // _NSGetExecutablePath #ifdef __IOS__ #define DEST_PLATFORM_TEXT "ios" #else // ! iOS #define DEST_PLATFORM_TEXT "darwin" #endif // iOS ? #elif defined(__ANDROID__) -#include // readlink #define DEST_PLATFORM_TEXT "android" #elif defined(__linux__) -#include // readlink #define DEST_PLATFORM_TEXT "posix" #elif defined(__FreeBSD__) || defined(__unix__) #define DEST_PLATFORM_TEXT "bsd" @@ -740,74 +737,6 @@ bool WScriptJsrt::InstallObjectsOnObject(JsValueRef object, const char* name, return true; } -#define SET_BINARY_PATH_ERROR_MESSAGE(path, msg) \ - str_len = (int) strlen(msg); \ - memcpy(path, msg, (size_t)str_len); \ - path[str_len] = char(0) - -void GetBinaryLocation(char *path, const unsigned size) -{ - AssertMsg(size >= 512 && path != nullptr, "Min path buffer size 512 and path can not be nullptr"); - AssertMsg(size < INT_MAX, "Isn't it too big for a path buffer?"); -#ifdef _WIN32 - LPWSTR wpath = (WCHAR*)malloc(sizeof(WCHAR) * size); - int str_len; - if (!wpath) - { - SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed. OutOfMemory!"); - return; - } - str_len = GetModuleFileNameW(NULL, wpath, size - 1); - if (str_len <= 0) - { - SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName has failed."); - free(wpath); - return; - } - - str_len = WideCharToMultiByte(CP_UTF8, 0, wpath, str_len, path, size, NULL, NULL); - free(wpath); - - if (str_len <= 0) - { - SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: GetModuleFileName (WideCharToMultiByte) has failed."); - return; - } - - if ((unsigned)str_len > size - 1) - { - str_len = (int) size - 1; - } - path[str_len] = char(0); -#elif defined(__APPLE__) - uint32_t path_size = (uint32_t)size; - char *tmp = nullptr; - int str_len; - if (_NSGetExecutablePath(path, &path_size)) - { - SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: _NSGetExecutablePath has failed."); - return; - } - - tmp = (char*)malloc(size); - char *result = realpath(path, tmp); - str_len = strlen(result); - memcpy(path, result, str_len); - free(tmp); - path[str_len] = char(0); -#elif defined(__linux__) - int str_len = readlink("/proc/self/exe", path, size - 1); - if (str_len <= 0) - { - SET_BINARY_PATH_ERROR_MESSAGE(path, "GetBinaryLocation: /proc/self/exe has failed."); - return; - } - path[str_len] = char(0); -#else -#warning "Implement GetBinaryLocation for this platform" -#endif -} - bool WScriptJsrt::Initialize() { HRESULT hr = S_OK; diff --git a/bin/ch/ch.cpp b/bin/ch/ch.cpp index 6eb4ddab1e1..f1ff35c5af0 100644 --- a/bin/ch/ch.cpp +++ b/bin/ch/ch.cpp @@ -737,7 +737,10 @@ unsigned int WINAPI StaticThreadProc(void *lpParam) static char16** argv = nullptr; int main(int argc, char** c_argv) { - PAL_InitializeChakraCore(argc, c_argv); +#ifndef CHAKRA_STATIC_LIBRARY +// xplat-todo: PAL free CH ? + PAL_InitializeChakraCore(); +#endif argv = new char16*[argc]; for (int i = 0; i < argc; i++) { diff --git a/bin/ch/stdafx.h b/bin/ch/stdafx.h index 5869aa57ab2..cee8c0bbe4b 100644 --- a/bin/ch/stdafx.h +++ b/bin/ch/stdafx.h @@ -257,3 +257,6 @@ inline JsErrorCode CreatePropertyIdFromString(const char* str, JsPropertyIdRef * { return ChakraRTInterface::JsCreatePropertyId(str, strlen(str), Id); } + +void GetBinaryLocation(char *path, const unsigned size); +void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename); diff --git a/lib/Common/Core/SysInfo.cpp b/lib/Common/Core/SysInfo.cpp index c50f8d7bcd6..91c4df449b0 100644 --- a/lib/Common/Core/SysInfo.cpp +++ b/lib/Common/Core/SysInfo.cpp @@ -65,7 +65,7 @@ AutoSystemInfo::Initialize() { Assert(!initialized); #ifndef _WIN32 - PAL_InitializeDLL(); + PAL_InitializeChakraCore(); majorVersion = CHAKRA_CORE_MAJOR_VERSION; minorVersion = CHAKRA_CORE_MINOR_VERSION; #endif diff --git a/lib/Common/Memory/RecyclerWriteBarrierManager.cpp b/lib/Common/Memory/RecyclerWriteBarrierManager.cpp index 40a8d06dca5..12723c75b1b 100644 --- a/lib/Common/Memory/RecyclerWriteBarrierManager.cpp +++ b/lib/Common/Memory/RecyclerWriteBarrierManager.cpp @@ -57,7 +57,7 @@ X64WriteBarrierCardTableManager::OnThreadInit() ULONG_PTR stackEnd = 0; ::GetCurrentThreadStackLimits(&stackEnd, &stackBase); #endif - + size_t numPages = (stackBase - stackEnd) / AutoSystemInfo::PageSize; // stackEnd is the lower boundary return OnSegmentAlloc((char*) stackEnd, numPages); diff --git a/lib/Jsrt/JsrtHelper.cpp b/lib/Jsrt/JsrtHelper.cpp index 5ea2b66891a..4567c59ee25 100644 --- a/lib/Jsrt/JsrtHelper.cpp +++ b/lib/Jsrt/JsrtHelper.cpp @@ -121,7 +121,7 @@ void JsrtCallbackState::ObjectBeforeCallectCallbackWrapper(JsObjectBeforeCollect #endif #ifndef _WIN32 - PAL_InitializeChakraCore(0, NULL); + PAL_InitializeChakraCore(); #endif HMODULE mod = GetModuleHandleW(NULL); diff --git a/pal/inc/pal.h b/pal/inc/pal.h index 09f359bcdd5..07580abefe9 100644 --- a/pal/inc/pal.h +++ b/pal/inc/pal.h @@ -390,51 +390,14 @@ typedef long time_t; #define DLL_THREAD_DETACH 3 #define DLL_PROCESS_DETACH 0 -#define PAL_INITIALIZE_NONE 0x00 -#define PAL_INITIALIZE_SYNC_THREAD 0x01 -#define PAL_INITIALIZE_EXEC_ALLOCATOR 0x02 -#define PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER 0x08 -#define PAL_INITIALIZE_DEBUGGER_EXCEPTIONS 0x10 - -// PAL_Initialize() flags -#define PAL_INITIALIZE PAL_INITIALIZE_SYNC_THREAD - -// PAL_InitializeDLL() flags - don't start any of the helper threads -#define PAL_INITIALIZE_DLL PAL_INITIALIZE_NONE - -// PAL_InitializeChakraCore() flags -#define PAL_INITIALIZE_CHAKRACORE (PAL_INITIALIZE | PAL_INITIALIZE_EXEC_ALLOCATOR) - typedef DWORD (PALAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; /******************* PAL-Specific Entrypoints *****************************/ -PALIMPORT -int -PALAPI -PAL_Initialize( - int argc, - const char * const argv[]); - -PALIMPORT int PALAPI -PAL_InitializeDLL(); - -PALIMPORT -DWORD -PALAPI -PAL_InitializeChakraCore( - int argc, - char** argv); - -PALIMPORT -DWORD_PTR -PALAPI -PAL_EntryPoint( - IN LPTHREAD_START_ROUTINE lpStartAddress, - IN LPVOID lpParameter); +PAL_InitializeChakraCore(); /// /// This function shuts down PAL WITHOUT exiting the current process. @@ -464,30 +427,6 @@ PALAPI PAL_TerminateEx( int exitCode); -/*++ -Function: - PAL_SetShutdownCallback - -Abstract: - Sets a callback that is executed when the PAL is shut down because of - ExitProcess, TerminateProcess or PAL_Shutdown but not PAL_Terminate/Ex. - - NOTE: Currently only one callback can be set at a time. ---*/ -typedef VOID (*PSHUTDOWN_CALLBACK)(void); - -PALIMPORT -VOID -PALAPI -PAL_SetShutdownCallback( - IN PSHUTDOWN_CALLBACK callback); - -PALIMPORT -void -PALAPI -PAL_InitializeDebug( - void); - PALIMPORT VOID PALAPI @@ -522,15 +461,6 @@ PAL_Random( IN OUT LPVOID lpBuffer, IN DWORD dwLength); -// This helper will be used *only* by the CoreCLR to determine -// if an address lies inside CoreCLR or not. -// -// This shouldnt be used by any other component that links into the PAL. -PALIMPORT -BOOL -PALAPI -PAL_IsIPInCoreCLR(IN PVOID address); - #ifdef PLATFORM_UNIX PALIMPORT diff --git a/pal/src/exception/machexception.cpp b/pal/src/exception/machexception.cpp index e06ca5342c0..220db019b3f 100644 --- a/pal/src/exception/machexception.cpp +++ b/pal/src/exception/machexception.cpp @@ -48,8 +48,6 @@ mach_port_t s_ExceptionPort; static BOOL s_DebugInitialized = FALSE; -static DWORD s_PalInitializeFlags = 0; - static const char * PAL_MACH_EXCEPTION_MODE = "PAL_MachExceptionMode"; // This struct is used to track the threads that need to have an exception forwarded @@ -191,23 +189,6 @@ GetExceptionMask() { machExceptionMask |= PAL_EXC_ILLEGAL_MASK; } - if (!(exMode & MachException_SuppressDebugging) && (s_PalInitializeFlags & PAL_INITIALIZE_DEBUGGER_EXCEPTIONS)) - { -#ifdef FEATURE_PAL_SXS - // Always hook exception ports for breakpoint exceptions. - // The reason is that we don't know when a managed debugger - // will attach, so we have to be prepared. We don't want - // to later go through the thread list and hook exception - // ports for exactly those threads that currently are in - // this PAL. - machExceptionMask |= PAL_EXC_DEBUGGING_MASK; -#else // FEATURE_PAL_SXS - if (s_DebugInitialized) - { - machExceptionMask |= PAL_EXC_DEBUGGING_MASK; - } -#endif // FEATURE_PAL_SXS - } if (!(exMode & MachException_SuppressManaged)) { machExceptionMask |= PAL_EXC_MANAGED_MASK; @@ -1378,20 +1359,16 @@ Function : Initialize all SEH-related stuff related to mach exceptions - flags - PAL_INITIALIZE flags - Return value : TRUE if SEH support initialization succeeded FALSE otherwise --*/ BOOL -SEHInitializeMachExceptions(DWORD flags) +SEHInitializeMachExceptions() { pthread_t exception_thread; kern_return_t machret; - s_PalInitializeFlags = flags; - // Allocate a mach port that will listen in on exceptions machret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &s_ExceptionPort); if (machret != KERN_SUCCESS) diff --git a/pal/src/exception/machexception.h b/pal/src/exception/machexception.h index a035052b790..2fb7898c5bd 100644 --- a/pal/src/exception/machexception.h +++ b/pal/src/exception/machexception.h @@ -36,7 +36,7 @@ extern "C" #define PAL_EXC_ALL_MASK (PAL_EXC_ILLEGAL_MASK | PAL_EXC_DEBUGGING_MASK | PAL_EXC_MANAGED_MASK) // Process and thread initialization/cleanup/context routines -BOOL SEHInitializeMachExceptions(DWORD flags); +BOOL SEHInitializeMachExceptions(); void SEHCleanupExceptionPort (void); void MachExceptionInitializeDebug(void); PAL_NORETURN void MachSetThreadContext(CONTEXT *lpContext); diff --git a/pal/src/init/pal.cpp b/pal/src/init/pal.cpp index c6e9b72341d..44bf67458dc 100644 --- a/pal/src/init/pal.cpp +++ b/pal/src/init/pal.cpp @@ -94,7 +94,6 @@ static pthread_mutex_t init_critsec_mutex = PTHREAD_MUTEX_INITIALIZER; very first PAL_Initialize call, and is freed afterward. */ static PCRITICAL_SECTION init_critsec = NULL; -static int Initialize(int argc, const char *const argv[], DWORD flags); static BOOL INIT_IncreaseDescriptorLimit(void); static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv); static LPWSTR INIT_FindEXEPath(LPCSTR exe_name); @@ -103,49 +102,6 @@ static LPWSTR INIT_FindEXEPath(LPCSTR exe_name); extern void PROCDumpThreadList(void); #endif -/*++ -Function: - PAL_Initialize - -Abstract: - This function is the first function of the PAL to be called. - Internal structure initialization is done here. It could be called - several time by the same process, a reference count is kept. - -Return: - 0 if successful - -1 if it failed - ---*/ - -int -PALAPI -PAL_Initialize( - int argc, - const char *const argv[]) -{ - return Initialize(argc, argv, PAL_INITIALIZE); -} - -/*++ -Function: - PAL_InitializeDLL - -Abstract: - Initializes the non-runtime DLLs/modules like the DAC and SOS. - -Return: - 0 if successful - -1 if it failed - ---*/ -int -PALAPI -PAL_InitializeDLL() -{ - return Initialize(0, NULL, PAL_INITIALIZE_DLL); -} - /*++ Function: Initialize @@ -158,24 +114,19 @@ PAL_InitializeDLL() -1 if it failed --*/ -int -Initialize( - int argc, - const char *const argv[], - DWORD flags) +static int +Initialize() { PAL_ERROR palError = ERROR_GEN_FAILURE; CPalThread *pThread = NULL; CSharedMemoryObjectManager *pshmom = NULL; - LPWSTR command_line = NULL; - LPWSTR exe_path = NULL; int retval = -1; bool fFirstTimeInit = false; /* the first ENTRY within the first call to PAL_Initialize is a special case, since debug channels are not initialized yet. So in that case the ENTRY will be called after the DBG channels initialization */ - ENTRY_EXTERNAL("PAL_Initialize(argc = %d argv = %p)\n", argc, argv); + ENTRY_EXTERNAL("PAL_Initialize()\n"); /*Firstly initiate a lastError */ SetLastError(ERROR_GEN_FAILURE); @@ -232,7 +183,6 @@ Initialize( { goto done; } - #if _DEBUG // Verify that our page size is what we think it is. If it's // different, we can't run. @@ -261,7 +211,6 @@ Initialize( // // Initialize global process data // - palError = InitializeProcessData(); if (NO_ERROR != palError) { @@ -272,7 +221,7 @@ Initialize( #if HAVE_MACH_EXCEPTIONS // Mach exception port needs to be set up before the thread // data or threads are set up. - if (!SEHInitializeMachExceptions(flags)) + if (!SEHInitializeMachExceptions()) { ERROR("SEHInitializeMachExceptions failed!\n"); palError = ERROR_GEN_FAILURE; @@ -283,7 +232,6 @@ Initialize( // // Initialize global thread data // - palError = InitializeGlobalThreadData(); if (NO_ERROR != palError) { @@ -301,7 +249,6 @@ Initialize( ERROR("Unable to create initial thread data\n"); goto CLEANUP1a; } - PROCAddThread(pThread, pThread); // @@ -318,7 +265,6 @@ Initialize( // // It's now safe to access our thread data // - g_fThreadDataAvailable = TRUE; // @@ -334,7 +280,6 @@ Initialize( // // Initialize the object manager // - pshmom = InternalNew(); if (NULL == pshmom) { @@ -373,63 +318,6 @@ Initialize( palError = ERROR_GEN_FAILURE; - if (argc > 0 && argv != NULL) - { - /* build the command line */ - command_line = INIT_FormatCommandLine(argc, argv); - if (NULL == command_line) - { - ERROR("Error building command line\n"); - goto CLEANUP1d; - } - - /* find out the application's full path */ - exe_path = INIT_FindEXEPath(argv[0]); - if (NULL == exe_path) - { - ERROR("Unable to find exe path\n"); - goto CLEANUP1e; - } - - if (NULL == command_line || NULL == exe_path) - { - ERROR("Failed to process command-line parameters!\n"); - goto CLEANUP2; - } - - palError = InitializeProcessCommandLine( - command_line, - exe_path); - - if (NO_ERROR != palError) - { - ERROR("Unable to initialize command line\n"); - goto CLEANUP2; - } - - // InitializeProcessCommandLine took ownership of this memory. - command_line = NULL; - -#ifdef PAL_PERF - // Initialize the Profiling structure - if(FALSE == PERFInitialize(command_line, exe_path)) - { - ERROR("Performance profiling initial failed\n"); - goto CLEANUP2; - } - PERFAllocThreadInfo(); -#endif - - if (!LOADSetExeName(exe_path)) - { - ERROR("Unable to set exe name\n"); - goto CLEANUP2; - } - - // LOADSetExeName took ownership of this memory. - exe_path = NULL; - } - if (init_count == 0) { // @@ -439,7 +327,7 @@ Initialize( if (NO_ERROR != palError) { ERROR("Unable to create initial process and thread objects\n"); - goto CLEANUP2; + goto CLEANUP5; } #if !HAVE_MACH_EXCEPTIONS @@ -449,19 +337,6 @@ Initialize( } #endif - if (flags & PAL_INITIALIZE_SYNC_THREAD) - { - // - // Tell the synchronization manager to start its worker thread - // - palError = CPalSynchMgrController::StartWorker(pThread); - if (NO_ERROR != palError) - { - ERROR("Synch manager failed to start worker thread\n"); - goto CLEANUP5; - } - } - palError = ERROR_GEN_FAILURE; if (FALSE == TIMEInitialize()) @@ -477,14 +352,6 @@ Initialize( goto CLEANUP6; } - /* Initialize the Virtual* functions. */ - bool initializeExecutableMemoryAllocator = (flags & PAL_INITIALIZE_EXEC_ALLOCATOR) != 0; - if (FALSE == VIRTUALInitialize(initializeExecutableMemoryAllocator)) - { - ERROR("Unable to initialize virtual memory support\n"); - goto CLEANUP10; - } - /* create file objects for standard handles */ if(!FILEInitStdHandles()) { @@ -533,10 +400,6 @@ Initialize( CLEANUP6: CLEANUP5: PROCCleanupInitialProcess(); -CLEANUP2: - InternalFree(exe_path); -CLEANUP1e: - InternalFree(command_line); CLEANUP1d: // Cleanup synchronization manager CLEANUP1c: @@ -550,6 +413,7 @@ Initialize( CLEANUP0: ERROR("PAL_Initialize failed\n"); SetLastError(palError); + done: #ifdef PAL_PERF if( retval == 0) @@ -594,21 +458,36 @@ Initialize( --*/ static bool pal_was_initialized = false; -PAL_ERROR +int PALAPI -PAL_InitializeChakraCore(int argc, char** argv) +PAL_InitializeChakraCore() { // this is not thread safe but PAL_InitializeChakraCore is per process // besides, calling Jsrt initializer function is thread safe if (pal_was_initialized) return ERROR_SUCCESS; - // Fake up a command line to call PAL initialization with. - int result = Initialize(argc, argv, PAL_INITIALIZE_CHAKRACORE); - if (result != 0) + if (Initialize()) { return GetLastError(); } + CPalThread *pThread = InternalGetCurrentThread(); + // + // Tell the synchronization manager to start its worker thread + // + int error = CPalSynchMgrController::StartWorker(pThread); + if (NO_ERROR != error) + { + ERROR("Synch manager failed to start worker thread\n"); + return error; + } + + if (FALSE == VIRTUALInitialize(true)) + { + ERROR("Unable to initialize virtual memory support\n"); + return ERROR_GEN_FAILURE; + } + // Check for a repeated call (this is a no-op). if (InterlockedIncrement(&g_chakraCoreInitialized) > 1) { @@ -680,40 +559,6 @@ PAL_IsDebuggerPresent() #endif } -/*++ -Function: - PAL_EntryPoint - -Abstract: - This function should be used to wrap code that uses PAL library on thread that was not created by PAL. ---*/ -PALIMPORT -DWORD_PTR -PALAPI -PAL_EntryPoint( - IN LPTHREAD_START_ROUTINE lpStartAddress, - IN LPVOID lpParameter) -{ - CPalThread *pThread; - DWORD_PTR retval = (DWORD) -1; - - ENTRY("PAL_EntryPoint(lpStartAddress=%p, lpParameter=%p)\n", lpStartAddress, lpParameter); - - pThread = InternalGetCurrentThread(); - if (NULL == pThread) - { - /* This function works only for thread that called PAL_Initialize for now. */ - ERROR( "Unable to get the thread object.\n" ); - goto done; - } - - retval = (*lpStartAddress)(lpParameter); - -done: - LOGEXIT("PAL_EntryPoint returns int %d\n", retval); - return retval; -} - /*++ Function: PAL_Shutdown @@ -775,27 +620,6 @@ PAL_TerminateEx( exit(exitCode); } -/*++ -Function: - PAL_InitializeDebug - -Abstract: - This function is the called when cordbg attaches to the process. ---*/ -void -PALAPI -PAL_InitializeDebug( - void) -{ - PERF_ENTRY(PAL_InitializeDebug); - ENTRY("PAL_InitializeDebug()\n"); -#if HAVE_MACH_EXCEPTIONS - MachExceptionInitializeDebug(); -#endif - LOGEXIT("PAL_InitializeDebug returns\n"); - PERF_EXIT(PAL_InitializeDebug); -} - /*++ Function: PALIsThreadDataInitialized diff --git a/pal/src/thread/process.cpp b/pal/src/thread/process.cpp index 993116f5e6c..a855bf07fd7 100644 --- a/pal/src/thread/process.cpp +++ b/pal/src/thread/process.cpp @@ -1,6 +1,6 @@ // // Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. // /*++ @@ -97,7 +97,7 @@ static int s_helperPage[VIRTUAL_PAGE_SIZE / sizeof(int)] __attribute__((aligned( // // Mutex to make the FlushProcessWriteBuffersMutex thread safe -// +// pthread_mutex_t flushProcessWriteBuffersMutex PAL_GLOBAL; CAllowedObjectTypes aotProcess PAL_GLOBAL (otiProcess); @@ -125,15 +125,12 @@ DWORD g_dwThreadCount; LPWSTR g_lpwstrCmdLine = NULL; LPWSTR g_lpwstrAppDir = NULL; -// Thread ID of thread that has started the ExitProcess process +// Thread ID of thread that has started the ExitProcess process Volatile terminator PAL_GLOBAL = 0; // Process ID of this process. DWORD gPID = (DWORD) -1; -// Function to call during PAL/process shutdown -PSHUTDOWN_CALLBACK g_shutdownCallback = nullptr; - // // Key used for associating CPalThread's with the underlying pthread // (through pthread_setspecific) @@ -556,7 +553,7 @@ CorUnix::InternalCreateProcess( int iFdOut = -1; IPalObject *pobjFileErr = NULL; int iFdErr = -1; - + pid_t processId; char * lpFileName; PathCharString lpFileNamePS; @@ -579,7 +576,7 @@ CorUnix::InternalCreateProcess( lpApplicationName); palError = ERROR_INVALID_PARAMETER; goto InternalCreateProcessExit; - } + } if (0 != (dwCreationFlags & ~(CREATE_SUSPENDED|CREATE_NEW_CONSOLE))) { @@ -685,7 +682,7 @@ CorUnix::InternalCreateProcess( palError = ERROR_FILE_NOT_FOUND; goto InternalCreateProcessExit; } - + lpFileNamePS.CloseBuffer(MAX_LONGPATH-1); /* check type of file */ iRet = checkFileType(lpFileName); @@ -696,7 +693,7 @@ CorUnix::InternalCreateProcess( WARN ("File is not valid (%s)", lpFileName); palError = ERROR_FILE_NOT_FOUND; goto InternalCreateProcessExit; - + case FILE_UNIX: /* Unix binary file */ break; /* nothing to do */ @@ -759,7 +756,7 @@ CorUnix::InternalCreateProcess( palError = g_pObjectManager->AllocateObject( pThread, &otProcess, - &oa, + &oa, &pobjProcess ); @@ -801,7 +798,7 @@ CorUnix::InternalCreateProcess( &pDummyThread, &hDummyThread ); - + if (dwCreationFlags & CREATE_SUSPENDED) { int pipe_descs[2]; @@ -811,7 +808,7 @@ CorUnix::InternalCreateProcess( ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno)); palError = ERROR_NOT_ENOUGH_MEMORY; goto InternalCreateProcessExit; - } + } /* [0] is read end, [1] is write end */ pDummyThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]); @@ -846,9 +843,9 @@ CorUnix::InternalCreateProcess( if (NO_ERROR != palError) { ASSERT("Unable to obtain local data for new process object\n"); - goto InternalCreateProcessExit; + goto InternalCreateProcessExit; } - + /* fork the new process */ processId = fork(); @@ -866,15 +863,15 @@ CorUnix::InternalCreateProcess( goto InternalCreateProcessExit; } - /* From the time the child process begins running, to when it reaches execve, + /* From the time the child process begins running, to when it reaches execve, the child process is not a real PAL process and does not own any PAL - resources, although it has access to the PAL resources of its parent process. - Thus, while the child process is in this window, it is dangerous for it to affect + resources, although it has access to the PAL resources of its parent process. + Thus, while the child process is in this window, it is dangerous for it to affect its parent's PAL resources. As a consequence, no PAL code should be used in this window; all code should make unix calls. Note the use of _exit instead of exit to avoid calling PAL_Terminate and the lack of TRACE's and ASSERT's. */ - + if (processId == 0) /* child process */ { // At this point, the PAL should be considered uninitialized for this child process. @@ -883,8 +880,8 @@ CorUnix::InternalCreateProcess( // calling PAL functions. Furthermore, nothing should be changing // the init_count in the child process at this point since this is the only // thread executing. - init_count = 0; - + init_count = 0; + sigset_t sm; // @@ -897,7 +894,7 @@ CorUnix::InternalCreateProcess( { _exit(EXIT_FAILURE); } - + if (dwCreationFlags & CREATE_SUSPENDED) { BYTE resume_code = 0; @@ -917,7 +914,7 @@ CorUnix::InternalCreateProcess( } else { - /* note : read might return 0 (and return EAGAIN) if the other + /* note : read might return 0 (and return EAGAIN) if the other end of the pipe gets closed - for example because the parent process dies (very) abruptly */ _exit(EXIT_FAILURE); @@ -960,9 +957,9 @@ CorUnix::InternalCreateProcess( if (dup2(iFdErr, STDERR_FILENO) == -1) { // Didn't duplicate standard error. - _exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } - + /* now close the original FDs, we don't need them anymore */ close(iFdIn); close(iFdOut); @@ -993,17 +990,17 @@ CorUnix::InternalCreateProcess( pLocalData->dwProcessId = processId; pLocalDataLock->ReleaseLock(pThread, TRUE); pLocalDataLock = NULL; - + pSharedData->dwProcessId = processId; pSharedDataLock->ReleaseLock(pThread, TRUE); pSharedDataLock = NULL; - // + // // Release file handle info; we don't need them anymore. Note that // this must happen after we've released the data locks, as // otherwise a deadlock could result. // - + if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) { pobjFileIn->ReleaseReference(pThread); @@ -1063,11 +1060,11 @@ CorUnix::InternalCreateProcess( InternalFree(EnvironmentArray); } - /* if we still have the file structures at this point, it means we - encountered an error sometime between when we acquired them and when we - fork()ed. We not only have to release them, we have to give them back + /* if we still have the file structures at this point, it means we + encountered an error sometime between when we acquired them and when we + fork()ed. We not only have to release them, we have to give them back their close-on-exec flag */ - if (NULL != pobjFileIn) + if (NULL != pobjFileIn) { if(-1 == fcntl(iFdIn, F_SETFD, 1)) { @@ -1076,8 +1073,8 @@ CorUnix::InternalCreateProcess( } pobjFileIn->ReleaseReference(pThread); } - - if (NULL != pobjFileOut) + + if (NULL != pobjFileOut) { if(-1 == fcntl(iFdOut, F_SETFD, 1)) { @@ -1086,8 +1083,8 @@ CorUnix::InternalCreateProcess( } pobjFileOut->ReleaseReference(pThread); } - - if (NULL != pobjFileErr) + + if (NULL != pobjFileErr) { if(-1 == fcntl(iFdErr, F_SETFD, 1)) { @@ -1144,7 +1141,7 @@ GetExitCodeProcess( &ps, &dwExitCode ); - + if (NO_ERROR != palError) { ASSERT("Couldn't get process status information!\n"); @@ -1166,10 +1163,10 @@ GetExitCodeProcess( { pThread->SetLastError(palError); } - + LOGEXIT("GetExitCodeProcess returns BOOL %d\n", NO_ERROR == palError); PERF_EXIT(GetExitCodeProcess); - + return NO_ERROR == palError; } @@ -1213,12 +1210,12 @@ ExitProcess( } else if (0 != old_terminator) { - /* another thread has already initiated the termination process. we - could just block on the PALInitLock critical section, but then + /* another thread has already initiated the termination process. we + could just block on the PALInitLock critical section, but then PROCSuspendOtherThreads would hang... so sleep forever here, we're - terminating anyway + terminating anyway - Update: [TODO] PROCSuspendOtherThreads has been removed. Can this + Update: [TODO] PROCSuspendOtherThreads has been removed. Can this code be changed? */ WARN("termination already started from another thread; blocking.\n"); poll(NULL, 0, INFTIM); @@ -1237,7 +1234,7 @@ ExitProcess( else { exit(uExitCode); - + /* Should not get here, because we terminate the current process */ ASSERT("exit has returned\n"); } @@ -1268,7 +1265,7 @@ TerminateProcess( ENTRY("TerminateProcess(hProcess=%p, uExitCode=%u)\n",hProcess, uExitCode ); ret = PROCEndProcess(hProcess, uExitCode, TRUE); - + LOGEXIT("TerminateProcess returns BOOL %d\n", ret); PERF_EXIT(TerminateProcess); return ret; @@ -1277,7 +1274,7 @@ TerminateProcess( /*++ Function: PROCEndProcess - + Called from TerminateProcess and ExitProcess. This does the work of TerminateProcess, but also takes a flag that determines whether we shut down unconditionally. If the flag is set, the PAL will do very @@ -1299,7 +1296,7 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon { if (uExitCode != 0) WARN("exit code 0x%x ignored for external process.\n", uExitCode); - + if (kill(dwProcessId, SIGKILL) == 0) { ret = TRUE; @@ -1336,7 +1333,7 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon } TerminateCurrentProcessNoExit(bTerminateUnconditionally); - + LOGEXIT("PROCEndProcess will not return\n"); // exit() runs atexit handlers possibly registered by foreign code. @@ -1344,22 +1341,22 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon // registered our own PAL_Terminate with atexit(), the latter will // explicitly re-enter us. PAL_Leave(PAL_BoundaryBottom); - + if (bTerminateUnconditionally) { - // abort() has the semantics that + // abort() has the semantics that // (1) it doesn't run atexit handlers // (2) can invoke CrashReporter or produce a coredump, // which is appropriate for TerminateProcess calls - + // If this turns out to be inappropriate for some case, where we // call TerminateProcess vs. ExitProcess, then there needs to be // a CLR wrapper for TerminateProcess and some exposure for PAL_abort() // to selectively use that in all but those cases. - + abort(); } - else + else exit(uExitCode); ASSERT(FALSE); // we shouldn't get here @@ -1368,30 +1365,10 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon return ret; } -/*++ -Function: - PAL_SetShutdownCallback - -Abstract: - Sets a callback that is executed when the PAL is shut down because of - ExitProcess, TerminateProcess or PAL_Shutdown but not PAL_Terminate/Ex. - - NOTE: Currently only one callback can be set at a time. ---*/ -PALIMPORT -VOID -PALAPI -PAL_SetShutdownCallback( - IN PSHUTDOWN_CALLBACK callback) -{ - _ASSERTE(g_shutdownCallback == nullptr); - g_shutdownCallback = callback; -} - /*++ Function: PROCCleanupProcess - + Do all cleanup work for TerminateProcess, but don't terminate the process. If bTerminateUnconditionally is TRUE, we exit as quickly as possible. @@ -1399,11 +1376,6 @@ PAL_SetShutdownCallback( --*/ void PROCCleanupProcess(BOOL bTerminateUnconditionally) { - if (g_shutdownCallback != nullptr) - { - g_shutdownCallback(); - } - /* Declare the beginning of shutdown */ PALSetShutdownIntent(); @@ -1450,7 +1422,7 @@ GetProcessTimes( goto GetProcessTimesExit; } - /* First, we need to actually retrieve the relevant statistics from the + /* First, we need to actually retrieve the relevant statistics from the OS */ if (getrusage (RUSAGE_SELF, &resUsage) == -1) { @@ -1459,7 +1431,7 @@ GetProcessTimes( SetLastError(ERROR_INTERNAL_ERROR); goto GetProcessTimesExit; } - + TRACE ("getrusage User: %ld sec,%ld microsec. Kernel: %ld sec,%ld" " microsec\n", resUsage.ru_utime.tv_sec, resUsage.ru_utime.tv_usec, @@ -1486,7 +1458,7 @@ GetProcessTimes( lpKernelTime->dwLowDateTime = (DWORD)calcTime; lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32); } - + retval = TRUE; @@ -1498,7 +1470,7 @@ GetProcessTimes( #define FILETIME_TO_ULONGLONG(f) \ (((ULONGLONG)(f).dwHighDateTime << 32) | ((ULONGLONG)(f).dwLowDateTime)) - + /*++ Function: PAL_GetCPUBusyTime @@ -1636,7 +1608,7 @@ GetCommandLineW( g_lpwstrCmdLine, lpwstr); PERF_EXIT(GetCommandLineW); - + return lpwstr; } @@ -1741,7 +1713,7 @@ OpenProcess( // // TODO: check to see if the process actually exists? // - + OpenProcessExit: if (NULL != pobjProcess) @@ -1775,10 +1747,10 @@ Return TRUE if it succeeded, FALSE otherwise Notes - This API is tricky because the module handles are never closed/freed so there can't be any - allocations for the module handle or name strings, etc. The "handles" are actually the base - addresses of the modules. The module handles should only be used by GetModuleFileNameExW - below. + This API is tricky because the module handles are never closed/freed so there can't be any + allocations for the module handle or name strings, etc. The "handles" are actually the base + addresses of the modules. The module handles should only be used by GetModuleFileNameExW + below. --*/ BOOL PALAPI @@ -1830,7 +1802,7 @@ EnumProcessModules( Function: GetModuleFileNameExW - Used only with module handles returned from EnumProcessModule (for dbgshim). + Used only with module handles returned from EnumProcessModule (for dbgshim). --*/ DWORD @@ -2015,7 +1987,7 @@ CreateProcessModules( #elif defined(HAVE_PROCFS_CTL) - // Here we read /proc//maps file in order to parse it and figure out what it says + // Here we read /proc//maps file in order to parse it and figure out what it says // about a library we are looking for. This file looks something like this: // // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file @@ -2030,14 +2002,14 @@ CreateProcessModules( // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so // Making something like: /proc/123/maps - char mapFileName[100]; + char mapFileName[100]; INDEBUG(int chars = ) snprintf(mapFileName, sizeof(mapFileName), "/proc/%d/maps", dwProcessId); _ASSERTE(chars > 0 && chars <= sizeof(mapFileName)); FILE *mapsFile = fopen(mapFileName, "r"); - if (mapsFile == NULL) + if (mapsFile == NULL) { SetLastError(ERROR_INVALID_HANDLE); return NULL; @@ -2048,8 +2020,8 @@ CreateProcessModules( int count = 0; ssize_t read; - // Reading maps file line by line - while ((read = getline(&line, &lineLen, mapsFile)) != -1) + // Reading maps file line by line + while ((read = getline(&line, &lineLen, mapsFile)) != -1) { void *startAddress, *endAddress, *offset; int devHi, devLo, inode; @@ -2186,14 +2158,14 @@ BOOL InitializeFlushProcessWriteBuffers() See MSDN doc. --*/ -VOID -PALAPI +VOID +PALAPI FlushProcessWriteBuffers() -{ +{ int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex); FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock"); - // Changing a helper memory page protection from read / write to no access + // Changing a helper memory page protection from read / write to no access // causes the OS to issue IPI to flush TLBs on all processors. This also // results in flushing the processor buffers. status = mprotect(s_helperPage, VIRTUAL_PAGE_SIZE, PROT_READ | PROT_WRITE); @@ -2230,7 +2202,7 @@ PROCGetProcessIDFromHandle( PAL_ERROR palError; IPalObject *pobjProcess = NULL; CPalThread *pThread = InternalGetCurrentThread(); - + DWORD dwProcessId = 0; if (hPseudoCurrentProcess == hProcess) @@ -2238,7 +2210,7 @@ PROCGetProcessIDFromHandle( dwProcessId = gPID; goto PROCGetProcessIDFromHandleExit; } - + palError = g_pObjectManager->ReferenceObjectByHandle( pThread, @@ -2264,8 +2236,8 @@ PROCGetProcessIDFromHandle( { dwProcessId = pLocalData->dwProcessId; pDataLock->ReleaseLock(pThread, FALSE); - } - + } + pobjProcess->ReleaseReference(pThread); } @@ -2281,7 +2253,7 @@ CorUnix::InitializeProcessData( { PAL_ERROR palError = NO_ERROR; bool fLockInitialized = FALSE; - + pGThreadList = NULL; g_dwThreadCount = 0; @@ -2309,7 +2281,7 @@ Abstract Parameter lpwstrCmdLine lpwstrFullPath - + Return PAL_ERROR @@ -2377,7 +2349,7 @@ Abstract Parameter pThread - the initial thread - + Return PAL_ERROR --*/ @@ -2415,7 +2387,7 @@ CorUnix::CreateInitialProcessAndThreadObjects( // // Create and initialize process object // - + palError = g_pObjectManager->AllocateObject( pThread, &otProcess, @@ -2431,7 +2403,7 @@ CorUnix::CreateInitialProcessAndThreadObjects( palError = pobjProcess->GetProcessLocalData( pThread, - WriteLock, + WriteLock, &pDataLock, reinterpret_cast(&pLocalData) ); @@ -2447,7 +2419,7 @@ CorUnix::CreateInitialProcessAndThreadObjects( pDataLock->ReleaseLock(pThread, TRUE); palError = pobjProcess->GetSharedData( - pThread, + pThread, WriteLock, &pDataLock, reinterpret_cast(&pSharedData) @@ -2522,10 +2494,10 @@ PROCCleanupInitialProcess(VOID) CPalThread *pThread = InternalGetCurrentThread(); InternalEnterCriticalSection(pThread, &g_csProcess); - + /* Free the application directory */ InternalFree(g_lpwstrAppDir); - + /* Free the stored command line */ InternalFree(g_lpwstrCmdLine); @@ -2535,7 +2507,7 @@ PROCCleanupInitialProcess(VOID) // Object manager shutdown will handle freeing the underlying // thread and process data // - + } /*++ @@ -2555,7 +2527,7 @@ CorUnix::PROCAddThread( CPalThread *pTargetThread ) { - /* protect the access of the thread list with critical section for + /* protect the access of the thread list with critical section for mutithreading access */ InternalEnterCriticalSection(pCurrentThread, &g_csProcess); @@ -2590,7 +2562,7 @@ CorUnix::PROCRemoveThread( { CPalThread *curThread, *prevThread; - /* protect the access of the thread list with critical section for + /* protect the access of the thread list with critical section for mutithreading access */ InternalEnterCriticalSection(pCurrentThread, &g_csProcess); @@ -2607,7 +2579,7 @@ CorUnix::PROCRemoveThread( if (curThread == pTargetThread) { pGThreadList = curThread->GetNext(); - TRACE("Thread 0x%p (id %#x) removed from the process thread list\n", + TRACE("Thread 0x%p (id %#x) removed from the process thread list\n", pTargetThread, pTargetThread->GetThreadId()); goto EXIT; } @@ -2675,7 +2647,7 @@ VOID PROCProcessLock( VOID) { - CPalThread * pThread = + CPalThread * pThread = (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL); InternalEnterCriticalSection(pThread, &g_csProcess); @@ -2699,10 +2671,10 @@ VOID PROCProcessUnlock( VOID) { - CPalThread * pThread = + CPalThread * pThread = (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL); - InternalLeaveCriticalSection(pThread, &g_csProcess); + InternalLeaveCriticalSection(pThread, &g_csProcess); } #if USE_SYSV_SEMAPHORES @@ -2733,7 +2705,7 @@ PROCCleanupThreadSemIds(void) } PROCProcessUnlock(); - + } #endif // USE_SYSV_SEMAPHORES @@ -2769,8 +2741,8 @@ CorUnix::TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally) could just block on the PALInitLock critical section, but then PROCSuspendOtherThreads would hang... so sleep forever here, we're terminating anyway - - Update: [TODO] PROCSuspendOtherThreads has been removed. Can this + + Update: [TODO] PROCSuspendOtherThreads has been removed. Can this code be changed? */ /* note that if *this* thread has already started the termination @@ -2828,10 +2800,10 @@ PROCGetProcessStatus( int status; // - // First, check if we already know the status of this process. This will be + // First, check if we already know the status of this process. This will be // the case if this function has already been called for the same process. // - + palError = g_pObjectManager->ReferenceObjectByHandle( pThread, hProcess, @@ -2839,7 +2811,7 @@ PROCGetProcessStatus( 0, &pobjProcess ); - + if (NO_ERROR != palError) { goto PROCGetProcessStatusExit; @@ -2851,23 +2823,23 @@ PROCGetProcessStatus( &pDataLock, reinterpret_cast(&pLocalData) ); - + if (PS_DONE == pLocalData->ps) { TRACE("We already called waitpid() on process ID %#x; process has " - "terminated, exit code is %d\n", + "terminated, exit code is %d\n", pLocalData->dwProcessId, pLocalData->dwExitCode); - + *pps = pLocalData->ps; *pdwExitCode = pLocalData->dwExitCode; pDataLock->ReleaseLock(pThread, FALSE); - + goto PROCGetProcessStatusExit; } - /* By using waitpid(), we can even retrieve the exit code of a non-PAL - process. However, note that waitpid() can only provide the low 8 bits + /* By using waitpid(), we can even retrieve the exit code of a non-PAL + process. However, note that waitpid() can only provide the low 8 bits of the exit code. This is all that is required for the PAL spec. */ TRACE("Looking for status of process; trying wait()"); @@ -2875,7 +2847,7 @@ PROCGetProcessStatus( { /* try to get state of process, using non-blocking call */ wait_retval = waitpid(pLocalData->dwProcessId, &status, WNOHANG); - + if ( wait_retval == (pid_t) pLocalData->dwProcessId ) { /* success; get the exit code */ @@ -2901,10 +2873,10 @@ PROCGetProcessStatus( } else if (-1 == wait_retval) { - // This might happen if waitpid() had already been called, but - // this shouldn't happen - we call waitpid once, store the + // This might happen if waitpid() had already been called, but + // this shouldn't happen - we call waitpid once, store the // result, and use that afterwards. - // One legitimate cause of failure is EINTR; if this happens we + // One legitimate cause of failure is EINTR; if this happens we // have to try again. A second legitimate cause is ECHILD, which // happens if we're trying to retrieve the status of a currently- // running process that isn't a child of this process. @@ -2942,7 +2914,7 @@ PROCGetProcessStatus( } else { - // Ignoring unexpected waitpid errno and assuming that + // Ignoring unexpected waitpid errno and assuming that // the process is still running ERROR("waitpid(pid=%u) failed with unexpected errno=%d (%s)\n", pLocalData->dwProcessId, errno, strerror(errno)); @@ -2966,10 +2938,10 @@ PROCGetProcessStatus( pLocalData->ps = PS_DONE; pLocalData->dwExitCode = *pdwExitCode; } - - TRACE( "State of process 0x%08x : %d (exit code %d)\n", + + TRACE( "State of process 0x%08x : %d (exit code %d)\n", pLocalData->dwProcessId, *pps, *pdwExitCode ); - + pDataLock->ReleaseLock(pThread, TRUE); PROCGetProcessStatusExit: @@ -2978,7 +2950,7 @@ PROCGetProcessStatus( { pobjProcess->ReleaseReference(pThread); } - + return palError; } @@ -3028,14 +3000,14 @@ void PROCDumpThreadList() while (NULL != pThread) { TRACE (" {pThr=0x%p tid=%#x lwpid=%#x state=%d finsusp=%d}\n", - pThread, (int)pThread->GetThreadId(), (int)pThread->GetLwpId(), + pThread, (int)pThread->GetThreadId(), (int)pThread->GetLwpId(), (int)pThread->synchronizationInfo.GetThreadState(), (int)pThread->suspensionInfo.GetSuspendedForShutdown()); pThread = pThread->GetNext(); } TRACE ("Threads:}\n"); - + PROCProcessUnlock(); } #endif @@ -3314,45 +3286,45 @@ isManagedExecutable(LPSTR lpFileName) HANDLE hFile = INVALID_HANDLE_VALUE; DWORD cbRead; IMAGE_DOS_HEADER dosheader; - IMAGE_NT_HEADERS32 NtHeaders; + IMAGE_NT_HEADERS32 NtHeaders; BOOL ret = 0; - /* then check if it is a PE/COFF file */ + /* then check if it is a PE/COFF file */ if((hFile = CreateFileA(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) == INVALID_HANDLE_VALUE) - { + { goto isManagedExecutableExit; } - - /* Open the file and read the IMAGE_DOS_HEADER structure */ + + /* Open the file and read the IMAGE_DOS_HEADER structure */ if(!ReadFile(hFile, &dosheader, sizeof(IMAGE_DOS_HEADER), &cbRead, NULL) || cbRead != sizeof(IMAGE_DOS_HEADER) ) goto isManagedExecutableExit; - + /* check the DOS headers */ - if ( (dosheader.e_magic != VAL16(IMAGE_DOS_SIGNATURE)) || (VAL32(dosheader.e_lfanew) <= 0) ) - goto isManagedExecutableExit; - + if ( (dosheader.e_magic != VAL16(IMAGE_DOS_SIGNATURE)) || (VAL32(dosheader.e_lfanew) <= 0) ) + goto isManagedExecutableExit; + /* Advance the file pointer to File address of new exe header */ if( SetFilePointer(hFile, VAL32(dosheader.e_lfanew), NULL, FILE_BEGIN) == 0xffffffff) goto isManagedExecutableExit; - + if( !ReadFile(hFile, &NtHeaders , sizeof(IMAGE_NT_HEADERS32), &cbRead, NULL) || cbRead != sizeof(IMAGE_NT_HEADERS32) ) goto isManagedExecutableExit; - - /* check the NT headers */ + + /* check the NT headers */ if ((NtHeaders.Signature != VAL32(IMAGE_NT_SIGNATURE)) || (NtHeaders.FileHeader.SizeOfOptionalHeader != VAL16(IMAGE_SIZEOF_NT_OPTIONAL32_HEADER)) || (NtHeaders.OptionalHeader.Magic != VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))) goto isManagedExecutableExit; - + /* Check that the virtual address of IMAGE_DIRECTORY_ENTRY_COMHEADER is non-null */ if ( NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress == 0 ) goto isManagedExecutableExit; - + /* The file is a managed executable */ ret = 1; - + isManagedExecutableExit: /* Close the file handle if we opened it */ if ( hFile != INVALID_HANDLE_VALUE ) @@ -3380,7 +3352,7 @@ isManagedExecutable(LPSTR lpFileName) static int checkFileType( char *lpFileName) -{ +{ struct stat stat_data; /* check if the file exist */ @@ -3388,7 +3360,7 @@ checkFileType( char *lpFileName) { return FILE_ERROR; } - + if( isManagedExecutable(lpFileName) ) { return FILE_PE; @@ -3435,17 +3407,17 @@ checkFileType( char *lpFileName) Return: the number of arguments -note: this doesn't yet match precisely the behavior of Windows, but should be +note: this doesn't yet match precisely the behavior of Windows, but should be sufficient. what's here: 1) stripping nonquoted whitespace -2) handling of quoted parameters and quoted "parts" of parameters, removal of +2) handling of quoted parameters and quoted "parts" of parameters, removal of doublequotes ( becomes ) 3) \" as an escaped doublequote, both within doublequoted sequences and out what's known missing : -1) \\ as an escaped backslash, but only if the string of '\' - is followed by a " (escaped or not) -2) "alternate" escape sequence : double-doublequote within a double-quoted +1) \\ as an escaped backslash, but only if the string of '\' + is followed by a " (escaped or not) +2) "alternate" escape sequence : double-doublequote within a double-quoted argument (<"aaa a""aa aaa">) expands to a single-doublequote() note that there may be other special cases --*/ @@ -3517,7 +3489,7 @@ buildArgv( /* let's skip the first argument in the command line */ - /* strip leading whitespace; function returns NULL if there's only + /* strip leading whitespace; function returns NULL if there's only whitespace, so the if statement below will work correctly */ lpCommandLine = UTIL_inverse_wcspbrk((LPWSTR)lpCommandLine, W16_WHITESPACE); @@ -3536,14 +3508,14 @@ buildArgv( } else if('"' == *lpCommandLine) { - /* got a dquote; skip over it if it's escaped; make sure we - don't try to look before the first character in the + /* got a dquote; skip over it if it's escaped; make sure we + don't try to look before the first character in the string */ if(lpCommandLine > stringstart && '\\' == lpCommandLine[-1]) { lpCommandLine++; continue; - } + } /* found beginning of dquoted sequence, run to the end */ /* don't stop if we hit an escaped dquote */ @@ -3560,9 +3532,9 @@ buildArgv( { /* dquote is not escaped, dquoted sequence is over*/ break; - } + } lpCommandLine++; - } + } if(NULL == lpCommandLine || '\0' == *lpCommandLine) { /* no terminating dquote */ @@ -3596,11 +3568,11 @@ buildArgv( pChar = lpAsciiCmdLine; - /* loops through all the arguments, to find out how many arguments there + /* loops through all the arguments, to find out how many arguments there are; while looping replace whitespace by \0 */ /* skip leading whitespace (and replace by '\0') */ - /* note : there shouldn't be any, command starts either with PE loader name + /* note : there shouldn't be any, command starts either with PE loader name or computed application path, but this won't hurt */ while (*pChar) { @@ -3621,14 +3593,14 @@ buildArgv( { if('"' == *pChar) { - /* skip over dquote if it's escaped; make sure we don't try to + /* skip over dquote if it's escaped; make sure we don't try to look before the start of the string for the \ */ if(pChar > lpAsciiCmdLine && '\\' == pChar[-1]) { pChar++; continue; } - + /* found leading dquote : look for ending dquote */ pChar++; while (*pChar) @@ -3636,17 +3608,17 @@ buildArgv( pChar = strchr(pChar,'"'); if(NULL == pChar) { - /* no ending dquote found : argument extends to the end + /* no ending dquote found : argument extends to the end of the string*/ break; } if('\\' != pChar[-1]) { - /* found a dquote, and it's not escaped : quoted + /* found a dquote, and it's not escaped : quoted sequence is over*/ break; - } - /* found a dquote, but it was escaped : skip over it, keep + } + /* found a dquote, but it was escaped : skip over it, keep looking */ pChar++; } @@ -3663,7 +3635,7 @@ buildArgv( /* reached the end of the string : we're done */ break; } - /* reached end of arg; replace trailing whitespace by '\0', to split + /* reached end of arg; replace trailing whitespace by '\0', to split arguments into separate strings */ while (isspace((unsigned char) *pChar)) { @@ -3684,7 +3656,7 @@ buildArgv( lppTemp = lppArgv; /* at this point all parameters are separated by NULL - we need to fill the array of arguments; we must also remove all dquotes + we need to fill the array of arguments; we must also remove all dquotes from arguments (new process shouldn't see them) */ for (i = *pnArg, pChar = lpAsciiCmdLine; i; i--) { @@ -3703,7 +3675,7 @@ buildArgv( /* copy character if it's not a dquote */ if('"' != *pChar) { - /* if it's the \ of an escaped dquote, skip over it, we'll + /* if it's the \ of an escaped dquote, skip over it, we'll copy the " instead */ if( '\\' == pChar[0] && '"' == pChar[1] ) { @@ -3771,7 +3743,7 @@ getPath( TRACE("file %s exists\n", lpFileName); return TRUE; - } + } else { TRACE("file %s doesn't exist.\n", lpFileName); @@ -3856,14 +3828,14 @@ getPath( { lpNext++; } - + /* search for ':' */ lpCurrent = strchr(lpNext, ':'); if (lpCurrent) { *lpCurrent++ = '\0'; } - + nextLen = strlen(lpNext); slashLen = (lpNext[nextLen-1] == '/') ? 0:1; @@ -3882,7 +3854,7 @@ getPath( { strcat_s (lpPathFileName, iLen, "/"); } - + strcat_s (lpPathFileName, iLen, lpFileName); if (access (lpPathFileName, F_OK) == 0) @@ -3904,7 +3876,7 @@ getPath( /*++ Function: PROCThreadFromMachPort - + Given a Mach thread port, return the CPalThread associated with it. Return @@ -3925,7 +3897,7 @@ CorUnix::CPalThread *PROCThreadFromMachPort(mach_port_t hTargetThread) pThread = pThread->GetNext(); } - + PROCProcessUnlock(); return pThread; @@ -3945,4 +3917,3 @@ CorUnix::CProcProcessLocalData::~CProcProcessLocalData() DestroyProcessModules(pProcessModules); } } - From 694b5e860b0d9cd9d74c196b1c891165546665bf Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Fri, 30 Dec 2016 15:27:57 +0100 Subject: [PATCH 02/13] android: fix memory status --- pal/src/configure.cmake | 6 +++--- pal/src/misc/sysinfo.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pal/src/configure.cmake b/pal/src/configure.cmake index 3523422a044..accd0aa4513 100644 --- a/pal/src/configure.cmake +++ b/pal/src/configure.cmake @@ -948,7 +948,7 @@ else() # ANDROID set(HAVE_FUTIMES 0) set(HAVE_UTIMES 1) set(HAVE_SYSCTL 0) - set(HAVE_SYSCONF 0) + set(HAVE_SYSCONF 1) set(HAVE_LOCALTIME_R 1) set(HAVE_GMTIME_R 1) set(HAVE_TIMEGM 1) @@ -974,8 +974,8 @@ else() # ANDROID set(HAVE_INFTIM 0) set(HAVE_CHAR_BIT 1) # -DUSER_H_DEFINES_DEBUG 1 - # -DHAVE__SC_PHYS_PAGES 1) - # -DHAVE__SC_AVPHYS_PAGES + set(HAVE__SC_PHYS_PAGES 1) + set(HAVE__SC_AVPHYS_PAGES 1) # -DREALPATH_SUPPORTS_NONEXISTENT_FILES # -DSSCANF_CANNOT_HANDLE_MISSING_EXPONENT # -DSSCANF_SUPPORT_ll diff --git a/pal/src/misc/sysinfo.cpp b/pal/src/misc/sysinfo.cpp index 5a259c250bd..a2fcf0e5ed5 100644 --- a/pal/src/misc/sysinfo.cpp +++ b/pal/src/misc/sysinfo.cpp @@ -269,7 +269,7 @@ GlobalMemoryStatusEx( if (lpBuffer->ullTotalPhys > 0) { #if defined(__ANDROID__) - lpBuffer->ullAvailPhys = lpBuffer->ullTotalPhys; // xplat-todo: fix this + lpBuffer->ullAvailPhys = sysconf(_SC_AVPHYS_PAGES) * sysconf( _SC_PAGE_SIZE ); INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys; lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys); #elif defined(__LINUX__) From fe0d176642cf327f04fc44e474d023a61187cc43 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Fri, 30 Dec 2016 16:18:56 +0100 Subject: [PATCH 03/13] android: fix cs native data size for ARMv7 Android --- pal/inc/pal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pal/inc/pal.h b/pal/inc/pal.h index 07580abefe9..38fd9f177c3 100644 --- a/pal/inc/pal.h +++ b/pal/inc/pal.h @@ -3196,6 +3196,8 @@ PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, #define PAL_CS_NATIVE_DATA_SIZE 56 #elif defined(__LINUX__) && defined(__x86_64__) #define PAL_CS_NATIVE_DATA_SIZE 96 +#elif defined(__ANDROID__) && defined(_ARM_) +#define PAL_CS_NATIVE_DATA_SIZE 12 #elif defined(__LINUX__) && defined(_ARM_) #define PAL_CS_NATIVE_DATA_SIZE 80 #elif defined(__LINUX__) && defined(_ARM64_) From a167b473235f22b87238467df61935a160f1676f Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Fri, 30 Dec 2016 16:21:16 +0100 Subject: [PATCH 04/13] fix: set isLowMemoryDevice for Android and iOS --- lib/Common/Core/SysInfo.cpp | 4 ++++ lib/Common/Memory/RecyclerHeuristic.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/lib/Common/Core/SysInfo.cpp b/lib/Common/Core/SysInfo.cpp index 91c4df449b0..c324f74a8b4 100644 --- a/lib/Common/Core/SysInfo.cpp +++ b/lib/Common/Core/SysInfo.cpp @@ -111,7 +111,11 @@ AutoSystemInfo::Initialize() this->shouldQCMoreFrequently = false; this->supportsOnlyMultiThreadedCOM = false; +#if defined(__ANDROID__) || defined(__IOS__) + this->isLowMemoryDevice = true; +#else this->isLowMemoryDevice = false; +#endif // 0 indicates we haven't retrieved the available commit. We get it lazily. this->availableCommit = 0; diff --git a/lib/Common/Memory/RecyclerHeuristic.cpp b/lib/Common/Memory/RecyclerHeuristic.cpp index 47b481e05d5..a992b2f0b0d 100644 --- a/lib/Common/Memory/RecyclerHeuristic.cpp +++ b/lib/Common/Memory/RecyclerHeuristic.cpp @@ -32,6 +32,8 @@ RecyclerHeuristic::RecyclerHeuristic() DWORDLONG physicalMemoryBytes = mem.ullTotalPhys; uint baseFactor; + // xplat-todo: Android sysconf is rather unreliable, + // ullTotalPhys may not be the best source for a decision below if (isSuccess && AutoSystemInfo::IsLowMemoryDevice() && physicalMemoryBytes <= 512 MEGABYTES) { // Low-end Apollo (512MB RAM) scenario. From 9eefb7018c0b05169a497f3b7abbd84960999426 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 01:11:07 +0100 Subject: [PATCH 05/13] explicitly set O0 for debug builds to prevent custom default option optimizing the symbols away --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c21df49c06..cf48ee9e50b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,6 +312,8 @@ endif(CMAKE_BUILD_TYPE STREQUAL Debug) if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) add_compile_options(-O3) +else() + add_compile_options(-O0) endif(NOT CMAKE_BUILD_TYPE STREQUAL Debug) if(IS_64BIT_BUILD) From eefe40b60cd8f8f6bf2199df76769ee5bf2e4086 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 01:12:20 +0100 Subject: [PATCH 06/13] pal: fix missing semicolon issue with PAL Trace - ERROR command --- pal/src/file/pal_path.cpp | 190 +++++++++++++++++++------------------- pal/src/map/virtual.cpp | 2 +- pal/src/synchmgr/wait.cpp | 159 ++++++++++++++++--------------- 3 files changed, 175 insertions(+), 176 deletions(-) diff --git a/pal/src/file/pal_path.cpp b/pal/src/file/pal_path.cpp index bfaa5b3d3c7..c65bc4ef643 100644 --- a/pal/src/file/pal_path.cpp +++ b/pal/src/file/pal_path.cpp @@ -1,6 +1,6 @@ // // Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. // /*++ @@ -91,14 +91,14 @@ GetFullPathNameA( SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; } - } + } else { size_t max_len; /* allocate memory for full non-canonical path */ max_len = strlen(lpFileName)+1; /* 1 for the slash to append */ - max_len += MAX_LONGPATH + 1; + max_len += MAX_LONGPATH + 1; lpUnixPath = (LPSTR)PAL_malloc(max_len); if(NULL == lpUnixPath) { @@ -107,7 +107,7 @@ GetFullPathNameA( SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto done; } - + /* build full path */ if(!GetCurrentDirectoryA(MAX_LONGPATH + 1, lpUnixPath)) { @@ -117,7 +117,7 @@ GetFullPathNameA( SetLastError(ERROR_INTERNAL_ERROR); goto done; } - + if (strcat_s(lpUnixPath, max_len, "/") != SAFECRT_SUCCESS) { ERROR("strcat_s failed!\n"); @@ -135,7 +135,7 @@ GetFullPathNameA( /* do conversion to Unix path */ FILEDosToUnixPathA( lpUnixPath ); - + /* now we can canonicalize this */ FILECanonicalizePath(lpUnixPath); @@ -165,9 +165,9 @@ GetFullPathNameA( nRet = 0; goto done; } - else + else { - (*lpFilePart)++; + (*lpFilePart)++; } } @@ -209,14 +209,14 @@ GetFullPathNameW( ENTRY("GetFullPathNameW(lpFileName=%p (%S), nBufferLength=%u, lpBuffer=%p" ", lpFilePart=%p)\n", lpFileName?lpFileName:W16_NULLSTRING, - lpFileName?lpFileName:W16_NULLSTRING, nBufferLength, + lpFileName?lpFileName:W16_NULLSTRING, nBufferLength, lpBuffer, lpFilePart); /* Find the number of bytes required to convert lpFileName to ANSI. This may be more than MAX_LONGPATH. We try to handle that case, since it may be less than MAX_LONGPATH WCHARs. */ - + fileNameLength = WideCharToMultiByte(CP_ACP, 0, lpFileName, -1, NULL, 0, NULL, NULL); if (fileNameLength == 0) @@ -229,9 +229,9 @@ GetFullPathNameW( { fileNameA = static_cast(alloca(fileNameLength)); } - + /* Now convert lpFileName to ANSI. */ - srcSize = WideCharToMultiByte (CP_ACP, 0, lpFileName, + srcSize = WideCharToMultiByte (CP_ACP, 0, lpFileName, -1, fileNameA, fileNameLength, NULL, NULL ); if( srcSize == 0 ) @@ -248,7 +248,7 @@ GetFullPathNameW( SetLastError(ERROR_INVALID_PARAMETER); goto done; } - + bufferASize = MAX_LONGPATH * MaxWCharToAcpLengthRatio; bufferA = bufferAPS.OpenStringBuffer(bufferASize); if (NULL == bufferA) @@ -258,14 +258,14 @@ GetFullPathNameW( } length = GetFullPathNameA(fileNameA, bufferASize, bufferA, &lpFilePartA); bufferAPS.CloseBuffer(length); - + if (length == 0 || length > bufferASize) { /* Last error is set by GetFullPathNameA */ nRet = length; goto done; } - + /* Convert back to Unicode the result */ nRet = MultiByteToWideChar( CP_ACP, 0, bufferA, -1, lpBuffer, nBufferLength ); @@ -309,7 +309,7 @@ GetFullPathNameW( See MSDN doc. Note: - Since short path names are not implemented (nor supported) in the PAL, + Since short path names are not implemented (nor supported) in the PAL, this function simply copies the given path into the new buffer. --*/ @@ -328,7 +328,7 @@ GetLongPathNameW( if ( !lpszShortPath ) { - ERROR( "lpszShortPath was not a valid pointer.\n" ) + ERROR( "lpszShortPath was not a valid pointer.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); LOGEXIT("GetLongPathNameW returns DWORD 0\n"); PERF_EXIT(GetLongPathNameW); @@ -337,7 +337,7 @@ GetLongPathNameW( else if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( lpszShortPath )) { // last error has been set by GetFileAttributes - ERROR( "lpszShortPath does not exist.\n" ) + ERROR( "lpszShortPath does not exist.\n" ); LOGEXIT("GetLongPathNameW returns DWORD 0\n"); PERF_EXIT(GetLongPathNameW); return 0; @@ -354,7 +354,7 @@ GetLongPathNameW( { ERROR("Buffer is too small, need %d characters\n", dwPathLen); SetLastError( ERROR_INSUFFICIENT_BUFFER ); - } else + } else { if ( lpszShortPath != lpszLongPath ) { @@ -381,7 +381,7 @@ GetLongPathNameW( See MSDN doc. Note: - Since short path names are not implemented (nor supported) in the PAL, + Since short path names are not implemented (nor supported) in the PAL, this function simply copies the given path into the new buffer. --*/ @@ -400,7 +400,7 @@ GetShortPathNameW( if ( !lpszLongPath ) { - ERROR( "lpszLongPath was not a valid pointer.\n" ) + ERROR( "lpszLongPath was not a valid pointer.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); LOGEXIT("GetShortPathNameW returns DWORD 0\n"); PERF_EXIT(GetShortPathNameW); @@ -409,7 +409,7 @@ GetShortPathNameW( else if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( lpszLongPath )) { // last error has been set by GetFileAttributes - ERROR( "lpszLongPath does not exist.\n" ) + ERROR( "lpszLongPath does not exist.\n" ); LOGEXIT("GetShortPathNameW returns DWORD 0\n"); PERF_EXIT(GetShortPathNameW); return 0; @@ -426,7 +426,7 @@ GetShortPathNameW( { ERROR("Buffer is too small, need %d characters\n", dwPathLen); SetLastError( ERROR_INSUFFICIENT_BUFFER ); - } else + } else { if ( lpszLongPath != lpszShortPath ) { @@ -478,7 +478,7 @@ GetTempPathA( if ( !lpBuffer ) { - ERROR( "lpBuffer was not a valid pointer.\n" ) + ERROR( "lpBuffer was not a valid pointer.\n" ); SetLastError( ERROR_INVALID_PARAMETER ); LOGEXIT("GetTempPathA returns DWORD %u\n", dwPathLen); PERF_EXIT(GetTempPathA); @@ -489,7 +489,7 @@ GetTempPathA( dwPathLen = GetEnvironmentVariableA("TMPDIR", lpBuffer, nBufferLength); if (dwPathLen > 0) { - /* The env var existed. dwPathLen will be the length without null termination + /* The env var existed. dwPathLen will be the length without null termination * if the entire value was successfully retrieved, or it'll be the length * required to store the value with null termination. */ @@ -498,7 +498,7 @@ GetTempPathA( /* The environment variable fit in the buffer. Make sure it ends with '/'. */ if (lpBuffer[dwPathLen - 1] != '/') { - /* If adding the slash would still fit in our provided buffer, do it. Otherwise, + /* If adding the slash would still fit in our provided buffer, do it. Otherwise, * let the caller know how much space would be needed. */ if (dwPathLen + 2 <= nBufferLength) @@ -517,7 +517,7 @@ GetTempPathA( /* The value is too long for the supplied buffer. dwPathLen will now be the * length required to hold the value, but we don't know whether that value * is going to be '/' terminated. Since we'll need enough space for the '/', and since - * a caller would assume that the dwPathLen we return will be sufficient, + * a caller would assume that the dwPathLen we return will be sufficient, * we make sure to account for it in dwPathLen even if that means we end up saying * one more byte of space is needed than actually is. */ @@ -571,7 +571,7 @@ GetTempPathW( if (!lpBuffer) { - ERROR("lpBuffer was not a valid pointer.\n") + ERROR("lpBuffer was not a valid pointer.\n"); SetLastError(ERROR_INVALID_PARAMETER); LOGEXIT("GetTempPathW returns DWORD 0\n"); PERF_EXIT(GetTempPathW); @@ -580,17 +580,17 @@ GetTempPathW( char TempBuffer[nBufferLength > 0 ? nBufferLength : 1]; DWORD dwRetVal = GetTempPathA( nBufferLength, TempBuffer ); - + if ( dwRetVal >= nBufferLength ) { - ERROR( "lpBuffer was not large enough.\n" ) + ERROR( "lpBuffer was not large enough.\n" ); SetLastError( ERROR_INSUFFICIENT_BUFFER ); *lpBuffer = '\0'; } else if ( dwRetVal != 0 ) { /* Convert to wide. */ - if ( 0 == MultiByteToWideChar( CP_ACP, 0, TempBuffer, -1, + if ( 0 == MultiByteToWideChar( CP_ACP, 0, TempBuffer, -1, lpBuffer, dwRetVal + 1 ) ) { ASSERT( "An error occurred while converting the string to wide.\n" ); @@ -716,7 +716,7 @@ FILEDosToUnixPathA( Truncate at pPointAtDot, unless the dots are path specifiers (. or ..) */ if (pPointAtDot) { - /* make sure the trailing dots don't follow a '/', and that they aren't + /* make sure the trailing dots don't follow a '/', and that they aren't the only thing in the name */ if(pPointAtDot != lpPath && *(pPointAtDot-1) != '/') { @@ -754,7 +754,7 @@ FILEDosToUnixPathW( if (!lpPath) { return; - } + } for (p = lpPath; *p; p++) { @@ -833,7 +833,7 @@ FILEDosToUnixPathW( Truncate at pPointAtDot, unless the dots are path specifiers (. or ..) */ if (pPointAtDot) { - /* make sure the trailing dots don't follow a '/', and that they aren't + /* make sure the trailing dots don't follow a '/', and that they aren't the only thing in the name */ if(pPointAtDot != lpPath && *(pPointAtDot-1) != '/') { @@ -948,18 +948,18 @@ LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath ) /*++ FILECanonicalizePath - Removes all instances of '/./', '/../' and '//' from an absolute path. - + Removes all instances of '/./', '/../' and '//' from an absolute path. + Parameters: LPSTR lpUnixPath : absolute path to modify, in Unix format -(no return value) - +(no return value) + Notes : -behavior is undefined if path is not absolute --the order of steps *is* important: /one/./../two would give /one/two +-the order of steps *is* important: /one/./../two would give /one/two instead of /two if step 3 was done before step 2 --reason for this function is that GetFullPathName can't use realpath(), since +-reason for this function is that GetFullPathName can't use realpath(), since realpath() requires the given path to be valid and GetFullPathName does not. --*/ void FILECanonicalizePath(LPSTR lpUnixPath) @@ -1016,14 +1016,14 @@ void FILECanonicalizePath(LPSTR lpUnixPath) memmove(lpUnixPath, lpUnixPath+3,strlen(lpUnixPath+3)+1); continue; } - - /* null-terminate the string before the '/../', so that strrchr will + + /* null-terminate the string before the '/../', so that strrchr will start looking right before it */ *dotdotptr = '\0'; slashptr = strrchr(lpUnixPath,'/'); if(NULL == slashptr) { - /* this happens if this function was called with a relative path. + /* this happens if this function was called with a relative path. don't do that. */ ASSERT("can't find leading '/' before '/../ sequence\n"); break; @@ -1053,7 +1053,7 @@ void FILECanonicalizePath(LPSTR lpUnixPath) } else { - *slashptr = '\0'; + *slashptr = '\0'; } } } @@ -1116,11 +1116,11 @@ SearchPathA( ENTRY("SearchPathA(lpPath=%p (%s), lpFileName=%p (%s), lpExtension=%p, " "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n", lpPath, - lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, + lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); /* validate parameters */ - + if(NULL == lpPath) { ASSERT("lpPath may not be NULL\n"); @@ -1142,7 +1142,7 @@ SearchPathA( FileNameLength = strlen(lpFileName); - /* special case : if file name contains absolute path, don't search the + /* special case : if file name contains absolute path, don't search the provided path */ if('\\' == lpFileName[0] || '/' == lpFileName[0]) { @@ -1162,7 +1162,7 @@ SearchPathA( } dw = GetFullPathNameA(lpFileName, length+1, CanonicalFullPath, NULL); CanonicalFullPathPS.CloseBuffer(dw); - + if (length+1 < dw) { CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(dw-1); @@ -1176,7 +1176,7 @@ SearchPathA( CanonicalFullPathPS.CloseBuffer(dw); } - if (dw == 0) + if (dw == 0) { WARN("couldn't canonicalize path <%s>, error is %#x. failing.\n", lpFileName, GetLastError()); @@ -1194,13 +1194,13 @@ SearchPathA( else { LPCSTR pNextPath; - + pNextPath = lpPath; - - while (*pNextPath) + + while (*pNextPath) { pPathStart = pNextPath; - + /* get a pointer to the end of the first path in pPathStart */ pPathEnd = strchr(pPathStart, ':'); if (!pPathEnd) @@ -1215,13 +1215,13 @@ SearchPathA( /* point to the next component in the path string */ pNextPath = pPathEnd+1; } - + PathLength = pPathEnd-pPathStart; - - if (PathLength+FileNameLength+1 >= MAX_LONGPATH) + + if (PathLength+FileNameLength+1 >= MAX_LONGPATH) { /* The path+'/'+file length is too long. Skip it. */ - WARN("path component %.*s is too long, skipping it\n", + WARN("path component %.*s is too long, skipping it\n", (int)PathLength, pPathStart); continue; } @@ -1230,8 +1230,8 @@ SearchPathA( /* empty component : there were 2 consecutive ':' */ continue; } - - /* Construct a pathname by concatenating one path from lpPath, '/' + + /* Construct a pathname by concatenating one path from lpPath, '/' and lpFileName */ FullPathLength = PathLength + FileNameLength; FullPath = FullPathPS.OpenStringBuffer(FullPathLength+1); @@ -1250,7 +1250,7 @@ SearchPathA( goto done; } - FullPathPS.CloseBuffer(FullPathLength+1); + FullPathPS.CloseBuffer(FullPathLength+1); /* Canonicalize the path to deal with back-to-back '/', etc. */ length = MAX_LONGPATH; CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(length); @@ -1262,7 +1262,7 @@ SearchPathA( dw = GetFullPathNameA(FullPath, length+1, CanonicalFullPath, NULL); CanonicalFullPathPS.CloseBuffer(dw); - + if (length+1 < dw) { CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(dw-1); @@ -1270,15 +1270,15 @@ SearchPathA( CanonicalFullPath, NULL); CanonicalFullPathPS.CloseBuffer(dw); } - - if (dw == 0) + + if (dw == 0) { /* Call failed - possibly low memory. Skip the path */ WARN("couldn't canonicalize path <%s>, error is %#x. " "skipping it\n", FullPath, GetLastError()); continue; } - + /* see if the file exists */ if(0 == access(CanonicalFullPath, F_OK)) { @@ -1289,7 +1289,7 @@ SearchPathA( } } - if (nRet == 0) + if (nRet == 0) { /* file not found anywhere; say so. in Windows, this always seems to say FILE_NOT_FOUND, even if path doesn't exist */ @@ -1297,7 +1297,7 @@ SearchPathA( } else { - if (nRet < nBufferLength) + if (nRet < nBufferLength) { if(NULL == lpBuffer) { @@ -1308,7 +1308,7 @@ SearchPathA( nRet = 0; goto done; } - + if (strcpy_s(lpBuffer, nBufferLength, CanonicalFullPath) != SAFECRT_SUCCESS) { ERROR("strcpy_s failed!\n"); @@ -1333,7 +1333,7 @@ SearchPathA( } else { - /* if buffer is too small, report required length, including + /* if buffer is too small, report required length, including terminating null */ nRet++; } @@ -1389,11 +1389,11 @@ SearchPathW( ENTRY("SearchPathW(lpPath=%p (%S), lpFileName=%p (%S), lpExtension=%p, " "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n", lpPath, - lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, + lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart); /* validate parameters */ - + if(NULL == lpPath) { ASSERT("lpPath may not be NULL\n"); @@ -1411,9 +1411,9 @@ SearchPathW( ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension); SetLastError(ERROR_INVALID_PARAMETER); goto done; - } + } - /* special case : if file name contains absolute path, don't search the + /* special case : if file name contains absolute path, don't search the provided path */ if('\\' == lpFileName[0] || '/' == lpFileName[0]) { @@ -1438,8 +1438,8 @@ SearchPathW( dw = GetFullPathNameW(lpFileName, dw, CanonicalPath, NULL); CanonicalPathPS.CloseBuffer(dw); } - - if (dw == 0) + + if (dw == 0) { WARN("couldn't canonicalize path <%S>, error is %#x. failing.\n", lpPath, GetLastError()); @@ -1458,7 +1458,7 @@ SearchPathW( canonical_size = WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, CanonicalPathLength, NULL, NULL); AnsiPathPS.CloseBuffer(canonical_size); - + if(0 == access(AnsiPath, F_OK)) { /* found it */ @@ -1470,13 +1470,13 @@ SearchPathW( LPCWSTR pNextPath; pNextPath = lpPath; - + FileNameLength = PAL_wcslen(lpFileName); - while (*pNextPath) + while (*pNextPath) { pPathStart = pNextPath; - + /* get a pointer to the end of the first path in pPathStart */ pPathEnd = PAL_wcschr(pPathStart, ':'); if (!pPathEnd) @@ -1491,13 +1491,13 @@ SearchPathW( /* point to the next component in the path string */ pNextPath = pPathEnd+1; } - + PathLength = pPathEnd-pPathStart; - - if (PathLength+FileNameLength+1 >= MAX_LONGPATH) + + if (PathLength+FileNameLength+1 >= MAX_LONGPATH) { /* The path+'/'+file length is too long. Skip it. */ - WARN("path component %.*S is too long, skipping it\n", + WARN("path component %.*S is too long, skipping it\n", (int)PathLength, pPathStart); continue; } @@ -1506,8 +1506,8 @@ SearchPathW( /* empty component : there were 2 consecutive ':' */ continue; } - - /* Construct a pathname by concatenating one path from lpPath, '/' + + /* Construct a pathname by concatenating one path from lpPath, '/' and lpFileName */ FullPathLength = PathLength + FileNameLength; FullPath = FullPathPS.OpenStringBuffer(FullPathLength+1); @@ -1519,9 +1519,9 @@ SearchPathW( memcpy(FullPath, pPathStart, PathLength*sizeof(WCHAR)); FullPath[PathLength] = '/'; PAL_wcscpy(&FullPath[PathLength+1], lpFileName); - + FullPathPS.CloseBuffer(FullPathLength+1); - + /* Canonicalize the path to deal with back-to-back '/', etc. */ length = MAX_LONGPATH; CanonicalPath = CanonicalPathPS.OpenStringBuffer(length); @@ -1533,7 +1533,7 @@ SearchPathW( dw = GetFullPathNameW(FullPath, length+1, CanonicalPath, NULL); CanonicalPathPS.CloseBuffer(dw); - + if (length+1 < dw) { CanonicalPath = CanonicalPathPS.OpenStringBuffer(dw-1); @@ -1545,15 +1545,15 @@ SearchPathW( dw = GetFullPathNameW(FullPath, dw, CanonicalPath, NULL); CanonicalPathPS.CloseBuffer(dw); } - - if (dw == 0) + + if (dw == 0) { /* Call failed - possibly low memory. Skip the path */ WARN("couldn't canonicalize path <%S>, error is %#x. " "skipping it\n", FullPath, GetLastError()); continue; } - + /* see if the file exists */ CanonicalPathLength = (PAL_wcslen(CanonicalPath)+1) * MaxWCharToAcpLengthRatio; AnsiPath = AnsiPathPS.OpenStringBuffer(CanonicalPathLength); @@ -1565,7 +1565,7 @@ SearchPathW( canonical_size = WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1, AnsiPath, CanonicalPathLength, NULL, NULL); AnsiPathPS.CloseBuffer(canonical_size); - + if(0 == access(AnsiPath, F_OK)) { /* found it */ @@ -1575,7 +1575,7 @@ SearchPathW( } } - if (nRet == 0) + if (nRet == 0) { /* file not found anywhere; say so. in Windows, this always seems to say FILE_NOT_FOUND, even if path doesn't exist */ @@ -1583,7 +1583,7 @@ SearchPathW( } else { - /* find out the required buffer size, copy path to buffer if it's + /* find out the required buffer size, copy path to buffer if it's large enough */ nRet = PAL_wcslen(CanonicalPath)+1; if(nRet <= nBufferLength) @@ -1599,10 +1599,10 @@ SearchPathW( } PAL_wcscpy(lpBuffer, CanonicalPath); - /* don't include the null-terminator in the count if buffer was + /* don't include the null-terminator in the count if buffer was large enough */ nRet--; - + if(NULL != lpFilePart) { *lpFilePart = PAL_wcsrchr(lpBuffer, '/'); diff --git a/pal/src/map/virtual.cpp b/pal/src/map/virtual.cpp index ac360ea64f7..723647e0041 100644 --- a/pal/src/map/virtual.cpp +++ b/pal/src/map/virtual.cpp @@ -2016,7 +2016,7 @@ VirtualProtect( if ( !VIRTUALIsPageCommitted( Index, pEntry ) ) { ERROR( "You can only change the protection attributes" - " on committed memory.\n" ) + " on committed memory.\n" ); SetLastError( ERROR_INVALID_ADDRESS ); goto ExitVirtualProtect; } diff --git a/pal/src/synchmgr/wait.cpp b/pal/src/synchmgr/wait.cpp index 4b6a967e1d2..aa27812ed27 100644 --- a/pal/src/synchmgr/wait.cpp +++ b/pal/src/synchmgr/wait.cpp @@ -1,6 +1,6 @@ // // Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. // /*++ @@ -33,16 +33,16 @@ SET_DEFAULT_DEBUG_CHANNEL(SYNC); using namespace CorUnix; -static PalObjectTypeId sg_rgWaitObjectsIds[] = - { +static PalObjectTypeId sg_rgWaitObjectsIds[] = + { otiAutoResetEvent, otiManualResetEvent, otiMutex, - otiSemaphore, + otiSemaphore, otiProcess, otiThread }; -static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, +static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds, sizeof(sg_rgWaitObjectsIds)/sizeof(sg_rgWaitObjectsIds[0])); /*++ @@ -125,7 +125,7 @@ WaitForMultipleObjects(IN DWORD nCount, CPalThread * pThread = InternalGetCurrentThread(); - dwRet = InternalWaitForMultipleObjectsEx(pThread, nCount, lpHandles, + dwRet = InternalWaitForMultipleObjectsEx(pThread, nCount, lpHandles, bWaitAll, dwMilliseconds, FALSE); LOGEXIT("WaitForMultipleObjects returns DWORD %u\n", dwRet); @@ -183,7 +183,7 @@ Sleep(IN DWORD dwMilliseconds) if (NO_ERROR != palErr) { - ERROR("Sleep(dwMilliseconds=%u) failed [error=%u]\n", + ERROR("Sleep(dwMilliseconds=%u) failed [error=%u]\n", dwMilliseconds, palErr); pThread->SetLastError(palErr); } @@ -206,7 +206,7 @@ SleepEx(IN DWORD dwMilliseconds, { DWORD dwRet; - PERF_ENTRY(SleepEx); + PERF_ENTRY(SleepEx); ENTRY("SleepEx(dwMilliseconds=%u, bAlertable=%d)\n", dwMilliseconds, bAlertable); CPalThread * pThread = InternalGetCurrentThread(); @@ -231,7 +231,7 @@ QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) -{ +{ CPalThread * pCurrentThread = NULL; CPalThread * pTargetThread = NULL; IPalObject * pTargetThreadObject = NULL; @@ -239,12 +239,12 @@ QueueUserAPC( DWORD dwRet; PERF_ENTRY(QueueUserAPC); - ENTRY("QueueUserAPC(pfnAPC=%p, hThread=%p, dwData=%#x)\n", + ENTRY("QueueUserAPC(pfnAPC=%p, hThread=%p, dwData=%#x)\n", pfnAPC, hThread, dwData); - - /* NOTE: Windows does not check the validity of pfnAPC, even if it is - NULL. It just does an access violation later on when the APC call - is attempted */ + + /* NOTE: Windows does not check the validity of pfnAPC, even if it is + NULL. It just does an access violation later on when the APC call + is attempted */ pCurrentThread = InternalGetCurrentThread(); @@ -258,14 +258,14 @@ QueueUserAPC( if (NO_ERROR != palErr) { - ERROR("Unable to obtain thread data for handle %p (error %x)!\n", + ERROR("Unable to obtain thread data for handle %p (error %x)!\n", hThread, palErr); goto QueueUserAPC_exit; } - - palErr = g_pSynchronizationManager->QueueUserAPC(pCurrentThread, pTargetThread, - pfnAPC, dwData); + + palErr = g_pSynchronizationManager->QueueUserAPC(pCurrentThread, pTargetThread, + pfnAPC, dwData); QueueUserAPC_exit: if (pTargetThreadObject) @@ -274,7 +274,7 @@ QueueUserAPC( } dwRet = (NO_ERROR == palErr) ? 1 : 0; - + LOGEXIT("QueueUserAPC returns DWORD %d\n", dwRet); PERF_EXIT(QueueUserAPC); return dwRet; @@ -291,7 +291,7 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( DWORD dwRet = WAIT_FAILED; PAL_ERROR palErr = NO_ERROR; int i, iSignaledObjCount, iSignaledObjIndex = -1; - bool fWAll = (bool)bWaitAll, fNeedToBlock = false; + bool fWAll = (bool)bWaitAll, fNeedToBlock = false; bool fAbandoned = false; WaitType wtWaitType; @@ -299,22 +299,22 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( ISynchWaitController * pISyncStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL }; IPalObject ** ppIPalObjs = pIPalObjStackArray; ISynchWaitController ** ppISyncWaitCtrlrs = pISyncStackArray; - + if ((nCount == 0) || (nCount > MAXIMUM_WAIT_OBJECTS)) { ppIPalObjs = NULL; // make delete at the end safe - ppISyncWaitCtrlrs = NULL; // make delete at the end safe - ERROR("Invalid object count=%d [range: 1 to %d]\n", - nCount, MAXIMUM_WAIT_OBJECTS) + ppISyncWaitCtrlrs = NULL; // make delete at the end safe + ERROR("Invalid object count=%d [range: 1 to %d]\n", + nCount, MAXIMUM_WAIT_OBJECTS); pThread->SetLastError(ERROR_INVALID_PARAMETER); goto WFMOExIntExit; } else if (nCount == 1) { fWAll = false; // makes no difference when nCount is 1 - wtWaitType = SingleObject; + wtWaitType = SingleObject; } - else + else { wtWaitType = fWAll ? MultipleObjectsWaitAll : MultipleObjectsWaitOne; if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE) @@ -329,9 +329,9 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( } } } - + palErr = g_pObjectManager->ReferenceMultipleObjectsByHandleArray(pThread, - (VOID **)lpHandles, + (VOID **)lpHandles, nCount, &sg_aotWaitObject, SYNCHRONIZE, @@ -368,7 +368,7 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( } palErr = g_pSynchronizationManager->GetSynchWaitControllersForObjects( - pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs); + pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs); if (NO_ERROR != palErr) { ERROR("Unable to obtain ISynchWaitController interface for some or all " @@ -378,14 +378,14 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( } if (bAlertable) - { + { // First check for pending APC. We need to do that while holding the global // synch lock implicitely grabbed by GetSynchWaitControllersForObjects if (g_pSynchronizationManager->AreAPCsPending(pThread)) { // If there is any pending APC we need to release the // implicit global synch lock before calling into it - for (i = 0; (i < (int)nCount) && (NULL != ppISyncWaitCtrlrs[i]); i++) + for (i = 0; (i < (int)nCount) && (NULL != ppISyncWaitCtrlrs[i]); i++) { ppISyncWaitCtrlrs[i]->ReleaseController(); ppISyncWaitCtrlrs[i] = NULL; @@ -403,8 +403,8 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( } goto WFMOExIntCleanup; } - } - + } + iSignaledObjCount = 0; iSignaledObjIndex = -1; for (i=0;i<(int)nCount;i++) @@ -416,7 +416,7 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( ERROR("ISynchWaitController::CanThreadWaitWithoutBlocking() failed for " "%d-th object [handle=%p error=%u]\n", i, lpHandles[i], palErr); pThread->SetLastError(ERROR_INTERNAL_ERROR); - goto WFMOExIntReleaseControllers; + goto WFMOExIntReleaseControllers; } if (fValue) { @@ -424,16 +424,16 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( iSignaledObjIndex = i; if (!fWAll) break; - } + } } fNeedToBlock = (iSignaledObjCount == 0) || (fWAll && (iSignaledObjCount < (int)nCount)); if (!fNeedToBlock) { // At least one object signaled, or bWaitAll==TRUE and all object signaled. - // No need to wait, let's unsignal the object(s) and return without blocking + // No need to wait, let's unsignal the object(s) and return without blocking int iStartIdx, iEndIdx; - + if (fWAll) { iStartIdx = 0; @@ -444,7 +444,7 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( iStartIdx = iSignaledObjIndex; iEndIdx = iStartIdx + 1; } - + // Unsignal objects if( iStartIdx < 0 ) { @@ -457,9 +457,9 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( { palErr = ppISyncWaitCtrlrs[i]->ReleaseWaitingThreadWithoutBlocking(); if (NO_ERROR != palErr) - { + { ERROR("ReleaseWaitingThreadWithoutBlocking() failed for %d-th " - "object [handle=%p error=%u]\n", + "object [handle=%p error=%u]\n", i, lpHandles[i], palErr); pThread->SetLastError(palErr); goto WFMOExIntReleaseControllers; @@ -473,29 +473,29 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( // Not enough objects signaled, but timeout is zero: no actual wait dwRet = WAIT_TIMEOUT; fNeedToBlock = false; - } + } else { // Register the thread for waiting on all objects for (i=0;i<(int)nCount;i++) { palErr = ppISyncWaitCtrlrs[i]->RegisterWaitingThread( - wtWaitType, + wtWaitType, i, (TRUE == bAlertable)); if (NO_ERROR != palErr) - { + { ERROR("RegisterWaitingThread() failed for %d-th object " "[handle=%p error=%u]\n", i, lpHandles[i], palErr); pThread->SetLastError(palErr); goto WFMOExIntReleaseControllers; } - } + } } WFMOExIntReleaseControllers: - // Release all controllers before going to sleep - for (i = 0; i < (int)nCount; i++) + // Release all controllers before going to sleep + for (i = 0; i < (int)nCount; i++) { ppISyncWaitCtrlrs[i]->ReleaseController(); ppISyncWaitCtrlrs[i] = NULL; @@ -510,23 +510,23 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( // // Going to sleep // - palErr = g_pSynchronizationManager->BlockThread(pThread, - dwMilliseconds, - (TRUE == bAlertable), + palErr = g_pSynchronizationManager->BlockThread(pThread, + dwMilliseconds, + (TRUE == bAlertable), false, - &twrWakeupReason, + &twrWakeupReason, (DWORD *)&iSignaledObjIndex); // // Awakened // if (NO_ERROR != palErr) - { + { ERROR("IPalSynchronizationManager::BlockThread failed for thread " "pThread=%p [error=%u]\n", pThread, palErr); pThread->SetLastError(palErr); goto WFMOExIntCleanup; } - switch (twrWakeupReason) + switch (twrWakeupReason) { case WaitSucceeded: dwRet = WAIT_OBJECT_0; // offset added later @@ -536,32 +536,32 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( break; case WaitTimeout: dwRet = WAIT_TIMEOUT; - break; + break; case Alerted: - _ASSERT_MSG(bAlertable, + _ASSERT_MSG(bAlertable, "Awakened for APC from a non-alertable wait\n"); - dwRet = WAIT_IO_COMPLETION; + dwRet = WAIT_IO_COMPLETION; palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread); - _ASSERT_MSG(NO_ERROR == palErr, + _ASSERT_MSG(NO_ERROR == palErr, "Awakened for APC, but no APC is pending\n"); break; case WaitFailed: default: ERROR("Thread %p awakened with some failure\n", pThread); - dwRet = WAIT_FAILED; + dwRet = WAIT_FAILED; break; } - } - + } + if (!fWAll && ((WAIT_OBJECT_0 == dwRet) || (WAIT_ABANDONED_0 == dwRet))) { _ASSERT_MSG(0 <= iSignaledObjIndex, - "Failed to identify signaled/abandoned object\n"); + "Failed to identify signaled/abandoned object\n"); _ASSERT_MSG(iSignaledObjIndex >= 0 && nCount > static_cast(iSignaledObjIndex), "SignaledObjIndex object out of range " - "[index=%d obj_count=%u\n", + "[index=%d obj_count=%u\n", iSignaledObjCount, nCount); if (iSignaledObjIndex < 0) @@ -579,14 +579,14 @@ DWORD CorUnix::InternalWaitForMultipleObjectsEx( ppIPalObjs[i]->ReleaseReference(pThread); ppIPalObjs[i] = NULL; } - + WFMOExIntExit: if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE) { InternalDeleteArray(ppIPalObjs); InternalDeleteArray(ppISyncWaitCtrlrs); } - + return dwRet; } @@ -605,7 +605,7 @@ PAL_ERROR CorUnix::InternalSleepEx ( { // In this case do not use AreAPCsPending. In fact, since we are // not holding the synch lock(s) an APC posting may race with - // AreAPCsPending. + // AreAPCsPending. palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread); if (NO_ERROR == palErr) { @@ -617,40 +617,40 @@ PAL_ERROR CorUnix::InternalSleepEx ( // No APC was pending, just continue palErr = NO_ERROR; } - } + } if (dwMilliseconds > 0) { ThreadWakeupReason twrWakeupReason; - - palErr = g_pSynchronizationManager->BlockThread(pThread, + + palErr = g_pSynchronizationManager->BlockThread(pThread, dwMilliseconds, - (TRUE == bAlertable), + (TRUE == bAlertable), true, - &twrWakeupReason, - (DWORD *)&iSignaledObjIndex); + &twrWakeupReason, + (DWORD *)&iSignaledObjIndex); if (NO_ERROR != palErr) - { + { ERROR("IPalSynchronizationManager::BlockThread failed for thread " "pThread=%p [error=%u]\n", pThread, palErr); goto InternalSleepExExit; } - switch (twrWakeupReason) + switch (twrWakeupReason) { case WaitSucceeded: case WaitTimeout: - dwRet = 0; - break; + dwRet = 0; + break; case Alerted: - _ASSERT_MSG(bAlertable, + _ASSERT_MSG(bAlertable, "Awakened for APC from a non-alertable wait\n"); - dwRet = WAIT_IO_COMPLETION; + dwRet = WAIT_IO_COMPLETION; palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread); - _ASSERT_MSG(NO_ERROR == palErr, - "Awakened for APC, but no APC is pending\n"); + _ASSERT_MSG(NO_ERROR == palErr, + "Awakened for APC, but no APC is pending\n"); break; case MutexAbondoned: ASSERT("Thread %p awakened with reason=MutexAbondoned from a " @@ -662,7 +662,7 @@ PAL_ERROR CorUnix::InternalSleepEx ( ERROR("Thread %p awakened with some failure\n", pThread); palErr = ERROR_INTERNAL_ERROR; break; - } + } } else { @@ -674,4 +674,3 @@ PAL_ERROR CorUnix::InternalSleepEx ( InternalSleepExExit: return dwRet; } - From 42eda8e7ff3b75113784c5e99e9005ed31ebeb90 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 01:56:56 +0100 Subject: [PATCH 07/13] InitializeCriticalSectionAndSpinCount duplicate definition --- pal/inc/pal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/pal/inc/pal.h b/pal/inc/pal.h index 38fd9f177c3..480727f5c42 100644 --- a/pal/inc/pal.h +++ b/pal/inc/pal.h @@ -3232,7 +3232,6 @@ typedef struct _CRITICAL_SECTION { PALIMPORT VOID PALAPI EnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); PALIMPORT VOID PALAPI LeaveCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); PALIMPORT VOID PALAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection); -PALIMPORT BOOL PALAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount); PALIMPORT BOOL PALAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags); PALIMPORT BOOL PALAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount); PALIMPORT VOID PALAPI DeleteCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection); From 85fe1ac99e30f6f4424259c77c90991cd5f8bbe1 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 02:37:10 +0100 Subject: [PATCH 08/13] android: fix ranlib mixup and remove post ranlib call --- Build/android_toolchain.sh | 4 ++++ lib/Common/Core/CMakeLists.txt | 6 ------ lib/Jsrt/CMakeLists.txt | 6 ------ pal/src/CMakeLists.txt | 5 ----- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Build/android_toolchain.sh b/Build/android_toolchain.sh index 3de2c6707f5..e12f4ccc2cd 100755 --- a/Build/android_toolchain.sh +++ b/Build/android_toolchain.sh @@ -21,4 +21,8 @@ $1/build/tools/make-standalone-toolchain.sh \ --install-dir=$TOOLCHAIN \ --platform=$ANDROID_TARGET --force +# use system python rm $TOOLCHAIN/bin/python + +# keep cmake from using system ranlib +cp android-toolchain-arm/bin/arm-linux-androideabi-ranlib android-toolchain-arm/bin/ranlib diff --git a/lib/Common/Core/CMakeLists.txt b/lib/Common/Core/CMakeLists.txt index 73b158fc00c..f8cfefb5514 100644 --- a/lib/Common/Core/CMakeLists.txt +++ b/lib/Common/Core/CMakeLists.txt @@ -22,9 +22,3 @@ add_library (Chakra.Common.Core STATIC target_include_directories ( Chakra.Common.Core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) - -if(CC_TARGET_OS_ANDROID) - add_custom_command(TARGET Chakra.Common.Core POST_BUILD - COMMAND ${ANDROID_TOOLCHAIN_DIR}/bin/ranlib ${CMAKE_CURRENT_BINARY_DIR}/libChakra.Common.Core.a - ) -endif() diff --git a/lib/Jsrt/CMakeLists.txt b/lib/Jsrt/CMakeLists.txt index 3deb0e93821..ac3dc0d28c7 100644 --- a/lib/Jsrt/CMakeLists.txt +++ b/lib/Jsrt/CMakeLists.txt @@ -52,9 +52,3 @@ target_include_directories ( ../Runtime/Debug ../Parser ) - -if(CC_TARGET_OS_ANDROID) - add_custom_command(TARGET Chakra.Jsrt POST_BUILD - COMMAND ${ANDROID_TOOLCHAIN_DIR}/bin/ranlib ${CMAKE_CURRENT_BINARY_DIR}/libChakra.Jsrt.a - ) -endif() diff --git a/pal/src/CMakeLists.txt b/pal/src/CMakeLists.txt index b138ae4826f..234bc0ce59c 100644 --- a/pal/src/CMakeLists.txt +++ b/pal/src/CMakeLists.txt @@ -189,9 +189,4 @@ else() # Linux ${PTHREAD} dl ) - if(CC_TARGET_OS_ANDROID) - add_custom_command(TARGET Chakra.Pal POST_BUILD - COMMAND ${ANDROID_TOOLCHAIN_DIR}/bin/ranlib ${CMAKE_CURRENT_BINARY_DIR}/libChakra.Pal.a - ) - endif() endif() From 50afb956250f8d6f1586beb6451efef7bb2ea533 Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 18:14:50 +0100 Subject: [PATCH 09/13] trace: add builtin experimental trace support --- CMakeLists.txt | 17 + build.sh | 8 +- .../PlatformAgnostic/Platform/CMakeLists.txt | 1 + .../Platform/Common/Trace.cpp | 320 ++++++++++++++++++ 4 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 lib/Runtime/PlatformAgnostic/Platform/Common/Trace.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cf48ee9e50b..293ad9dcb47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,23 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(CC_TARGET_OS_OSX 1) endif() +if (ENABLE_CC_XPLAT_TRACE_SH) + unset(ENABLE_CC_XPLAT_TRACE_SH CACHE) + set(ENABLE_CC_XPLAT_TRACE 1) + if (CC_TARGET_OS_ANDROID) + add_definitions(-DTRACE_OUTPUT_TO_LOGCAT=1) + else() + add_definitions(-DTRACE_OUTPUT_TARGET_FILE=1) + endif() + add_definitions(-DENABLE_CC_XPLAT_TRACE=1) + add_compile_options(-finstrument-functions) + add_compile_options(-g) + add_compile_options(-ggdb) + if(NOT STATIC_LIBRARY) + message(FATAL_ERROR "Trace option is available only for --static builds") + endif() +endif() + if(CC_EMBED_ICU_SH) unset(CC_EMBED_ICU_SH CACHE) set(CC_EMBED_ICU 1) diff --git a/build.sh b/build.sh index 7ff93b223d7..e027cdbf768 100755 --- a/build.sh +++ b/build.sh @@ -47,6 +47,7 @@ PRINT_USAGE() { echo " e.g. undefined,signed-integer-overflow" echo " -t, --test-build Test build (by default Release build)" echo " --target[=S] Target OS" + echo " --trace Enables experimental built-in trace" echo " --xcode Generate XCode project" echo " --without=FEATURE,FEATURE,..." echo " Disable FEATUREs from JSRT experimental" @@ -80,6 +81,7 @@ OS_APT_GET=0 OS_UNIX=0 LTO="" TARGET_OS="" +ENABLE_CC_XPLAT_TRACE="" if [ -f "/proc/version" ]; then OS_LINUX=1 @@ -252,6 +254,10 @@ while [[ $# -gt 0 ]]; do fi ;; + --trace) + ENABLE_CC_XPLAT_TRACE="-DENABLE_CC_XPLAT_TRACE_SH=1" + ;; + --without=*) FEATURES=$1 FEATURES=${FEATURES:10} # value after --without= @@ -365,7 +371,7 @@ else fi echo Generating $BUILD_TYPE makefiles -cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $LTO $STATIC_LIBRARY $ARCH $TARGET_OS \ +cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $LTO $STATIC_LIBRARY $ARCH $TARGET_OS $ENABLE_CC_XPLAT_TRACE\ -DCMAKE_BUILD_TYPE=$BUILD_TYPE $SANITIZE $NO_JIT $WITHOUT_FEATURES ../.. _RET=$? diff --git a/lib/Runtime/PlatformAgnostic/Platform/CMakeLists.txt b/lib/Runtime/PlatformAgnostic/Platform/CMakeLists.txt index b18a2c2ae79..69f1a20bf49 100644 --- a/lib/Runtime/PlatformAgnostic/Platform/CMakeLists.txt +++ b/lib/Runtime/PlatformAgnostic/Platform/CMakeLists.txt @@ -6,6 +6,7 @@ set(PL_SOURCE_FILES Linux/HiResTimer.cpp Linux/NumbersUtility.cpp Linux/Thread.cpp + Common/Trace.cpp ) if(CC_TARGET_OS_ANDROID OR CC_TARGET_OS_LINUX) diff --git a/lib/Runtime/PlatformAgnostic/Platform/Common/Trace.cpp b/lib/Runtime/PlatformAgnostic/Platform/Common/Trace.cpp new file mode 100644 index 00000000000..1b51b00bff6 --- /dev/null +++ b/lib/Runtime/PlatformAgnostic/Platform/Common/Trace.cpp @@ -0,0 +1,320 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +// Trace light +// Standalone solution to trace function calls in a *nix application + +// Notes to Embedder; + +// This file is originally implemented for ChakraCore. +// However it is not dependent to any part of the project (and supposed to keep it that way) +// To use with your project, simple copy-paste of this file is sufficient. +// Required compiler args are -finstrument-functions +// -finstrument-functions enables GCC/Clang to inject __cyg_profile_func_enter/exit +// As of 3.9, clang doesn't support finstrument_functions_exclude_file_list or similar (reason for IN_TRACE) +// This version doesn't support multithread profiling. Records the entries from initial thread only + +// In case of bug-fix and/or improvements, please contribute back to https://github.com/Microsoft/ChakraCore + +// Dealing with output; + +// Converting from Address +// OSX -> atos -o
+// Linux -> addr2line -e
+ +// gdb -> info symbol
+ +// DEFINITIONS + +// #define TRACE_OUTPUT_TARGET_FILE // <- uncomment this if you want the trace is written to a file (TraceOutput.txt) +// #define TRACE_OUTPUT_TO_LOGCAT // <- uncomment this if you want to target Logcat for Android instead of stderr + +// #define ENABLE_CC_XPLAT_TRACE // uncomment this to use this code with your project or add ENABLE_CC_XPLAT_TRACE to your compile definitions +#ifdef ENABLE_CC_XPLAT_TRACE +#include +#include +#include +#include +#include +#include +#include +#define _GNU_SOURCE +#include // dladdr + +#if defined(__APPLE__) +#include // _NSGetExecutablePath +#elif defined(__linux__) +#include // readlink +#endif + + +#if defined(__ANDROID__) && defined(TRACE_OUTPUT_TO_LOGCAT) +#include +#define PRINT_ERROR(...) \ + __android_log_print(ANDROID_LOG_ERROR, "TRACE_LIGHT", __VA_ARGS__) +#else +#define PRINT_ERROR(...) \ + fprintf(stderr, __VA_ARGS__); +#endif + +#define TRACE_VERSION_STRING "Trace light v0.01" +#define FILE_BUFFER_SIZE 16384 +#define SELF_PATH_SIZE 2048 +static int SELF_PATH_LENGTH = 0; +static FILE *FTRACE = NULL; +static _Thread_local size_t LAST_TICK = -1; +static bool IN_TRACE = 0; +static unsigned long CALL_IN_COUNTER = 0; +static char SELF_PATH[SELF_PATH_SIZE]; +static char FILE_BUFFER[FILE_BUFFER_SIZE]; +static int BUFFER_POS = 0; + +__attribute__((no_instrument_function)) +static void +GetBinaryLocation() +{ +#if defined(__APPLE__) + uint32_t path_size = SELF_PATH_SIZE; + char *tmp = nullptr; + + if (_NSGetExecutablePath(SELF_PATH, &path_size)) + { + SELF_PATH_LENGTH = 0; + SELF_PATH[0] = char(0); // failed + return; + } + + tmp = (char*)malloc(SELF_PATH_SIZE); + char *result = realpath(SELF_PATH, tmp); + SELF_PATH_LENGTH = strlen(result); + memcpy(SELF_PATH, result, SELF_PATH_LENGTH); + free(tmp); + SELF_PATH[SELF_PATH_LENGTH] = char(0); +#elif defined(__linux__) + SELF_PATH_LENGTH = readlink("/proc/self/exe", SELF_PATH, SELF_PATH_SIZE - 1); + if (SELF_PATH_LENGTH <= 0) + { + SELF_PATH_LENGTH = 0; + SELF_PATH[0] = char(0); // failed + return; + } + SELF_PATH[SELF_PATH_LENGTH] = char(0); +#else +#warning "Implement GetBinaryLocation for this platform" +#endif +} + +template +__attribute__((no_instrument_function)) +static void +print_to_buffer(const char* format, const T data) +{ +#ifndef TRACE_OUTPUT_TARGET_FILE + PRINT_ERROR(format, data); +#else + char TEMP[FILE_BUFFER_SIZE]; + int length = 0; + + if (format) + { + length = snprintf(TEMP, FILE_BUFFER_SIZE, format, data); + } + + if (format && (length + BUFFER_POS < FILE_BUFFER_SIZE - 1)) + { + memcpy(FILE_BUFFER + BUFFER_POS, TEMP, length); + BUFFER_POS += length; + } + else + { + FILE_BUFFER[BUFFER_POS] = 0; + fprintf(FTRACE, "%s", FILE_BUFFER); + BUFFER_POS = 0; + + if (format) + { + print_to_buffer(format, data); + } + } +#endif +} + +__attribute__((no_instrument_function)) +static inline size_t +rdtsc() +{ +#if !defined(_X86_) && !defined(__AMD64__) && !defined(__x86_64__) + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#else + size_t H, L; + __asm volatile ("rdtsc":"=a"(L), "=d"(H)); +#ifdef _X86_ + return L; +#else + return (H << 32) | L; +#endif +#endif // __x86_64__ +} + +__attribute__((no_instrument_function)) +static double +CPUFreq() +{ + struct timeval tstart, tend; + size_t start, end; + + struct timezone tzone; + memset(&tzone, 0, sizeof(tzone)); + + start = rdtsc(); + gettimeofday(&tstart, &tzone); + + usleep(1000); // 1ms + + end = rdtsc(); + gettimeofday(&tend, &tzone); + + size_t usec = ((tend.tv_sec - tstart.tv_sec)*1e6) + + (tend.tv_usec - tstart.tv_usec); + + if (!usec) return 0; + return (end - start) / usec; +} + +__attribute__ ((constructor, no_instrument_function)) +void +INIT_TRACE_FILE () +{ + GetBinaryLocation(); + print_to_buffer("%s\n", TRACE_VERSION_STRING); + print_to_buffer("CPU Freq at ~%f\n", CPUFreq()); + print_to_buffer("Binary Path: %s\n\n", SELF_PATH); + +#ifdef TRACE_OUTPUT_TARGET_FILE + FTRACE = fopen("TraceOutput.txt", "w"); +#else + FTRACE = (FILE*) 1; +#endif + LAST_TICK = rdtsc(); +} + +__attribute__ ((destructor, no_instrument_function)) +void +CLOSE_TRACE_FILE () +{ + IN_TRACE = 1; // no_instrument_function does not block sub calls +#ifdef TRACE_OUTPUT_TARGET_FILE + if(FTRACE != NULL) + { + print_to_buffer(nullptr, 0); // force flush + fclose(FTRACE); + printf("\nTrace output is available under ./TraceOutput.txt\n"); + } +#endif + IN_TRACE = 0; +} + +__attribute__((no_instrument_function)) +static bool +CMP_REVERSE(const char * fname) +{ + if (SELF_PATH_LENGTH == 0) return false; + + // linux dli_fname may not return the full path + // compare from the end. + int pos = strlen(fname) - 1; + int self_pos = SELF_PATH_LENGTH - 1; + if (self_pos < pos) return false; + while(pos >= 0) + { + if (fname[pos--] != SELF_PATH[self_pos--]) return false; + } + + return true; +} + +__attribute__((no_instrument_function)) +static void +print_function(void *func) +{ + print_to_buffer("[%p]", func); + + Dl_info info; + if (dladdr(func, &info) != 0) + { + if(CMP_REVERSE(info.dli_fname)) + { + print_to_buffer("<%s>", "self"); + } + else + { + print_to_buffer("<%s>", info.dli_fname); + } + } +} + +__attribute__((no_instrument_function)) +static void +print_indent() +{ + char space[512 + 1]; // max spaces + int length = (CALL_IN_COUNTER * 2) + 1; + if (length > 512) length = 512; + + for(int i = 0; i < length; i++) space[i] = ' '; + space[length - 1] = 0; + print_to_buffer("%s", space); +} + +__attribute__((no_instrument_function)) +static void +print_trace(void *func, void *caller, bool is_enter) +{ + if (FTRACE == NULL) return; + if (LAST_TICK == -1) return; // wrong thread + if (IN_TRACE) return; // clang doesn't support finstrument_functions_exclude_file_list + IN_TRACE = 1; + + size_t tick = rdtsc(); + if (!is_enter) + { + CALL_IN_COUNTER--; + LAST_TICK = tick; + IN_TRACE = 0; + return; + } + + print_indent(); + print_function(func); + print_to_buffer("(%lu)\n", tick - LAST_TICK); + + LAST_TICK = rdtsc(); + + if (is_enter) CALL_IN_COUNTER++; + IN_TRACE = 0; +} + +#define PROFILE_FUNC_ENTER __cyg_profile_func_enter(void *func, void *caller) +#define PROFILE_FUNC_EXIT __cyg_profile_func_exit(void *func, void *caller) + +extern "C" +{ + __attribute__((no_instrument_function)) + extern void + PROFILE_FUNC_ENTER + { + print_trace(func, caller, true); + } + + __attribute__((no_instrument_function)) + extern void + PROFILE_FUNC_EXIT + { + print_trace(func, caller, false); + } +} +#endif // ENABLE_CC_XPLAT_TRACE From 4f024b3b3658a725ca9258b6f3bfe23ecc2c4aac Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Mon, 2 Jan 2017 23:47:38 +0100 Subject: [PATCH 10/13] ld: reduce link time memory usage --- bin/ChakraCore/CMakeLists.txt | 2 ++ bin/ch/CMakeLists.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bin/ChakraCore/CMakeLists.txt b/bin/ChakraCore/CMakeLists.txt index dc26b9375c2..03ed9f36d99 100644 --- a/bin/ChakraCore/CMakeLists.txt +++ b/bin/ChakraCore/CMakeLists.txt @@ -53,6 +53,8 @@ set(lib_target "${lib_target}" if(CC_TARGET_OS_ANDROID OR CC_TARGET_OS_LINUX) set(lib_target "${lib_target}" -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libChakraCoreLib.version + # reduce link time memory usage + -Xlinker --no-keep-memory ) elseif(CC_TARGET_OS_OSX) if(CC_TARGETS_X86) diff --git a/bin/ch/CMakeLists.txt b/bin/ch/CMakeLists.txt index 4ed85967704..96f0cd0ac7e 100644 --- a/bin/ch/CMakeLists.txt +++ b/bin/ch/CMakeLists.txt @@ -87,6 +87,8 @@ endif() if(CC_TARGET_OS_ANDROID OR CC_TARGET_OS_LINUX) set(lib_target "${lib_target}" -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/ch.version + # reduce link time memory usage + -Xlinker --no-keep-memory ) elseif(CC_TARGET_OS_OSX) if(CC_TARGETS_X86) From 880222ad1ee40ecee31d04557b003da81cce5aff Mon Sep 17 00:00:00 2001 From: "ogbastem@microsoft.com" Date: Wed, 4 Jan 2017 13:58:07 -0800 Subject: [PATCH 11/13] arm: do not require --arch when compiling on ARM Linux --- CMakeLists.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 293ad9dcb47..98c8fce9854 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,19 +18,19 @@ if(STATIC_LIBRARY_SH) set(STATIC_LIBRARY 1) endif() -if(CC_TARGETS_AMD64_SH) - set(CC_TARGETS_AMD64 1) -endif() - -if(CC_TARGETS_X86_SH) - set(CC_TARGETS_X86 1) - set(CMAKE_SYSTEM_PROCESSOR "i386") -endif() - -if(CC_TARGETS_ARM_SH) +if (CC_TARGETS_ARM_SH OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") set(CC_TARGETS_ARM 1) add_definitions(-D_ARM_=1) set(CMAKE_SYSTEM_PROCESSOR "armv7l") +else() + if(CC_TARGETS_AMD64_SH) + set(CC_TARGETS_AMD64 1) + endif() + + if(CC_TARGETS_X86_SH) + set(CC_TARGETS_X86 1) + set(CMAKE_SYSTEM_PROCESSOR "i386") + endif() endif() unset(CC_TARGETS_ARM_SH CACHE) From fc95140cca741835e35ba137e5a29582c5ce3d0a Mon Sep 17 00:00:00 2001 From: "ogbastem@microsoft.com" Date: Thu, 5 Jan 2017 23:36:58 -0800 Subject: [PATCH 12/13] xplat: bring clang/llvm/bintools-gold and prepare for ChakraCore - Automated preq. installation for Debian / RedHat distros Build/compile_clang.sh This script downloads and compiles llvm/clang/lto-gold projects [3.9.1] --- .gitignore | 1 + Build/compile_clang.sh | 122 +++++++++++++++++++++++++++++++++ CMakeLists.txt | 27 ++++++-- bin/ChakraCore/CMakeLists.txt | 5 +- bin/GCStress/CMakeLists.txt | 1 + bin/ch/CMakeLists.txt | 5 +- build.sh | 7 ++ lib/Common/Core/CMakeLists.txt | 4 ++ lib/Jsrt/CMakeLists.txt | 4 ++ pal/src/CMakeLists.txt | 3 +- 10 files changed, 170 insertions(+), 9 deletions(-) create mode 100755 Build/compile_clang.sh diff --git a/.gitignore b/.gitignore index 08cd53d07c0..c14b7c8990e 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ deps/ .DS_Store android-toolchain-arm/ +cc-toolchain/ diff --git a/Build/compile_clang.sh b/Build/compile_clang.sh new file mode 100755 index 00000000000..0fc3ab5ece4 --- /dev/null +++ b/Build/compile_clang.sh @@ -0,0 +1,122 @@ +#!/bin/bash +#------------------------------------------------------------------------------------------------------- +# Copyright (C) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +#------------------------------------------------------------------------------------------------------- + +LLVM_VERSION="3.9.1" + +CC_URL="git://sourceware.org/git/binutils-gdb.git\nhttp://llvm.org/releases/${LLVM_VERSION}/\n" +echo -e "\n----------------------------------------------------------------" +echo -e "\nThis script will download LLVM/CLANG and LLVM Gold Bintools from\n${CC_URL}\n" +echo "These software are licensed to you by its publisher(s), not Microsoft." +echo "Microsoft is not responsible for the software." +echo "Your installation and use of the software is subject to the publisher’s terms available here:" +echo -e "http://llvm.org/docs/DeveloperPolicy.html#license\nhttp://llvm.org/docs/GoldPlugin.html#licensing\n" +echo -e "----------------------------------------------------------------\n" +echo "If you don't agree, press Ctrl+C to terminate" +read -t 10 -p "Hit ENTER to continue (or wait 10 seconds)" + +echo -e "\nThis will take some time... [and free memory 2GB+]\n" + +ROOT=${PWD}/cc-toolchain/ +GOLD_PLUGIN="" + +if [ ! -d ./cc-toolchain/src/llvm/projects/compiler-rt ]; then + rm -rf cc-toolchain + mkdir cc-toolchain + cd cc-toolchain + mkdir src + mkdir bin + cd src + + apt-get -v >/dev/null 2>&1 + if [ $? == 0 ]; then # debian + sudo apt-get install -y apt-file texinfo texi2html csh gawk automake libtool libtool-bin bison flex libncurses5-dev + if [ $? != 0 ]; then + exit 1 + fi + else + yum -v >/dev/null 2>&1 + if [ $? == 0 ]; then # redhat + yum install -y texinfo texi2html csh gawk automake libtool libtool-bin bison flex ncurses-devel + else + echo "This script requires (texinfo texi2html csh gawk automake libtool libtool-bin bison flex ncurses-devel)" + echo "Automated installation of these requirements is supported with apt-get and yum only." + echo "" + echo "If you don't have these packages are installed, press Ctrl+C to terminate" + read -t 10 -p "Hit ENTER to continue (or wait 10 seconds)" + fi + fi + + mkdir lto_utils + cd lto_utils + echo "Downloading LLVM Gold Plugin" + git clone --depth 1 git://sourceware.org/git/binutils-gdb.git binutils >/dev/null 2>&1 + mkdir binutils_compile; cd binutils_compile + ../binutils/configure --enable-gold --enable-plugins --disable-werror --prefix="${ROOT}/build" + make -j2 + make install + if [ $? != 0 ]; then + exit 1 + fi + + echo -e "\n\n\n\n" + cd "${ROOT}/src/" + + echo "Downloading LLVM ${LLVM_VERSION}" + wget –quiet "http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz" >/dev/null 2>&1 + tar -xf "llvm-${LLVM_VERSION}.src.tar.xz" + if [ $? == 0 ]; then + rm "llvm-${LLVM_VERSION}.src.tar.xz" + mv "llvm-${LLVM_VERSION}.src" llvm + else + exit 1 + fi + + cd llvm/tools/ + echo "Downloading Clang ${LLVM_VERSION}" + wget –quiet "http://llvm.org/releases/${LLVM_VERSION}/cfe-${LLVM_VERSION}.src.tar.xz" >/dev/null 2>&1 + tar -xf "cfe-${LLVM_VERSION}.src.tar.xz" + if [ $? == 0 ]; then + mv "cfe-${LLVM_VERSION}.src" clang + rm "cfe-${LLVM_VERSION}.src.tar.xz" + else + exit 1 + fi + + mkdir -p ../projects/ + cd ../projects/ + echo "Downloading Compiler-RT ${LLVM_VERSION}" + wget –quiet "http://llvm.org/releases/${LLVM_VERSION}/compiler-rt-${LLVM_VERSION}.src.tar.xz" >/dev/null 2>&1 + tar -xf "compiler-rt-${LLVM_VERSION}.src.tar.xz" + if [ $? == 0 ]; then + mv "compiler-rt-${LLVM_VERSION}.src" compiler-rt + rm "compiler-rt-${LLVM_VERSION}.src.tar.xz" + else + exit 1 + fi +fi + +GOLD_PLUGIN=-DLLVM_BINUTILS_INCDIR="${ROOT}/src/lto_utils/binutils/include" + +mkdir -p "${ROOT}/build" +cd "${ROOT}/src/llvm" +mkdir -p build_ +cd build_ + +cmake ../ -DCMAKE_INSTALL_PREFIX="${ROOT}/build" -DCMAKE_BUILD_TYPE=Release ${GOLD_PLUGIN} + +if [ $? != 0 ]; then + cd .. + rm -rf build_ + mkdir build_ + exit 1 +fi + +make -j4 install + +if [ $? == 0 ]; then + echo -e "Done!\n./build.sh args are given below;\n\n" + echo "--cxx=${ROOT}/build/bin/clang++ --cc=${ROOT}/build/bin/clang" +fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c8fce9854..cb4eb7b1027 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,12 +306,27 @@ if(CLR_CMAKE_PLATFORM_XPLAT) endif() endif(CLR_CMAKE_PLATFORM_XPLAT) -if(ENABLE_FULL_LTO_SH) - unset(DENABLE_FULL_LTO_SH CACHE) - add_compile_options(-flto) -elseif(ENABLE_THIN_LTO_SH) - unset(ENABLE_THIN_LTO_SH CACHE) - add_compile_options(-flto=thin) +if (ENABLE_FULL_LTO_SH OR ENABLE_THIN_LTO_SH) + if (CC_TARGET_OS_LINUX) + set(CC_LTO_ENABLED + -fuse-ld=gold + -Xlinker -plugin=${CHAKRACORE_BINARY_DIR}/../../cc-toolchain/build/lib/LLVMgold.so + ) + endif() + + if (ENABLE_FULL_LTO_SH) + unset(DENABLE_FULL_LTO_SH CACHE) + add_compile_options(-flto) + if (CC_LTO_ENABLED) + set(CC_LTO_ENABLED "${CC_LTO_ENABLED} -flto") + endif() + elseif (ENABLE_THIN_LTO_SH) + unset(ENABLE_THIN_LTO_SH CACHE) + add_compile_options(-flto=thin) + if (CC_LTO_ENABLED) + set(CC_LTO_ENABLED "${CC_LTO_ENABLED} -flto=thin") + endif() + endif() endif() if(CMAKE_BUILD_TYPE STREQUAL Debug) diff --git a/bin/ChakraCore/CMakeLists.txt b/bin/ChakraCore/CMakeLists.txt index 03ed9f36d99..088d1c40357 100644 --- a/bin/ChakraCore/CMakeLists.txt +++ b/bin/ChakraCore/CMakeLists.txt @@ -64,7 +64,10 @@ elseif(CC_TARGET_OS_OSX) endif() endif() -target_link_libraries (ChakraCore ${lib_target}) +target_link_libraries (ChakraCore + ${lib_target} + ${CC_LTO_ENABLED} + ) if(NOT CC_XCODE_PROJECT) set(CC_LIB_EXT "so") diff --git a/bin/GCStress/CMakeLists.txt b/bin/GCStress/CMakeLists.txt index f054818cec3..bfb7a5f788f 100644 --- a/bin/GCStress/CMakeLists.txt +++ b/bin/GCStress/CMakeLists.txt @@ -32,6 +32,7 @@ set(lib_target "${lib_target}" Chakra.Pal Chakra.Jsrt ${LINKER_END_GROUP} + ${CC_LTO_ENABLED} ) target_link_libraries (GCStress ${lib_target}) diff --git a/bin/ch/CMakeLists.txt b/bin/ch/CMakeLists.txt index 96f0cd0ac7e..d62ab2cfd72 100644 --- a/bin/ch/CMakeLists.txt +++ b/bin/ch/CMakeLists.txt @@ -99,7 +99,10 @@ elseif(CC_TARGET_OS_OSX) endif() -target_link_libraries (ch ${lib_target}) +target_link_libraries (ch + ${lib_target} + ${CC_LTO_ENABLED} + ) if(NOT CC_XCODE_PROJECT) # Add a post build event to the ch target diff --git a/build.sh b/build.sh index e027cdbf768..d7691984cc7 100755 --- a/build.sh +++ b/build.sh @@ -196,10 +196,12 @@ while [[ $# -gt 0 ]]; do --lto) LTO="-DENABLE_FULL_LTO_SH=1" + HAS_LTO=1 ;; --lto-thin) LTO="-DENABLE_THIN_LTO_SH=1" + HAS_LTO=1 ;; -n | --ninja) @@ -282,6 +284,11 @@ while [[ $# -gt 0 ]]; do shift done +if [ "${HAS_LTO}${OS_LINUX}" == "11" ]; then + echo "lto: ranlib disabled" + export RANLIB=/bin/true +fi + if [[ ${#_VERBOSE} > 0 ]]; then # echo options back to the user echo "Printing command line options back to the user:" diff --git a/lib/Common/Core/CMakeLists.txt b/lib/Common/Core/CMakeLists.txt index f8cfefb5514..b719f81d2a8 100644 --- a/lib/Common/Core/CMakeLists.txt +++ b/lib/Common/Core/CMakeLists.txt @@ -20,5 +20,9 @@ add_library (Chakra.Common.Core STATIC SysInfo.cpp ) +target_link_libraries(Chakra.Common.Core + ${CC_LTO_ENABLED} + ) + target_include_directories ( Chakra.Common.Core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/lib/Jsrt/CMakeLists.txt b/lib/Jsrt/CMakeLists.txt index ac3dc0d28c7..38b7d0b600b 100644 --- a/lib/Jsrt/CMakeLists.txt +++ b/lib/Jsrt/CMakeLists.txt @@ -42,6 +42,10 @@ add_library (Chakra.Jsrt STATIC add_subdirectory(Core) +target_link_libraries(Chakra.Jsrt + ${CC_LTO_ENABLED} + ) + target_include_directories ( Chakra.Jsrt PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ../Backend diff --git a/pal/src/CMakeLists.txt b/pal/src/CMakeLists.txt index 234bc0ce59c..f53986ac203 100644 --- a/pal/src/CMakeLists.txt +++ b/pal/src/CMakeLists.txt @@ -188,5 +188,6 @@ else() # Linux target_link_libraries(Chakra.Pal ${PTHREAD} dl - ) + ${CC_LTO_ENABLED} + ) endif() From ef987bb2d738f1ea9370134b46e158c2708c6477 Mon Sep 17 00:00:00 2001 From: "ogbastem@microsoft.com" Date: Fri, 6 Jan 2017 00:33:40 -0800 Subject: [PATCH 13/13] arm-xplat: fix _get_va [ip + fp] --- lib/Runtime/Language/Arguments.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Runtime/Language/Arguments.h b/lib/Runtime/Language/Arguments.h index 7f2c5573ca3..c1ad50a7c44 100644 --- a/lib/Runtime/Language/Arguments.h +++ b/lib/Runtime/Language/Arguments.h @@ -28,6 +28,9 @@ inline Js::Var* _get_va(void* addrOfReturnAddress, int n) { // All args are right after ReturnAddress by custom calling convention Js::Var* pArgs = reinterpret_cast(addrOfReturnAddress) + 1; +#ifdef _ARM_ + n += 2; // ip + fp +#endif return pArgs + n; }