JDK-4323062 : Any Windows NT Service embedding Java VM aborts, when user logs out from Windows
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 1.2.2,1.2.2_006,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_2.3,windows_nt,windows_2000
  • CPU: generic,x86
  • Submitted: 2000-03-18
  • Updated: 2001-07-30
  • Resolved: 2000-11-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.3.0_04 04Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
   IHAC with a NT Service program which starts a Java program. The java
 program is a simple program with a server socket waiting to accept socket
 connections. The program is installed and everything works fine until the user
 decides to log off. Since the Java program is installed through the NT Service,
 the program should continue to work even when the user logs out of the
 system. But on the contrary, the program goes into an unstable state and the
 program hangs. I have enclosed the stack trace which I managed to capture by
 making the NT Service interact with the desktop, so we get to see the console.

 This problem does not occur with JDK1.1.x. This happens only for JDK1.2 and
 greater versions. The Java thread dump and testcase TestNTSvc.tar.Z is
 in the attachments.
 

Follow these instructions to reproduce the problems:
SOURCE MODIFICATION
=============================================================
1)In the clienttest.java file edit line 16:
   s = new Socket("sworks.eng.sun.com",7990);
  with your test system's host address. Save and recompile. 


INSTRUCTIONS FOR INSTALLING SERVICE ON WINDOW NT 4.0
==============================================================

1. Extract the contents of the zip file to say C:\
2. Assuming this, you would now have a directory C:\testntsvc
3. Create an "System Variable" TEST_ROOT in Environment tab of the System
   Properties from the "Control Panel" Settings
and set C:\testntsvc
to
   TEST_ROOT.
4. Append C:\testntsvc to your classpath settings in control panel and also 
   make sure your CLASSPATH is a "System Variable". 
5. Go to DOS command prompt and go to the directory c:\testntsvc
6. Type TestNTSvc -install to install the NTService.
7. Now go to your control panel settings and click on the "Services"
   icon to see if the NT Service "TestNTSvc" is installed.
8. If it has not been installed please contact me at ###@###.###
or 650 526 3336.
9. If it has been installed, then select the "TestNTSvc"
in the services window, click on the button "Startup" and set
the "StartUp Type" to Manual(from Automatic). 
Also check the checkbox for "Allow Service to interact with the Desktop".
10. Now  click on OK Button and close the control panel settings.
11. Now ensure that you have installed JDK1.1.6, JDK1.1.7b and Java2 on your 
	NT Workstation.
12. Open the file "cmdscripts.cfg" file in C:\testntsvc, and update your
directory path for the various jre vms. You can comment all the lines
except the line which you intend to invoke a particular JVM, so for example
you intend to run jre1.2.2, then the following would be the text in the
file cmdscripts.cfg file:

================================================================================
adm=d:/jdk1.2.2/jre/bin/java -mx256m -DTEST_ROOT=%TEST_ROOT% testserver
#adm=f:/jdk1.1.7b/bin/java -mx256m -classpath %classpath%;f:/testntsvc -DTEST_ROOT=%TEST_ROOT% testserver
#adm=f:/jdk1.1.7b/bin/jre -mx256m -cp f:/testntsvc -DTEST_ROOT=%TEST_ROOT% testserver
adm=f:/jdk1.1.6/bin/jre -cp f:/testntsvc -DTEST_ROOT=%TEST_ROOT% testserver
#adm=f:/jdk1.1.6/bin/java -classpath %classpath%;f:/testntsvc -DTEST_ROOT=%TEST_ROOT% testserver
================================================================================
13. Save the file and close it.
14. Reboot your workstation so that the classpath and the new "System
variables" comes into effect.
15. After booting go to the control panel.
16. Go to the services panel in control panel and
start the NT Service "TestNTSvc". You should now see the Java console
for d:/jdk1.2.2/bin/jre with the statement "Getting Connected" being printed
in the console.

