changeset 2963:1f45c4c1f3a7

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
author amenkov
date Wed, 20 Oct 2010 15:08:39 +0400
parents 4a29a9ff158c
children db2bc901c702
files src/windows/bin/java_md.c src/windows/classes/sun/awt/windows/WToolkit.java src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp src/windows/native/sun/java2d/d3d/D3DPipelineManager.h src/windows/native/sun/java2d/windows/WindowsFlags.cpp src/windows/native/sun/windows/awt_Toolkit.cpp src/windows/native/sun/windows/awt_Toolkit.h
diffstat 8 files changed, 898 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/windows/bin/java_md.c	Wed Oct 20 14:41:39 2010 +0900
+++ b/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 */
--- a/src/windows/classes/sun/awt/windows/WToolkit.java	Wed Oct 20 14:41:39 2010 +0900
+++ b/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) {
--- a/src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp	Wed Oct 20 14:41:39 2010 +0900
+++ b/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;
 }
--- a/src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp	Wed Oct 20 14:41:39 2010 +0900
+++ b/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; i<adapterCount; i++) {
+            pAdapterIniters[i].setAdapter(i);
+            AwtToolkit::GetInstance().GetPreloadThread().AddAction(&pAdapterIniters[i]);
+        }
+    }
+}
+
+void D3DInitializer::CleanImpl(bool reInit)
+{
+    J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DInitializer::CleanImpl (%s)",
+                                    reInit ? "RELAUNCH" : "normal");
+    D3DPipelineManager::DeleteInstance();
+    if (bComInitialized) {
+        CoUninitialize();
+    }
+}
+
+
+void D3DInitializer::D3DAdapterInitializer::InitImpl()
+{
+    J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DAdapterInitializer::InitImpl(%d) started", adapter);
+
+    D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance();
+    if (pMgr == NULL) {
+        return;
+    }
+
+    D3DContext *pd3dContext;
+    pMgr->GetD3DContext(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;
+}
+
+}
+
--- a/src/windows/native/sun/java2d/d3d/D3DPipelineManager.h	Wed Oct 20 14:41:39 2010 +0900
+++ b/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;
+
+};
+
--- a/src/windows/native/sun/java2d/windows/WindowsFlags.cpp	Wed Oct 20 14:41:39 2010 +0900
+++ b/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
--- a/src/windows/native/sun/windows/awt_Toolkit.cpp	Wed Oct 20 14:41:39 2010 +0900
+++ b/src/windows/native/sun/windows/awt_Toolkit.cpp	Wed Oct 20 15:08:39 2010 +0400
@@ -26,6 +26,7 @@
 #include "awt.h"
 #include <signal.h>
 #include <windowsx.h>
+#include <process.h>
 
 //#if defined(_DEBUG) && defined(_MSC_VER) && _MSC_VER >= 1000
 //#include <crtdbg.h>
@@ -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
  */
--- a/src/windows/native/sun/windows/awt_Toolkit.h	Wed Oct 20 14:41:39 2010 +0900
+++ b/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;
+
 };