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
This commit is contained in:
parent
fbe778aead
commit
631d924ad6
@ -51,6 +51,92 @@ static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
|
||||
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 @@ CreateExecutionEnvironment(int *pargc, char ***pargv,
|
||||
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 @@ ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void
|
||||
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 @@ ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void
|
||||
} else {
|
||||
rslt = continuation(args);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_AWT_PRELOAD
|
||||
if (awtPreloaded) {
|
||||
AWTPreloadStop();
|
||||
}
|
||||
#endif /* ENABLE_AWT_PRELOAD */
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
@ -1140,3 +1291,98 @@ InitLauncher(boolean javaw)
|
||||
_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 */
|
||||
|
@ -218,6 +218,8 @@ public class WToolkit extends SunToolkit implements Runnable {
|
||||
|
||||
private static native void postDispose();
|
||||
|
||||
private static native boolean startToolkitThread(Runnable thread);
|
||||
|
||||
public WToolkit() {
|
||||
// Startup toolkit threads
|
||||
if (PerformanceLogger.loggingEnabled()) {
|
||||
@ -231,9 +233,6 @@ public class WToolkit extends SunToolkit implements Runnable {
|
||||
// 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 @@ public class WToolkit extends SunToolkit implements Runnable {
|
||||
*/
|
||||
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 class WToolkit extends SunToolkit implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Thread.currentThread().setPriority(Thread.NORM_PRIORITY+1);
|
||||
boolean startPump = init();
|
||||
|
||||
if (startPump) {
|
||||
|
@ -36,22 +36,6 @@ extern jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
|
||||
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 @@ JNIEXPORT jboolean JNICALL Java_sun_java2d_d3d_D3DGraphicsDevice_initD3D
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ static BOOL bNoHwCheck = (getenv("J2D_D3D_NO_HWCHECK") != NULL);
|
||||
|
||||
D3DPipelineManager *D3DPipelineManager::pMgr = NULL;
|
||||
|
||||
|
||||
D3DPipelineManager * D3DPipelineManager::CreateInstance(void)
|
||||
{
|
||||
if (!IsD3DEnabled() ||
|
||||
@ -179,6 +180,12 @@ void D3DPipelineManager::NotifyAdapterEventListeners(UINT adapter,
|
||||
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 @@ HRESULT D3DPipelineManager::GetD3DContext(UINT adapterOrdinal,
|
||||
*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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "D3DPipeline.h"
|
||||
#include "D3DContext.h"
|
||||
#include "awt_Toolkit.h"
|
||||
|
||||
typedef class D3DPipelineManager *LPD3DPIPELINEMANAGER;
|
||||
|
||||
@ -38,11 +39,15 @@ typedef struct D3DAdapter
|
||||
|
||||
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 @@ private:
|
||||
#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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 @@ extern void DWMResetCompositionEnabled();
|
||||
|
||||
/* 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 @@ HWND AwtToolkit::CreateToolkitWnd(LPCTSTR name)
|
||||
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 @@ BOOL AwtToolkit::Initialize(BOOL localPump) {
|
||||
// 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 @@ BOOL AwtToolkit::Dispose() {
|
||||
// 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 @@ void AwtToolkit::GetWindowRect(HWND hWnd, LPRECT lpRect)
|
||||
::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
|
||||
*/
|
||||
|
@ -465,6 +465,151 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user