提交 3eff6911 编写于 作者: A amenkov

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
上级 86114362
......@@ -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;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册