SUGGESTED FIX
The previous version of the fix has one disadvantage: it will never delete "alive" components during log-off. A better version is available in jdk7:
http://sa.sfbay.sun.com/projects/awt_data/7/6660258/
It simply calls ::DefWindowProc(WM_UNDOCUMNTED_CLIENTSHUTDOWN) without entering into self->WindowProc so as to avoid considering "self" as "alive" component in secondary message pump later.
|
|
|
SUGGESTED FIX
here's the diffs for jdk7:
$ sccs diffs -C awt_Toolkit.h
------- awt_Toolkit.h -------
*** /tmp/sccs.sAA0eg 2008-02-19 12:14:51.000000000 +0300
--- awt_Toolkit.h 2008-02-18 14:04:10.000000000 +0300
***************
*** 387,392 ****
--- 387,393 ----
BOOL m_verbose;
BOOL m_isActive; // set to FALSE at beginning of Dispose
BOOL m_isDisposed; // set to TRUE at end of Dispose
+ BOOL m_isSessionEnded;
BOOL m_vmSignalled; // set to TRUE if QUERYENDSESSION has successfully
// raised SIGTERM
$ sccs diffs -C awt_Toolkit.cpp
------- awt_Toolkit.cpp -------
*** /tmp/sccs.vz1qMh 2008-02-19 12:15:16.000000000 +0300
--- awt_Toolkit.cpp 2008-02-18 15:26:01.000000000 +0300
***************
*** 331,336 ****
--- 331,337 ----
m_verbose = FALSE;
m_isActive = TRUE;
m_isDisposed = FALSE;
+ m_isSessionEnded = FALSE;
m_vmSignalled = FALSE;
***************
*** 681,694 ****
}
case WM_AWT_DELETEOBJECT: {
AwtObject *p = (AwtObject *)wParam;
if (p->CanBeDeleted()) {
// all the messages for this component are processed, so
// it can be deleted
delete p;
! } else {
// postpone deletion, waiting for all the messages for this
! // component to be processed
! AwtToolkit::GetInstance().PostMessage(WM_AWT_DELETEOBJECT, wParam, (LPARAM)0);
}
return 0;
}
--- 682,698 ----
}
case WM_AWT_DELETEOBJECT: {
AwtObject *p = (AwtObject *)wParam;
+ AwtToolkit& tk = AwtToolkit::GetInstance();
+
if (p->CanBeDeleted()) {
// all the messages for this component are processed, so
// it can be deleted
delete p;
! } else if (!tk.m_isSessionEnded) {
// postpone deletion, waiting for all the messages for this
! // component to be processed; skipping the deletion during
! // shutdown to exit gracefully (6660258)
! tk.PostMessage(WM_AWT_DELETEOBJECT, wParam, (LPARAM)0);
}
return 0;
}
***************
*** 936,941 ****
--- 940,946 ----
// Keep pumping messages until the shutdown sequence halts the VM,
// or we exit the MessageLoop because of a WM_QUIT message
AwtToolkit& tk = AwtToolkit::GetInstance();
+ tk.m_isSessionEnded = TRUE;
// if WM_QUERYENDSESSION hasn't successfully raised SIGTERM
// we ignore the ENDSESSION message
|
|
|
EVALUATION
We shouldn't postpone component deletion during shutdown to terminate application conveniently. MSDN for WM_ENDSESSION: "The application need not call the DestroyWindow or PostQuitMessage function when the session is ending". So I believe that we may just skip component deletion and session will exit immediately.
|
|
|
WORK AROUND
2. Use java.exe instead of javaw.exe
With java.exe, we do not experience the issue you have reported. However,
the java.exe will show the command prompt and direct all the sysout/syserr
to the command prompt. User can run his/her application with redirection:
$> java <app> >> sysout.txt
Therefore, all the output will be directed to the sysout.txt file.
|
|
|
WORK AROUND
1. Add -Xrs in Java runtime
By adding the -Xrs flag, it reduces the OS signals used by JVM when shutting
down an applications.
|
|
|
EVALUATION
There are special Windows messages that are sent to application when user chooses to end the session, these messages are WM_QUERYENDSESSION and WM_ENDSESSION. In response to the messages AWT initiates the shutdown procedure, in particular, it disposes the toolkit object and starts secondary message loop to delete the AWT components that weren't deleted before. In order to delete the objects there is custom WM_AWT_DELETEOBJECT message that is sent to the toolkit object and if the objects are ready to be deleted then the deletion will immediately happen. A component can't be deleted sometimes if the component handles another message. In this case, the WM_AWT_DELETEOBJECT message is posted to the toolkit object again to delete the component later.
I'm running simple testcase (just an empty frame) using javaw.exe, then I'm trying to logout. The WM_[QUERY]ENDSESSION messages come to the toolkit object, as result of the WM_ENDSESSION message the toolkit thread enters into the secondary dispose loop and it never exit the loop. The only message I'm seeing in this loop is the WM_AWT_DELETEOBJECT message, the toolkit thread repeatedly tries to delete the component (frame) but the component handles another message. The message that the component handles has 0x003b identifier, it seems like this is MS undocumented message. The message is sent to application when user ends the session. The component just calls default window procedure for the message and then the default window procedure initiates the WM_QUERYENDSESSION, WM_ENDSESSION messages.
In short, the toolkit thread repeatedly tries to dispose a component (in WndProc, WM_ENDSESSION) whereas the component handles MS shutdown message (waits in ::DefWindowProc that initiated the WM_ENDSESSION), this follows to the endless secondary loop.
|
|
|
EVALUATION
The problem can be reproduced only with javaw, not java, and only starting from 5.0u14. An interesting thing is that 7.0-b21 also has the same problem, but not 6uX.
|
|
|
EVALUATION
This bug is a regression of 6480378. If I delete the message loop introduced in this fix to AwtToolki::Dispose() method, javaw starts exiting correctly. I suspect this new problem is similar to what reported in 6513421.
|
|
|
|