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
--- 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 */
--- 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) {
--- 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;
}
--- 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; 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/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;
+
+};
+
--- 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
--- 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 <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/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;
+
};