17. Run the Java test program testclient.java on the command prompt,
by typing in at the command prompt c:\testntsvc>java testclient
18. The program works and  exits normally after printing the statements
"Creating a Socket", "Created the client Socket" on the console. This 
is what a remote client system would see when accessing the Server service.

19. Now try logging off the NT Workstation and you will see in the Java console
    that the JVM dumps a Java thread trace and the service hangs unresponsive
    when you log back in.



Name: rlT66838			Date: 03/29/2000


java version "1.3.0rc2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc2-Y)
Java HotSpot(TM) Client VM (build 1.3.0rc2-Y, mixed mode)


I'm writing NT-service by JDK1.3 (and some C codes).

1.NT-service start by manual. (check "System Account")
2.logoff

...then, NT-service(running JVM in service) stop process.

I hope, cancel shutdown JVM.
(Review ID: 103003)
======================================================================

Name: rlT66838			Date: 04/04/2000


java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)

Using ServiceInstaller 1.1 (http://www.kcmultimedia.com/smaster) install a
simple Java app as a service that outputs some trivial data to a file every
10 seconds.

Here's the simple demo service:

import java.io.*;
import java.util.*;


public class Test2
{
    public static void main(String[] args)
    {

        Date now;
        PrintWriter out;

        try{

            

            while(true){

                now = new Date();
                out = new PrintWriter(new FileWriter("test2.out",true), true);
                out.println(now.toString());
                out.close();

                Thread.sleep(10000);

            }

        }catch(Exception e){

            System.out.println(e.toString());

        }
    }
}

Start the service from the Control Panel|Services Applet, and check the
contents of the file test2.out, which should append a line showing the
date and time each 10 sec.

Log off, and log back in.

Although NT thinks the service is still running, it is not. You will see
that lines are no longer appended to the file.

This seems to only occur with JDK 1.3 RC1. Under JDK 1.2.2, the test app
keeps running thru the login/logout
(Review ID: 102993)
======================================================================

Name: yyT116575			Date: 11/09/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

I am using JNI 1.2 with JRE 1.3:

Write an NT Service that uses JNI to call the main method of a Java class
(NOTE user.name will be "SYSTEM")

Install & start the service.

Logoff.

Service dies!!!

NOTE:  JRE 1.2 deals with this correctly--when user logs back in the service is
still running.

I have thoroughly checked that my code is not exiting--
    env->CallStaticVoidMethod(jcl, m_methID, m_jobjArr);
never returns & there exists NO System.exit() in my java class.
(Review ID: 111892)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: ladybird FIXED IN: ladybird INTEGRATED IN: 1.3.0_04 ladybird merlin-beta VERIFIED IN: 1.3.0_04
14-06-2004

EVALUATION It seems that this is not a bug. In 1.1.x, runtime.exec create a new process which is a detached process, so the child process will not accept signals (like ctrl+break) from the console of the parent process. That's why in 1.1.x, there's no thread dump. In 1.2.2, runtime.exec create a new attached process, the child process can still accept the signal from the console of the parent process, it's stderr is linked to the parent's pipe. After it received the signal, it sent out thread dump to stderr which redirects to the pipe, as the pipe has a limited capacity, another thread needs to read from the pipe to keep it going, otherwise, the child process appears hang. ###@###.### 2000-04-18 ------------------------------------------------------------ The evaluation above is incorrect; a corrected one follows. A solution exists for this problem; please see the end of this evaluation for it. The problem was caused by the addition of the shutdown hook mechanism to 1.3. Shutdown hooks, compared to the System.runFinalizersOnExit() mechanism, have stronger guarantees regarding when they are run; for example, if the VM is terminated by a Ctrl-C, finalizers will not be executed via runFinalizersOnExit, but shutdown hooks will be run. On Win32, shutdown hooks are implemented by adding a console control handler (see the documentation for SetConsoleCtrlHandler) which, upon seeing a condition like a Control-C or a "user logoff event", raises the termination condition in the VM. This causes the shutdown hooks to be run. Both the shutdown hook mechanism and the Ctrl-Break stack dump require signal-like information. 1.2 implemented the Ctrl-Break stack dump using the POSIX "signal" call on Win32. It turns out (as was noted in the 1.3 VM code by hong.zhang@eng) that this mechanism translates all console events except Ctrl-C into SIGBREAK, which is not sufficient granularity to support both Ctrl-Break and shutdown hooks. This is why the console control handler was added in 1.3. When the VM's console handler receives the CTRL_LOGOFF_EVENT, it informs the rest of the VM of pending termination (thereby causing shutdown hooks to be run) and returns TRUE. According to the MSDN documentation, a return value of TRUE for this event will cause the popup window for process termination to be displayed. It seems that this return value was chosen because the VM is still doing work (running the shutdown hooks asynchronously) after the CTRL_LOGOFF_EVENT is received, and the author thought that returning false would cause the VM to be terminated by the OS while doing this work (as is stated in the MSDN documentation: the system's default handler terminates the process). The MSDN documentation is not specific about the relationship between services and the CTRL_LOGOFF_EVENT. Conceptually, a service runs in the background and should not be associated with any particular user's login session, so one might expect that a service should not be notified of logoff events. However, Win32 does send these events to services. Interestingly, the default console handler for services differs from the default for ordinary console processes; services continue to run after their default handler executes. This is what allows ordinary programs (which either do not install a console handler, or which return FALSE in their console handler for CTRL_LOGOFF_EVENT) to work with, for example, ServiceInstaller. However, it does not seem that there is a way for a process to query whether it is running as a service. If there were, the correct behavior for the VM upon receiving the CTRL_LOGOFF_EVENT if it were running as a service would be to skip running the shutdown hooks, not signal the termination condition to the rest of the VM, and return FALSE. Otherwise, the two possible workarounds are either to provide another command line option to java.exe ("running as a service on Windows NT") or to somehow intercept the CTRL_LOGOFF_EVENTs at the service wrapper level. -- Since the time this bug was filed, its original submitter (who is the author of ServiceInstaller) has released a revised piece of software, called JavaServ, which solves this problem elegantly by using the JNI Invocation API to create a Java VM and installing a console control handler afterwards which intercepts the CTRL_LOGOFF_EVENT and prevents it from being passed to the VM. It also contains other useful features like allowing pure Java programs to receive service control events. JavaServ may be downloaded from http://www.kcmultimedia.com/javaserv/ The comments on the JDC also contain the source code to a similar program. kenneth.russell@eng 2000-08-30 ----------------------------------------------------------------- Since the time the above evaluation was written, other problems have been discovered on Unix platforms involving the interaction between the signals/events the VM now catches to implement the shutdown hook mechanism and application code which may rely on catching those signals; see bug 4345157 and related bugs. It was agreed that it is necessary to have a cross-platform mechanism to inform the VM that the user will take care of calling shutdown hooks (by calling System.exit()), but because he/she either needs to catch SIGINT or similar signals on Unix or run the VM as a service on NT, the VM must not install signal handlers or attempt to catch console control events. It appears that similar reasoning informed the addition of the -Xrs flag in the Classic VM. The -Xrs flag has been reused to support this functionality; if it is specified on Windows NT, for example, java.exe can again be run with the ServiceInstaller wrapper (http://www.kcmultimedia.com/smaster/). This fix will appear in 1.3.1 and be documented in the README. kenneth.russell@eng 2000-11-08
08-11-2000

WORK AROUND The workaround is to create a new thread in the parent process to read the pipe. In this way, the pipe between the parent and child process will not get overflowed. The application will not hang any more. Also if the return value from read is -1, the read thread may be dismissed to retain resources. ###@###.### 2000-06-02
02-06-2000