# HG changeset patch # User amenkov # Date 1287572919 -14400 # Node ID 3f92ea1ffcacc6452be83e5e571cf83330535825 # Parent 7d8d9506b4eeebe298e5d9d5fe7971c522fb6835 6867515: Reduce impact of D3D initializion on startup time 6891435: Improve D3D preloading 6946559: AWTToolKit thread crashes in JNU_GetEnv 6987967: D3D preloading thread should initialize COM Reviewed-by: igor, art, uta diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/bin/java_md.c --- a/jdk/src/windows/bin/java_md.c Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/bin/java_md.c Wed Oct 20 15:08:39 2010 +0400 @@ -51,6 +51,92 @@ static jboolean GetJREPath(char *path, jint pathsize); static void EnsureJreInstallation(const char *jrepath); +/* We supports warmup for UI stack that is performed in parallel + * to VM initialization. + * This helps to improve startup of UI application as warmup phase + * might be long due to initialization of OS or hardware resources. + * It is not CPU bound and therefore it does not interfere with VM init. + * Obviously such warmup only has sense for UI apps and therefore it needs + * to be explicitly requested by passing -Dsun.awt.warmup=true property + * (this is always the case for plugin/javaws). + * + * Implementation launches new thread after VM starts and use it to perform + * warmup code (platform dependent). + * This thread is later reused as AWT toolkit thread as graphics toolkit + * often assume that they are used from the same thread they were launched on. + * + * At the moment we only support warmup for D3D. It only possible on windows + * and only if other flags do not prohibit this (e.g. OpenGL support requested). + */ +#undef ENABLE_AWT_PRELOAD +#ifndef JAVA_ARGS /* turn off AWT preloading for javac, jar, etc */ + #define ENABLE_AWT_PRELOAD +#endif + +#ifdef ENABLE_AWT_PRELOAD +/* "AWT was preloaded" flag; + * turned on by AWTPreload(). + */ +int awtPreloaded = 0; + +/* Calls a function with the name specified + * the function must be int(*fn)(void). + */ +int AWTPreload(const char *funcName); +/* stops AWT preloading */ +void AWTPreloadStop(); + +/* D3D preloading */ +/* -1: not initialized; 0: OFF, 1: ON */ +int awtPreloadD3D = -1; +/* command line parameter to swith D3D preloading on */ +#define PARAM_PRELOAD_D3D "-Dsun.awt.warmup" +/* D3D/OpenGL management parameters */ +#define PARAM_NODDRAW "-Dsun.java2d.noddraw" +#define PARAM_D3D "-Dsun.java2d.d3d" +#define PARAM_OPENGL "-Dsun.java2d.opengl" +/* funtion in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */ +#define D3D_PRELOAD_FUNC "preloadD3D" + + +/* Extracts value of a parameter with the specified name + * from command line argument (returns pointer in the argument). + * Returns NULL if the argument does not contains the parameter. + * e.g.: + * GetParamValue("theParam", "theParam=value") returns pointer to "value". + */ +const char * GetParamValue(const char *paramName, const char *arg) { + int nameLen = JLI_StrLen(paramName); + if (JLI_StrNCmp(paramName, arg, nameLen) == 0) { + /* arg[nameLen] is valid (may contain final NULL) */ + if (arg[nameLen] == '=') { + return arg + nameLen + 1; + } + } + return NULL; +} + +/* Checks if commandline argument contains property specified + * and analyze it as boolean property (true/false). + * Returns -1 if the argument does not contain the parameter; + * Returns 1 if the argument contains the parameter and its value is "true"; + * Returns 0 if the argument contains the parameter and its value is "false". + */ +int GetBoolParamValue(const char *paramName, const char *arg) { + const char * paramValue = GetParamValue(paramName, arg); + if (paramValue != NULL) { + if (JLI_StrCaseCmp(paramValue, "true") == 0) { + return 1; + } + if (JLI_StrCaseCmp(paramValue, "false") == 0) { + return 0; + } + } + return -1; +} +#endif /* ENABLE_AWT_PRELOAD */ + + static jboolean _isjavaw = JNI_FALSE; @@ -132,6 +218,30 @@ exit(4); } /* If we got here, jvmpath has been correctly initialized. */ + + /* Check if we need preload AWT */ +#ifdef ENABLE_AWT_PRELOAD + argv = *pargv; + for (i = 0; i < *pargc ; i++) { + /* Tests the "turn on" parameter only if not set yet. */ + if (awtPreloadD3D < 0) { + if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) { + awtPreloadD3D = 1; + } + } + /* Test parameters which can disable preloading if not already disabled. */ + if (awtPreloadD3D != 0) { + if (GetBoolParamValue(PARAM_NODDRAW, argv[i]) == 1 + || GetBoolParamValue(PARAM_D3D, argv[i]) == 0 + || GetBoolParamValue(PARAM_OPENGL, argv[i]) == 1) + { + awtPreloadD3D = 0; + /* no need to test the rest of the parameters */ + break; + } + } + } +#endif /* ENABLE_AWT_PRELOAD */ } @@ -1087,6 +1197,40 @@ 0, &thread_id); } + + /* AWT preloading (AFTER main thread start) */ +#ifdef ENABLE_AWT_PRELOAD + /* D3D preloading */ + if (awtPreloadD3D != 0) { + char *envValue; + /* D3D routines checks env.var J2D_D3D if no appropriate + * command line params was specified + */ + envValue = getenv("J2D_D3D"); + if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) { + awtPreloadD3D = 0; + } + /* Test that AWT preloading isn't disabled by J2D_D3D_PRELOAD env.var */ + envValue = getenv("J2D_D3D_PRELOAD"); + if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) { + awtPreloadD3D = 0; + } + if (awtPreloadD3D < 0) { + /* If awtPreloadD3D is still undefined (-1), test + * if it is turned on by J2D_D3D_PRELOAD env.var. + * By default it's turned OFF. + */ + awtPreloadD3D = 0; + if (envValue != NULL && JLI_StrCaseCmp(envValue, "true") == 0) { + awtPreloadD3D = 1; + } + } + } + if (awtPreloadD3D) { + AWTPreload(D3D_PRELOAD_FUNC); + } +#endif /* ENABLE_AWT_PRELOAD */ + if (thread_handle) { WaitForSingleObject(thread_handle, INFINITE); GetExitCodeThread(thread_handle, &rslt); @@ -1094,6 +1238,13 @@ } else { rslt = continuation(args); } + +#ifdef ENABLE_AWT_PRELOAD + if (awtPreloaded) { + AWTPreloadStop(); + } +#endif /* ENABLE_AWT_PRELOAD */ + return rslt; } @@ -1140,3 +1291,98 @@ _isjavaw = javaw; JLI_SetTraceLauncher(); } + + +/* ============================== */ +/* AWT preloading */ +#ifdef ENABLE_AWT_PRELOAD + +typedef int FnPreloadStart(void); +typedef void FnPreloadStop(void); +static FnPreloadStop *fnPreloadStop = NULL; +static HMODULE hPreloadAwt = NULL; + +/* + * Starts AWT preloading + */ +int AWTPreload(const char *funcName) +{ + int result = -1; + /* load AWT library once (if several preload function should be called) */ + if (hPreloadAwt == NULL) { + /* awt.dll is not loaded yet */ + char libraryPath[MAXPATHLEN]; + int jrePathLen = 0; + HMODULE hJava = NULL; + HMODULE hVerify = NULL; + + while (1) { + /* awt.dll depends on jvm.dll & java.dll; + * jvm.dll is already loaded, so we need only java.dll; + * java.dll depends on MSVCRT lib & verify.dll. + */ + if (!GetJREPath(libraryPath, MAXPATHLEN)) { + break; + } + + /* save path length */ + jrePathLen = JLI_StrLen(libraryPath); + + /* load msvcrt 1st */ + LoadMSVCRT(); + + /* load verify.dll */ + JLI_StrCat(libraryPath, "\\bin\\verify.dll"); + hVerify = LoadLibrary(libraryPath); + if (hVerify == NULL) { + break; + } + + /* restore jrePath */ + libraryPath[jrePathLen] = 0; + /* load java.dll */ + JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL); + hJava = LoadLibrary(libraryPath); + if (hJava == NULL) { + break; + } + + /* restore jrePath */ + libraryPath[jrePathLen] = 0; + /* load awt.dll */ + JLI_StrCat(libraryPath, "\\bin\\awt.dll"); + hPreloadAwt = LoadLibrary(libraryPath); + if (hPreloadAwt == NULL) { + break; + } + + /* get "preloadStop" func ptr */ + fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop"); + + break; + } + } + + if (hPreloadAwt != NULL) { + FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName); + if (fnInit != NULL) { + /* don't forget to stop preloading */ + awtPreloaded = 1; + + result = fnInit(); + } + } + + return result; +} + +/* + * Terminates AWT preloading + */ +void AWTPreloadStop() { + if (fnPreloadStop != NULL) { + fnPreloadStop(); + } +} + +#endif /* ENABLE_AWT_PRELOAD */ diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/classes/sun/awt/windows/WToolkit.java --- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Wed Oct 20 15:08:39 2010 +0400 @@ -218,6 +218,8 @@ private static native void postDispose(); + private static native boolean startToolkitThread(Runnable thread); + public WToolkit() { // Startup toolkit threads if (PerformanceLogger.loggingEnabled()) { @@ -231,9 +233,6 @@ // where notifyAll can be called before // the "AWT-Windows" thread's parent thread is // waiting, resulting in a deadlock on startup. - Thread toolkitThread = new Thread(this, "AWT-Windows"); - toolkitThread.setDaemon(true); - toolkitThread.setPriority(Thread.NORM_PRIORITY+1); /* * Fix for 4701990. @@ -242,7 +241,11 @@ */ AWTAutoShutdown.notifyToolkitThreadBusy(); - toolkitThread.start(); + if (!startToolkitThread(this)) { + Thread toolkitThread = new Thread(this, "AWT-Windows"); + toolkitThread.setDaemon(true); + toolkitThread.start(); + } try { wait(); @@ -263,6 +266,7 @@ } public void run() { + Thread.currentThread().setPriority(Thread.NORM_PRIORITY+1); boolean startPump = init(); if (startPump) { diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp --- a/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp Wed Oct 20 15:08:39 2010 +0400 @@ -36,22 +36,6 @@ extern void addDisplayMode(JNIEnv* env, jobject arrayList, jint width, jint height, jint bitDepth, jint refreshRate); -void InitD3D(void *pReturn) -{ - J2dTraceLn(J2D_TRACE_INFO, "InitD3D"); - - jboolean *pRet = (jboolean *)pReturn; - - D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance(); - if (pMgr == NULL) { - J2dTraceLn(J2D_TRACE_ERROR, "InitD3D: could not create or init d3d"); - *pRet = JNI_FALSE; - } else { - J2dTraceLn(J2D_TRACE_INFO, "InitD3D: successfully initialized d3d"); - *pRet = JNI_TRUE; - } -} - extern "C" { /* * Class: sun_java2d_d3d_D3DGraphicsDevice @@ -63,8 +47,8 @@ { J2dTraceLn(J2D_TRACE_INFO, "D3DGD_initD3D"); - jboolean result = JNI_FALSE; - AwtToolkit::GetInstance().InvokeFunction(InitD3D, &result); + jboolean result = D3DInitializer::GetInstance().EnsureInited() + ? JNI_TRUE : JNI_FALSE; J2dTraceLn1(J2D_TRACE_INFO, "D3DGD_initD3D: result=%x", result); return result; } diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp --- a/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp Wed Oct 20 15:08:39 2010 +0400 @@ -40,6 +40,7 @@ D3DPipelineManager *D3DPipelineManager::pMgr = NULL; + D3DPipelineManager * D3DPipelineManager::CreateInstance(void) { if (!IsD3DEnabled() || @@ -179,6 +180,12 @@ HMONITOR hMon; int gdiScreen; D3DPipelineManager *pMgr; + + // fix for 6946559: if d3d preloading fails jmv may be NULL + if (jvm == NULL) { + return; + } + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); pMgr = D3DPipelineManager::GetInstance(); @@ -934,3 +941,87 @@ *ppd3dContext = pAdapters[adapterOrdinal].pd3dContext; return res; } + + +//============================================================== +// D3DInitializer +//============================================================== + +D3DInitializer D3DInitializer::theInstance; + +D3DInitializer::D3DInitializer() + : bComInitialized(false), pAdapterIniters(NULL) +{ +} + +D3DInitializer::~D3DInitializer() +{ + if (pAdapterIniters) { + delete[] pAdapterIniters; + } +} + +void D3DInitializer::InitImpl() +{ + J2dRlsTraceLn(J2D_TRACE_INFO, "D3DInitializer::InitImpl"); + if (SUCCEEDED(::CoInitialize(NULL))) { + bComInitialized = true; + } + D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance(); + if (pMgr != NULL) { + UINT adapterCount = pMgr->adapterCount; + + pAdapterIniters = new D3DAdapterInitializer[adapterCount]; + for (UINT i=0; iGetD3DContext(adapter, &pd3dContext); + + J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) finished", adapter); +} + +void D3DInitializer::D3DAdapterInitializer::CleanImpl(bool reInit) +{ + // nothing to do - D3DPipelineManager cleans adapters +} + + +extern "C" { +/* + * Export function to start D3D preloading + * (called from java/javaw - see src/windows/bin/java-md.c) + */ +__declspec(dllexport) int preloadD3D() +{ + J2dRlsTraceLn(J2D_TRACE_INFO, "AWT warmup: preloadD3D"); + AwtToolkit::GetInstance().GetPreloadThread().AddAction(&D3DInitializer::GetInstance()); + return 1; +} + +} + diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h --- a/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h Wed Oct 20 15:08:39 2010 +0400 @@ -26,6 +26,7 @@ #include "D3DPipeline.h" #include "D3DContext.h" +#include "awt_Toolkit.h" typedef class D3DPipelineManager *LPD3DPIPELINEMANAGER; @@ -38,11 +39,15 @@ class D3DPIPELINE_API D3DPipelineManager { -public: + friend class D3DInitializer; +private: // creates and initializes instance of D3DPipelineManager, may return NULL static D3DPipelineManager* CreateInstance(void); + // deletes the single instance of the manager static void DeleteInstance(); + +public: // returns the single instance of the manager, may return NULL static D3DPipelineManager* GetInstance(void); @@ -143,3 +148,40 @@ #define OS_ALL (OS_VISTA|OS_WINSERV_2008|OS_WINXP|OS_WINXP_64|OS_WINSERV_2003) #define OS_UNKNOWN (~OS_ALL) BOOL D3DPPLM_OsVersionMatches(USHORT osInfo); + + +class D3DInitializer : public AwtToolkit::PreloadAction { +private: + D3DInitializer(); + ~D3DInitializer(); + +protected: + // PreloadAction overrides + virtual void InitImpl(); + virtual void CleanImpl(bool reInit); + +public: + static D3DInitializer& GetInstance() { return theInstance; } + +private: + // single instance + static D3DInitializer theInstance; + + // adapter initializer class + class D3DAdapterInitializer : public AwtToolkit::PreloadAction { + public: + void setAdapter(UINT adapter) { this->adapter = adapter; } + protected: + // PreloadAction overrides + virtual void InitImpl(); + virtual void CleanImpl(bool reInit); + private: + UINT adapter; + }; + + // the flag indicates success of COM initialization + bool bComInitialized; + D3DAdapterInitializer *pAdapterIniters; + +}; + diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp --- a/jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/java2d/windows/WindowsFlags.cpp Wed Oct 20 15:08:39 2010 +0400 @@ -28,7 +28,8 @@ #include "WindowsFlags.h" BOOL accelReset; // reset registry 2d acceleration settings -BOOL useD3D; // d3d enabled flag +BOOL useD3D = TRUE; // d3d enabled flag + // initially is TRUE to allow D3D preloading BOOL forceD3DUsage; // force d3d on or off jboolean g_offscreenSharing; // JAWT accelerated surface sharing BOOL checkRegistry; // Diagnostic tool: outputs 2d registry settings diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/windows/awt_Toolkit.cpp --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Wed Oct 20 15:08:39 2010 +0400 @@ -26,6 +26,7 @@ #include "awt.h" #include #include +#include //#if defined(_DEBUG) && defined(_MSC_VER) && _MSC_VER >= 1000 //#include @@ -92,7 +93,7 @@ /* Initialize the Java VM instance variable when the library is first loaded */ -JavaVM *jvm; +JavaVM *jvm = NULL; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) @@ -362,6 +363,95 @@ return hwnd; } + +struct ToolkitThreadProc_Data { + bool result; + HANDLE hCompleted; + + jobject thread; +}; + +void ToolkitThreadProc(void *param) +{ + ToolkitThreadProc_Data *data = (ToolkitThreadProc_Data *)param; + + bool bNotified = false; + + JNIEnv *env; + JavaVMAttachArgs attachArgs; + attachArgs.version = JNI_VERSION_1_2; + attachArgs.name = "AWT-Windows"; + attachArgs.group = NULL; + + jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs); + if (res < 0) { + return; + } + + jobject thread = env->NewGlobalRef(data->thread); + if (thread != NULL) { + jclass cls = env->GetObjectClass(thread); + if (cls != NULL) { + jmethodID runId = env->GetMethodID(cls, "run", "()V"); + if (runId != NULL) { + data->result = true; + ::SetEvent(data->hCompleted); + bNotified = true; + + env->CallVoidMethod(thread, runId); + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + // TODO: handle + } + } + env->DeleteLocalRef(cls); + } + env->DeleteGlobalRef(thread); + } + if (!bNotified) { + ::SetEvent(data->hCompleted); + } + + jvm->DetachCurrentThread(); +} + +/* + * Class: sun_awt_windows_WToolkit + * Method: startToolkitThread + * Signature: (Ljava/lang/Runnable;)Z + */ +JNIEXPORT jboolean JNICALL +Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread) +{ + AwtToolkit& tk = AwtToolkit::GetInstance(); + + ToolkitThreadProc_Data data; + data.result = false; + data.thread = env->NewGlobalRef(thread); + if (data.thread == NULL) { + return JNI_FALSE; + } + data.hCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL); + + bool result = tk.GetPreloadThread() + .InvokeAndTerminate(ToolkitThreadProc, &data); + + if (result) { + ::WaitForSingleObject(data.hCompleted, INFINITE); + result = data.result; + } else { + // no awt preloading + // return back to the usual toolkit way + } + ::CloseHandle(data.hCompleted); + + env->DeleteGlobalRef(data.thread); + + return result ? JNI_TRUE : JNI_FALSE; +} + BOOL AwtToolkit::Initialize(BOOL localPump) { AwtToolkit& tk = AwtToolkit::GetInstance(); @@ -375,6 +465,11 @@ // ComCtl32Util was constructed but not disposed ComCtl32Util::GetInstance().InitLibraries(); + if (!localPump) { + // if preload thread was run, terminate it + preloadThread.Terminate(true); + } + /* Register this toolkit's helper window */ VERIFY(tk.RegisterClass() != NULL); @@ -443,7 +538,7 @@ // dispose Direct3D-related resources. This should be done // before AwtObjectList::Cleanup() as the d3d will attempt to // shutdown when the last of its windows is disposed of - D3DPipelineManager::DeleteInstance(); + D3DInitializer::GetInstance().Clean(); AwtObjectList::Cleanup(); AwtFont::Cleanup(); @@ -1639,6 +1734,270 @@ ::GetWindowRect(hWnd, lpRect); } + +/************************************************************************ + * AWT preloading support + */ +bool AwtToolkit::PreloadAction::EnsureInited() +{ + DWORD _initThreadId = GetInitThreadID(); + if (_initThreadId != 0) { + // already inited + // ensure the action is inited on correct thread + PreloadThread &preloadThread + = AwtToolkit::GetInstance().GetPreloadThread(); + if (_initThreadId == preloadThread.GetThreadId()) { + if (!preloadThread.IsWrongThread()) { + return true; + } + // inited on preloadThread (wrongThread), not cleaned yet + // have to wait cleanup completion + preloadThread.Wait4Finish(); + } else { + // inited on other thread (Toolkit thread?) + // consider as correctly inited + return true; + } + } + + // init on Toolkit thread + AwtToolkit::GetInstance().InvokeFunction(InitWrapper, this); + + return true; +} + +DWORD AwtToolkit::PreloadAction::GetInitThreadID() +{ + CriticalSection::Lock lock(initLock); + return initThreadId; +} + +bool AwtToolkit::PreloadAction::Clean() +{ + DWORD _initThreadId = GetInitThreadID(); + if (_initThreadId == ::GetCurrentThreadId()) { + // inited on this thread + Clean(false); + return true; + } + return false; +} + +/*static*/ +void AwtToolkit::PreloadAction::InitWrapper(void *param) +{ + PreloadAction *pThis = (PreloadAction *)param; + pThis->Init(); +} + +void AwtToolkit::PreloadAction::Init() +{ + CriticalSection::Lock lock(initLock); + if (initThreadId == 0) { + initThreadId = ::GetCurrentThreadId(); + InitImpl(); + } +} + +void AwtToolkit::PreloadAction::Clean(bool reInit) { + CriticalSection::Lock lock(initLock); + if (initThreadId != 0) { + //ASSERT(initThreadId == ::GetCurrentThreadId()); + CleanImpl(reInit); + initThreadId = 0; + } +} + +// PreloadThread implementation +AwtToolkit::PreloadThread::PreloadThread() + : status(None), wrongThread(false), threadId(0), + pActionChain(NULL), pLastProcessedAction(NULL), + execFunc(NULL), execParam(NULL) +{ + hFinished = ::CreateEvent(NULL, TRUE, FALSE, NULL); + hAwake = ::CreateEvent(NULL, FALSE, FALSE, NULL); +} + +AwtToolkit::PreloadThread::~PreloadThread() +{ + //Terminate(false); + ::CloseHandle(hFinished); + ::CloseHandle(hAwake); +} + +bool AwtToolkit::PreloadThread::AddAction(AwtToolkit::PreloadAction *pAction) +{ + CriticalSection::Lock lock(threadLock); + + if (status > Preloading) { + // too late - the thread already terminated or run as toolkit thread + return false; + } + + if (pActionChain == NULL) { + // 1st action + pActionChain = pAction; + } else { + // add the action to the chain + PreloadAction *pChain = pActionChain; + while (true) { + PreloadAction *pNext = pChain->GetNext(); + if (pNext == NULL) { + break; + } + pChain = pNext; + } + pChain->SetNext(pAction); + } + + if (status > None) { + // the thread is already running (status == Preloading) + AwakeThread(); + return true; + } + + // need to start thread + ::ResetEvent(hAwake); + ::ResetEvent(hFinished); + + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0x100000, StaticThreadProc, + this, 0, &threadId); + + if (hThread == 0) { + threadId = 0; + return false; + } + + status = Preloading; + + ::CloseHandle(hThread); + + return true; +} + +bool AwtToolkit::PreloadThread::Terminate(bool wrongThread) +{ + CriticalSection::Lock lock(threadLock); + + if (status != Preloading) { + return false; + } + + execFunc = NULL; + execParam = NULL; + this->wrongThread = wrongThread; + status = Cleaning; + AwakeThread(); + + return true; +} + +bool AwtToolkit::PreloadThread::InvokeAndTerminate(void(_cdecl *fn)(void *), void *param) +{ + CriticalSection::Lock lock(threadLock); + + if (status != Preloading) { + return false; + } + + execFunc = fn; + execParam = param; + status = fn == NULL ? Cleaning : RunningToolkit; + AwakeThread(); + + return true; +} + +/*static*/ +unsigned WINAPI AwtToolkit::PreloadThread::StaticThreadProc(void *param) +{ + AwtToolkit::PreloadThread *pThis = (AwtToolkit::PreloadThread *)param; + return pThis->ThreadProc(); +} + +unsigned AwtToolkit::PreloadThread::ThreadProc() +{ + void(_cdecl *_execFunc)(void *) = NULL; + void *_execParam = NULL; + bool _wrongThread = false; + + // initialization + while (true) { + PreloadAction *pAction; + { + CriticalSection::Lock lock(threadLock); + if (status != Preloading) { + // get invoke parameters + _execFunc = execFunc; + _execParam = execParam; + _wrongThread = wrongThread; + break; + } + pAction = GetNextAction(); + } + if (pAction != NULL) { + pAction->Init(); + } else { + ::WaitForSingleObject(hAwake, INFINITE); + } + } + + // call a function from InvokeAndTerminate + if (_execFunc != NULL) { + _execFunc(_execParam); + } else { + // time to terminate.. + } + + // cleanup + { + CriticalSection::Lock lock(threadLock); + pLastProcessedAction = NULL; // goto 1st action in the chain + status = Cleaning; + } + for (PreloadAction *pAction = GetNextAction(); pAction != NULL; + pAction = GetNextAction()) { + pAction->Clean(_wrongThread); + } + + // don't clear threadId! it is used by PreloadAction::EnsureInited + + { + CriticalSection::Lock lock(threadLock); + status = Finished; + } + ::SetEvent(hFinished); + return 0; +} + +AwtToolkit::PreloadAction* AwtToolkit::PreloadThread::GetNextAction() +{ + CriticalSection::Lock lock(threadLock); + PreloadAction *pAction = (pLastProcessedAction == NULL) + ? pActionChain + : pLastProcessedAction->GetNext(); + if (pAction != NULL) { + pLastProcessedAction = pAction; + } + + return pAction; +} + + +extern "C" { + +/* Terminates preload thread (if it's still alive + * - it may occur if the application doesn't use AWT). + * The function is called from launcher after completion main java thread. + */ +__declspec(dllexport) void preloadStop() +{ + AwtToolkit::GetInstance().GetPreloadThread().Terminate(false); +} + +} + + /************************************************************************ * Toolkit native methods */ diff -r 7d8d9506b4ee -r 3f92ea1ffcac jdk/src/windows/native/sun/windows/awt_Toolkit.h --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.h Wed Oct 20 14:41:39 2010 +0900 +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.h Wed Oct 20 15:08:39 2010 +0400 @@ -465,6 +465,151 @@ void InstallMouseLowLevelHook(); void UninstallMouseLowLevelHook(); + + +/* AWT preloading (early Toolkit thread start) + */ +public: + /* Toolkit preload action class. + * Preload actions should be registered with + * AwtToolkit::getInstance().GetPreloadThread().AddAction(). + * AwtToolkit thread calls InitImpl method at the beghining + * and CleanImpl(false) before exiting for all registered actions. + * If an application provides own Toolkit thread + * (sun.awt.windows.WToolkit.embeddedInit), the thread calls Clean(true) + * for each action. + */ + class PreloadThread; // forward declaration + class PreloadAction { + friend class PreloadThread; + public: + PreloadAction() : initThreadId(0), pNext(NULL) {} + virtual ~PreloadAction() {} + + protected: + // called by PreloadThread or as result + // of EnsureInited() call (on Toolkit thread!). + virtual void InitImpl() = 0; + + // called by PreloadThread (before exiting). + // reInit == false: normal shutdown; + // reInit == true: PreloadThread is shutting down due external + // Toolkit thread was provided. + virtual void CleanImpl(bool reInit) = 0; + + public: + // Initialized the action on the Toolkit thread if not yet initialized. + bool EnsureInited(); + + // returns thread ID which the action was inited on (0 if not inited) + DWORD GetInitThreadID(); + + // Allows to deinitialize action earlier. + // The method must be called on the Toolkit thread only. + // returns true on success, + // false if the action was inited on other thread. + bool Clean(); + + private: + unsigned initThreadId; + // lock for Init/Clean + CriticalSection initLock; + + // Chain support (for PreloadThread) + PreloadAction *pNext; // for action chain used by PreloadThread + void SetNext(PreloadAction *pNext) { this->pNext = pNext; } + PreloadAction *GetNext() { return pNext; } + + // wrapper for AwtToolkit::InvokeFunction + static void InitWrapper(void *param); + + void Init(); + void Clean(bool reInit); + + }; + + /** Toolkit preload thread class. + */ + class PreloadThread { + public: + PreloadThread(); + ~PreloadThread(); + + // adds action & start the thread if not yet started + bool AddAction(PreloadAction *pAction); + + // sets termination flag; returns true if the thread is running. + // wrongThread specifies cause of the termination: + // false means termination on the application shutdown; + // wrongThread is used as reInit parameter for action cleanup. + bool Terminate(bool wrongThread); + bool InvokeAndTerminate(void(_cdecl *fn)(void *), void *param); + + // waits for the the thread completion; + // use the method after Terminate() only if Terminate() returned true + INLINE void Wait4Finish() { + ::WaitForSingleObject(hFinished, INFINITE); + } + + INLINE unsigned GetThreadId() { + CriticalSection::Lock lock(threadLock); + return threadId; + } + INLINE bool IsWrongThread() { + CriticalSection::Lock lock(threadLock); + return wrongThread; + } + + private: + // data access lock + CriticalSection threadLock; + + // the thread status + enum Status { + None = -1, // initial + Preloading = 0, // preloading in progress + RunningToolkit, // Running as Toolkit thread + Cleaning, // exited from Toolkit thread proc, cleaning + Finished // + } status; + + // "wrong thread" flag + bool wrongThread; + + // thread proc (calls (this)param->ThreadProc()) + static unsigned WINAPI StaticThreadProc(void *param); + unsigned ThreadProc(); + + INLINE void AwakeThread() { + ::SetEvent(hAwake); + } + + // if threadId != 0 -> we are running + unsigned threadId; + // ThreadProc sets the event on exit + HANDLE hFinished; + // ThreadProc waits on the event for NewAction/Terminate/InvokeAndTerminate + HANDLE hAwake; + + // function/param to invoke (InvokeAndTerminate) + // if execFunc == NULL => just terminate + void(_cdecl *execFunc)(void *); + void *execParam; + + // action chain + PreloadAction *pActionChain; + PreloadAction *pLastProcessedAction; + + // returns next action in the list (NULL if no more actions) + PreloadAction* GetNextAction(); + + }; + + INLINE PreloadThread& GetPreloadThread() { return preloadThread; } + +private: + PreloadThread preloadThread; + };