Hallo zusammen,
ich hoffe zwar nicht, aber es scheint, als hätte ich einen BUG in SWT gefunden. Zumindest habe ich einen Weg gefunden ihn auszulösen :T
Der Fehler in der Java-Console sieht folgendermaßen aus:
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x77f481bd, pid=3900, tid=2372
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_05-b05 mixed mode)
# Problematic frame:
# C [ntdll.dll+0x81bd]
...gefolgt von endlos vielen "[Too many errors, abort]"-Zeilen und beendet von "An unrecoverable stack overflow has occurred.", was auf eine Endlosschleife hindeutet. Im hs_err_pid*.log-File geht der Fehler auf die SWT-Methode CreateIconIndirect zurück.
Hier mal der Stack-Trace:
Stack: [0x0ae40000,0x0ae80000), sp=0x0ae7f4a8, free space=253k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [ntdll.dll+0x81bd]
C [USER32.dll+0x13bbe]
C [USER32.dll+0x13c70]
C [USER32.dll+0x2768a]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.eclipse.swt.internal.win32.OS.CreateIconIndirect(Lorg/eclipse/swt/internal/win32/ICONINFOI+0
j org.eclipse.swt.widgets.Decorations.createIcon(Lorg/eclipse/swt/graphics/ImageLorg/eclipse/swt/graphics/Image;+340
j org.eclipse.swt.widgets.Decorations.setImages(Lorg/eclipse/swt/graphics/Image;[Lorg/eclipse/swt/graphics/ImageV+244
j org.eclipse.swt.widgets.Decorations.setImage(Lorg/eclipse/swt/graphics/ImageV+28
j com.pictureshuffler.view.main.MainWindow.createShell()V+40
j com.pictureshuffler.view.AbstractView.createView()V+1
j com.pictureshuffler.view.main.MainWindow.createView()V+1
j com.pictureshuffler.view.AbstractView.open()Ljava/lang/Object;+11
j com.pictureshuffler.plugin.core.action.NormalRun$3.run()V+10
j org.eclipse.swt.widgets.Synchronizer.syncExec(Ljava/lang/RunnableV+15
j org.eclipse.swt.widgets.Display.syncExec(Ljava/lang/RunnableV+18
j com.pictureshuffler.plugin.core.action.NormalRun$2.handleEvent(Lorg/eclipse/swt/widgets/EventV+11
j org.eclipse.swt.widgets.EventTable.sendEvent(Lorg/eclipse/swt/widgets/EventV+71
j org.eclipse.swt.widgets.Widget.sendEvent(Lorg/eclipse/swt/widgets/EventV+25
j org.eclipse.swt.widgets.Display.runDeferredEvents()Z+84
j org.eclipse.swt.widgets.Display.readAndDispatch()Z+55
j com.pictureshuffler.view.ViewProvider.run()V+37
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
In der Methode gibt es einen Aufruf, der durchaus das Potential für eine Endlosschleiße hat (Auszug aus swt.c):
Der Aufruf von CreateIconIndirect in der CreateIconIndirect-Methode könnte das Problem entstehen lassen. Da die beiden Methoden aber eine unterschiedliche Anzahl Parameter haben, sollten sie eigentlich verschieden sein. Ich habe allerdings keine andere passende Methode gefunden.
Nun gibt es ja sonst keine Probleme mit dieser Methode, warum aber bei mir? Ich vermute, dass es mit einer eigenen DLL zusammenhängt., n der ich eine Dateisystemüberwachung implementiere. Der Code ist zu großen Teilen von anonytmouse aus http://cboard.cprogramming.com/showthread.php?t=77061 übernommen. Die DLL ist unten angehangen. Interessant ist dabei sicherlich der untere Teil, mit den JNI-Funktionen. Außerdem ist zu erwähnen, dass ich einen Java-Callback aus C++-Code heraus durchführe, der ausgelöst wird, wenn Dateisystemereignisse auftreten und ich mittels "WaitForSingleObjectEx( abortHandle, INFINITE, TRUE );" auf ein Abbruch-Event warte.
Hat einer von Euch vielleicht eine Idee, worin genau das Problem liegen könnte und wie ich es umgehen kann? Oder kennt jemand zufällig eine andere Möglichkeit mit Java Windows-Verzeichnisse zu überwachen, die keine Konflikte mit SWT verursacht (wohl eher nicht)?
Vielen Dank im voraus,
Henrik
Hier besagte DLL:
ich hoffe zwar nicht, aber es scheint, als hätte ich einen BUG in SWT gefunden. Zumindest habe ich einen Weg gefunden ihn auszulösen :T
Der Fehler in der Java-Console sieht folgendermaßen aus:
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x77f481bd, pid=3900, tid=2372
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_05-b05 mixed mode)
# Problematic frame:
# C [ntdll.dll+0x81bd]
...gefolgt von endlos vielen "[Too many errors, abort]"-Zeilen und beendet von "An unrecoverable stack overflow has occurred.", was auf eine Endlosschleife hindeutet. Im hs_err_pid*.log-File geht der Fehler auf die SWT-Methode CreateIconIndirect zurück.
Hier mal der Stack-Trace:
Stack: [0x0ae40000,0x0ae80000), sp=0x0ae7f4a8, free space=253k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [ntdll.dll+0x81bd]
C [USER32.dll+0x13bbe]
C [USER32.dll+0x13c70]
C [USER32.dll+0x2768a]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.eclipse.swt.internal.win32.OS.CreateIconIndirect(Lorg/eclipse/swt/internal/win32/ICONINFOI+0
j org.eclipse.swt.widgets.Decorations.createIcon(Lorg/eclipse/swt/graphics/ImageLorg/eclipse/swt/graphics/Image;+340
j org.eclipse.swt.widgets.Decorations.setImages(Lorg/eclipse/swt/graphics/Image;[Lorg/eclipse/swt/graphics/ImageV+244
j org.eclipse.swt.widgets.Decorations.setImage(Lorg/eclipse/swt/graphics/ImageV+28
j com.pictureshuffler.view.main.MainWindow.createShell()V+40
j com.pictureshuffler.view.AbstractView.createView()V+1
j com.pictureshuffler.view.main.MainWindow.createView()V+1
j com.pictureshuffler.view.AbstractView.open()Ljava/lang/Object;+11
j com.pictureshuffler.plugin.core.action.NormalRun$3.run()V+10
j org.eclipse.swt.widgets.Synchronizer.syncExec(Ljava/lang/RunnableV+15
j org.eclipse.swt.widgets.Display.syncExec(Ljava/lang/RunnableV+18
j com.pictureshuffler.plugin.core.action.NormalRun$2.handleEvent(Lorg/eclipse/swt/widgets/EventV+11
j org.eclipse.swt.widgets.EventTable.sendEvent(Lorg/eclipse/swt/widgets/EventV+71
j org.eclipse.swt.widgets.Widget.sendEvent(Lorg/eclipse/swt/widgets/EventV+25
j org.eclipse.swt.widgets.Display.runDeferredEvents()Z+84
j org.eclipse.swt.widgets.Display.readAndDispatch()Z+55
j com.pictureshuffler.view.ViewProvider.run()V+37
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
In der Methode gibt es einen Aufruf, der durchaus das Potential für eine Endlosschleiße hat (Auszug aus swt.c):
C:
JNIEXPORT jint JNICALL Java_org_eclipse_swt_internal_win32_OS_CreateIconIndirect
(JNIEnv *env, jclass that, jobject arg0)
{
DECL_GLOB(pGlob)
ICONINFO _arg0, *lparg0=NULL;
jint rc;
DEBUG_CALL("CreateIconIndirect\n")
if (arg0) lparg0 = getICONINFOFields(env, arg0, &_arg0, &PGLOB(ICONINFOFc));
rc = (jint)CreateIconIndirect(lparg0);
if (arg0) setICONINFOFields(env, arg0, lparg0, &PGLOB(ICONINFOFc));
return rc;
}
Nun gibt es ja sonst keine Probleme mit dieser Methode, warum aber bei mir? Ich vermute, dass es mit einer eigenen DLL zusammenhängt., n der ich eine Dateisystemüberwachung implementiere. Der Code ist zu großen Teilen von anonytmouse aus http://cboard.cprogramming.com/showthread.php?t=77061 übernommen. Die DLL ist unten angehangen. Interessant ist dabei sicherlich der untere Teil, mit den JNI-Funktionen. Außerdem ist zu erwähnen, dass ich einen Java-Callback aus C++-Code heraus durchführe, der ausgelöst wird, wenn Dateisystemereignisse auftreten und ich mittels "WaitForSingleObjectEx( abortHandle, INFINITE, TRUE );" auf ein Abbruch-Event warte.
Hat einer von Euch vielleicht eine Idee, worin genau das Problem liegen könnte und wie ich es umgehen kann? Oder kennt jemand zufällig eine andere Möglichkeit mit Java Windows-Verzeichnisse zu überwachen, die keine Konflikte mit SWT verursacht (wohl eher nicht)?
Vielen Dank im voraus,
Henrik
Hier besagte DLL:
C:
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include "Win32DirectoryWatcher.h"
// global vars for java-callback-function
jobject globalJavaObject;
jmethodID globalMid;
jobject globalMonitorHandle;
HANDLE abortHandle;
void throwJavaException(JNIEnv *env, LPCTSTR msg, DWORD errorCode)
{
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, msg);
}
typedef void (CALLBACK *FileChangeCallback)(LPTSTR, DWORD, LPARAM);
typedef struct tagDIR_MONITOR
{
OVERLAPPED ol;
HANDLE hDir;
BYTE buffer[32 * 1024];
LPARAM lParam;
DWORD notifyFilter;
BOOL fStop;
FileChangeCallback callback;
} *HDIR_MONITOR;
/*
* Unpacks events and passes them to a user defined callback.
*/
VOID CALLBACK MonitorCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
TCHAR szFile[MAX_PATH];
PFILE_NOTIFY_INFORMATION pNotify;
HDIR_MONITOR pMonitor = (HDIR_MONITOR) lpOverlapped;
size_t offset = 0;
BOOL RefreshMonitoring(HDIR_MONITOR pMonitor);
if (dwErrorCode == ERROR_SUCCESS)
{
do
{
pNotify = (PFILE_NOTIFY_INFORMATION) &pMonitor->buffer[offset];
offset += pNotify->NextEntryOffset;
# if defined(UNICODE)
{
lstrcpynW(szFile, pNotify->FileName,
min(MAX_PATH, pNotify->FileNameLength / sizeof(WCHAR) + 1));
}
# else
{
int count = WideCharToMultiByte(CP_ACP, 0, pNotify->FileName,
pNotify->FileNameLength / sizeof(WCHAR),
szFile, MAX_PATH - 1, NULL, NULL);
szFile[count] = TEXT('\0');
}
# endif
pMonitor->callback(szFile, pNotify->Action, pMonitor->lParam);
} while (pNotify->NextEntryOffset != 0);
}
if (!pMonitor->fStop)
{
RefreshMonitoring(pMonitor);
}
}
/*
* Refreshes the directory monitoring.
*/
BOOL RefreshMonitoring(HDIR_MONITOR pMonitor)
{
return
ReadDirectoryChangesW(pMonitor->hDir, pMonitor->buffer, sizeof(pMonitor->buffer), FALSE,
pMonitor->notifyFilter, NULL, &pMonitor->ol, MonitorCallback);
}
void CALLBACK FileCallback(LPTSTR szFile, DWORD action, LPARAM lParam)
{
JNIEnv *env;
JavaVM *jvm;
jsize count;
if ( !JNI_GetCreatedJavaVMs(&jvm, 1, &count) )
{
if ( !jvm->AttachCurrentThread( (void**) &env, NULL) )
{
env->CallVoidMethod(
globalJavaObject,
globalMid,
env->NewStringUTF(szFile),
(jlong) action );
jvm->DetachCurrentThread();
}
}
}
/*
* Stops monitoring a directory.
*/
void StopMonitoring(HDIR_MONITOR pMonitor)
{
if (pMonitor)
{
pMonitor->fStop = TRUE;
CancelIo(pMonitor->hDir);
if (!HasOverlappedIoCompleted(&pMonitor->ol))
{
SleepEx(5, TRUE);
}
CloseHandle(pMonitor->ol.hEvent);
CloseHandle(pMonitor->hDir);
HeapFree(GetProcessHeap(), 0, pMonitor);
}
}
/*
* Starts monitoring a directory.
*/
HDIR_MONITOR StartMonitoring(LPCTSTR szDirectory, DWORD notifyFilter, FileChangeCallback callback)
{
HDIR_MONITOR pMonitor = (tagDIR_MONITOR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pMonitor));
pMonitor->hDir = CreateFile(szDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if (pMonitor->hDir != INVALID_HANDLE_VALUE)
{
abortHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
pMonitor->ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pMonitor->notifyFilter = notifyFilter;
pMonitor->callback = callback;
if (RefreshMonitoring(pMonitor))
{
return pMonitor;
}
else
{
CloseHandle(pMonitor->ol.hEvent);
CloseHandle(pMonitor->hDir);
}
}
HeapFree(GetProcessHeap(), 0, pMonitor);
return NULL;
}
/* JAVA PART */
/*
* Class: com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher
* Method: stopWatching
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher_startWatchingNative
(JNIEnv *env, jobject obj, jstring path, jlong filter)
{
// save object reference for callback
globalJavaObject = env->NewGlobalRef(obj);
// retrieve method id of callback function
jclass cls = env->GetObjectClass(obj);
globalMid = env->GetMethodID(cls, "fileSystemEventOccured", "(Ljava/lang/String;J)V");
return (jlong) StartMonitoring(
env->GetStringUTFChars (path, NULL),
filter,
FileCallback);
}
/*
* Class: com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher
* Method: catchEvents
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher_catchEvents
(JNIEnv *env, jobject, jlong handle)
{
DWORD result;
BOOL done = FALSE;
while (!done)
{
result = WaitForSingleObjectEx( abortHandle, INFINITE, TRUE );
if (result != WAIT_IO_COMPLETION)
{
done = TRUE;
}
if (result == WAIT_FAILED)
{
throwJavaException(env, "catchEvents: wait failed", GetLastError());
}
}
}
/*
* Class: com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher
* Method: stopWatching
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT void JNICALL Java_com_pictureshuffler_plugin_incomming_localfolder_win32dirwatcher_Win32DirectoryWatcher_stopWatchingNative
(JNIEnv *env, jobject obj, jlong handle)
{
// stop watcher and break up message loop
if (handle)
{
if (!SetEvent(abortHandle))
{
jclass exceptionClass = env->FindClass("java/lang/Exception");
env->ThrowNew(exceptionClass, "Could not set abortEvent to signaled");
}
StopMonitoring( (HDIR_MONITOR) handle );
}
env->DeleteGlobalRef(globalJavaObject);
}