Skip to content
Snippets Groups Projects
Select Git revision
  • 29475371a4e9e84cc66dd69cc5f42b8df4f18db5
  • master default protected
  • 72-improve-docs-for_optimal_setup
  • os-path-join
  • develop-GA
  • add-higher-spindown-components
  • v1.3
  • v1.2
  • v1.1.2
  • v1.1.0
  • v1.0.1
11 results

plot_recovery.py

Blame
  • WinLauncher.cpp 9.48 KiB
    /*
     * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     *
     * This code is free software; you can redistribute it and/or modify it
     * under the terms of the GNU General Public License version 2 only, as
     * published by the Free Software Foundation.  Oracle designates this
     * particular file as subject to the "Classpath" exception as provided
     * by Oracle in the LICENSE file that accompanied this code.
     *
     * This code is distributed in the hope that it will be useful, but WITHOUT
     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     * version 2 for more details (a copy is included in the LICENSE file that
     * accompanied this code).
     *
     * You should have received a copy of the GNU General Public License version
     * 2 along with this work; if not, write to the Free Software Foundation,
     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     *
     * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     * or visit www.oracle.com if you need additional information or have any
     * questions.
     */
    
    #include <io.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <windows.h>
    
    #include "AppLauncher.h"
    #include "JvmLauncher.h"
    #include "Log.h"
    #include "Dll.h"
    #include "WinApp.h"
    #include "Toolbox.h"
    #include "Executor.h"
    #include "FileUtils.h"
    #include "UniqueHandle.h"
    #include "ErrorHandling.h"
    #include "WinSysInfo.h"
    #include "WinErrorHandling.h"
    
    
    // AllowSetForegroundWindow
    #pragma comment(lib, "user32")
    
    
    namespace {
    
    std::unique_ptr<Dll> loadDllWithAlteredPATH(const tstring& dllFullPath) {
        LOG_TRACE_FUNCTION();
    
        const tstring vanillaPathEnvVariable = SysInfo::getEnvVariable(_T("PATH"));
    
        tstring pathEnvVariable = vanillaPathEnvVariable
                + _T(";")
                + FileUtils::dirname(dllFullPath);
    
        SysInfo::setEnvVariable(_T("PATH"), pathEnvVariable);
    
        LOG_TRACE(tstrings::any() << "New value of PATH: " << pathEnvVariable);
    
        // Schedule restore of PATH after attempt to load the given dll
        const auto resetPATH = runAtEndOfScope([&vanillaPathEnvVariable]() -> void {
            SysInfo::setEnvVariable(_T("PATH"), vanillaPathEnvVariable);
        });
    
        return std::unique_ptr<Dll>(new Dll(dllFullPath));
    }
    
    std::unique_ptr<Dll> loadDllWithAddDllDirectory(const tstring& dllFullPath) {
        LOG_TRACE_FUNCTION();
    
        const tstring dirPath = FileUtils::dirname(dllFullPath);
    
        typedef DLL_DIRECTORY_COOKIE(WINAPI *AddDllDirectoryFunc)(PCWSTR);
    
        DllFunction<AddDllDirectoryFunc> _AddDllDirectory(
                Dll("kernel32.dll", Dll::System()), "AddDllDirectory");
    
        AddDllDirectoryFunc func = _AddDllDirectory;
        DLL_DIRECTORY_COOKIE res = func(dirPath.c_str());
        if (!res) {
            JP_THROW(SysError(tstrings::any()
                    << "AddDllDirectory(" << dirPath << ") failed", func));
        }
    
        LOG_TRACE(tstrings::any() << "AddDllDirectory(" << dirPath << "): OK");
    
        // Important: use LOAD_LIBRARY_SEARCH_DEFAULT_DIRS flag,
        // but not LOAD_LIBRARY_SEARCH_USER_DIRS!
        HMODULE dllHandle = LoadLibraryEx(dllFullPath.c_str(), NULL,
                LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
    
        LOG_TRACE(tstrings::any() << "LoadLibraryEx(" << dllFullPath
                << ", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS): " << dllHandle);
    
        const auto freeDll = runAtEndOfScope([&dllHandle]() -> void {
            Dll::freeLibrary(dllHandle);
        });
    
        return std::unique_ptr<Dll>(new Dll(dllFullPath));
    }
    
    
    class DllWrapper {
    public:
        DllWrapper(const tstring& dllName) {
            try {
                // Adjust the DLL search paths with AddDllDirectory() WINAPI CALL
                dll = loadDllWithAddDllDirectory(dllName);
            } catch (const std::exception&) {
                // Alter PATH environment variable as the last resort.
                dll = loadDllWithAlteredPATH(dllName);
            }
        }
    
    private:
        DllWrapper(const DllWrapper&);
        DllWrapper& operator=(const DllWrapper&);
    
    private:
        std::unique_ptr<Dll> dll;
    };
    
    
    tstring getJvmLibPath(const Jvm& jvm) {
        FileUtils::mkpath path;
    
        path << FileUtils::dirname(jvm.getPath()) << _T("server") << _T("jvm.dll");
    
        return path;
    }
    
    
    class RunExecutorWithMsgLoop {
    public:
        static DWORD apply(const Executor& exec) {
            RunExecutorWithMsgLoop instance(exec);
    
            UniqueHandle threadHandle = UniqueHandle(CreateThread(NULL, 0, worker,
                                        static_cast<LPVOID>(&instance), 0, NULL));
            if (threadHandle.get() == NULL) {
                JP_THROW(SysError("CreateThread() failed", CreateThread));
            }
    
            MSG msg;
            BOOL bRet;
            while((bRet = GetMessage(&msg, instance.hwnd, 0, 0 )) != 0) {
                if (bRet == -1) {
                    JP_THROW(SysError("GetMessage() failed", GetMessage));
                } else {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
    
            // Wait for worker thread to terminate to guarantee it will not linger
            // around after the thread running a message loop terminates.
            const DWORD res = ::WaitForSingleObject(threadHandle.get(), INFINITE);
            if (WAIT_FAILED ==  res) {
                JP_THROW(SysError("WaitForSingleObject() failed",
                                                            WaitForSingleObject));
            }
    
            LOG_TRACE(tstrings::any()
                                << "Executor worker thread terminated. Exit code="
                                << instance.exitCode);
            return instance.exitCode;
        }
    
    private:
        RunExecutorWithMsgLoop(const Executor& v): exec(v) {
            exitCode = 1;
    
            // Message-only window.
            hwnd = CreateWindowEx(0, _T("STATIC"), _T(""), 0, 0, 0, 0, 0,
                                  HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
            if (!hwnd) {
                JP_THROW(SysError("CreateWindowEx() failed", CreateWindowEx));
            }
        }
    
        static DWORD WINAPI worker(LPVOID param) {
            static_cast<RunExecutorWithMsgLoop*>(param)->run();
            return 0;
        }
    
        void run() {
            JP_TRY;
            exitCode = static_cast<DWORD>(exec.execAndWaitForExit());
            JP_CATCH_ALL;
    
            JP_TRY;
            if (!PostMessage(hwnd, WM_QUIT, 0, 0)) {
                JP_THROW(SysError("PostMessage(WM_QUIT) failed", PostMessage));
            }
            return;
            JP_CATCH_ALL;
    
            // All went wrong, PostMessage() failed. Just terminate with error code.
            exit(1);
        }
    
    private:
        const Executor& exec;
        DWORD exitCode;
        HWND hwnd;
    };
    
    
    void launchApp() {
        // [RT-31061] otherwise UI can be left in back of other windows.
        ::AllowSetForegroundWindow(ASFW_ANY);
    
        const tstring launcherPath = SysInfo::getProcessModulePath();
        const tstring appImageRoot = FileUtils::dirname(launcherPath);
        const tstring appDirPath = FileUtils::mkpath() << appImageRoot << _T("app");
    
        const AppLauncher appLauncher = AppLauncher().setImageRoot(appImageRoot)
            .addJvmLibName(_T("bin\\jli.dll"))
            .setAppDir(appDirPath)
            .setLibEnvVariableName(_T("PATH"))
            .setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot
                << _T("runtime"));
    
        const bool restart = !appLauncher.libEnvVariableContainsAppDir();
    
        std::unique_ptr<Jvm> jvm(appLauncher.createJvmLauncher());
    
        if (restart) {
            jvm->setEnvVariables();
    
            jvm = std::unique_ptr<Jvm>();
    
            UniqueHandle jobHandle(CreateJobObject(NULL, NULL));
            if (jobHandle.get() == NULL) {
                JP_THROW(SysError(tstrings::any() << "CreateJobObject() failed",
                                                                CreateJobObject));
            }
            JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = { };
            jobInfo.BasicLimitInformation.LimitFlags =
                    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
            if (!SetInformationJobObject(jobHandle.get(),
                    JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) {
                JP_THROW(SysError(tstrings::any() <<
                                                "SetInformationJobObject() failed",
                                                        SetInformationJobObject));
            }
    
            Executor exec(launcherPath);
            exec.visible(true).withJobObject(jobHandle.get()).suspended(true).inherit(true);
            const auto args = SysInfo::getCommandArgs();
            std::for_each(args.begin(), args.end(), [&exec] (const tstring& arg) {
                exec.arg(arg);
            });
    
            DWORD exitCode = RunExecutorWithMsgLoop::apply(exec);
    
            exit(exitCode);
            return;
        }
    
        // zip.dll (and others) may be loaded by java without full path
        // make sure it will look in runtime/bin
        const tstring runtimeBinPath = FileUtils::dirname(jvm->getPath());
        SetDllDirectory(runtimeBinPath.c_str());
        LOG_TRACE(tstrings::any() << "SetDllDirectory to: " << runtimeBinPath);
    
        const DllWrapper jliDll(jvm->getPath());
        std::unique_ptr<DllWrapper> splashDll;
        if (jvm->isWithSplash()) {
            const DllWrapper jvmDll(getJvmLibPath(*jvm));
            splashDll = std::unique_ptr<DllWrapper>(new DllWrapper(
                    FileUtils::mkpath()
                            << FileUtils::dirname(jvm->getPath())
                            << _T("splashscreen.dll")));
        }
    
        jvm->launch();
    }
    
    } // namespace
    
    #ifndef JP_LAUNCHERW
    
    int __cdecl  wmain() {
        return app::launch(std::nothrow, launchApp);
    }
    
    #else
    
    int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) {
        return app::wlaunch(std::nothrow, launchApp);
    }
    
    #endif