[Once again, this is an not an RMI but an ORB bug, but there is no category to report it against].
An ORB that is servicing an outgoing call does not block on #shutdown(true). Instead the shutdown call returns immediately. This is against the specification. In addition, when the call returns the client thread does not notice. It remains stuck in CorbaResponseWaitingRoomImpl#waitForResponse.
One threadpool thread "p: default-threadpool; w: Idle" is leaked in addition.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached test program. It sets up a client and a server orb; the client calls a longer operation on the server (in an own thread) ; shuts down the client orb and the server orb.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Shutting down the client should block until the server operation completes. The program should terminate then.
ACTUAL -
Shutting down the client does not block. The client call never returns; the VM does not terminate.
Output:
server operation starts
Shutting down client
Shut down client
Shutting down server
server operation ends
Shut down server
Program should terminate now; running threads: [Thread p: default-threadpool; w: Idle (Id = 12) TIMED_WAITING com.sun.corba.se.impl.orbutil.threadpool.WorkQueueImpl@1551f60, Thread Thread-3 (Id = 11) WAITING java.lang.Object@17ee8b8, Thread Monitor Ctrl-Break (Id = 7) RUNNABLE null, Thread Signal Dispatcher (Id = 4) RUNNABLE null, Thread Finalizer (Id = 3) WAITING java.lang.ref.ReferenceQueue$Lock@e0b6f5, Thread Reference Handler (Id = 2) WAITING java.lang.ref.Reference$Lock@10bc49d, Thread main (Id = 1) RUNNABLE null]
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/*
* Copyright (c) 2005 Matthias Ernst, Hamburg. All rights reserved.
*/
package test;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CORBA.Object;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.portable.*;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
import org.omg.PortableServer.POAManagerPackage.AdapterInactive;
import org.omg.PortableServer.POAPackage.ObjectNotActive;
import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;
import org.omg.PortableServer.Servant;
import sun.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.Arrays;
public class TigerORB {
public static void main(String[] args) throws InvalidName, ServantAlreadyActive, WrongPolicy, ObjectNotActive, AdapterInactive, InterruptedException {
final ORB server = ORB.init(args, System.getProperties());
final POA poa = POAHelper.narrow(server.resolve_initial_references("RootPOA"));
poa.the_POAManager().activate();
final MyServant servant = new MyServant();
final byte[] oid = poa.activate_object(servant);
final Object object = poa.id_to_reference(oid);
final String ior = server.object_to_string(object);
final ORB client = ORB.init(args, System.getProperties());
final ObjectImpl stub = (ObjectImpl) client.string_to_object(ior);
new Thread() {
public void run() {
try {
final OutputStream request = stub._request("callya", true);
stub._invoke(request);
System.out.println("Call returned");
} catch (ApplicationException e) {
e.printStackTrace(); // throw (e instanceof RuntimeException) ? (RuntimeException)e : new RuntimeException(e);
} catch (RemarshalException e) {
e.printStackTrace(); // throw (e instanceof RuntimeException) ? (RuntimeException)e : new RuntimeException(e);
}
}
}.start();
Thread.sleep(1000);
System.out.println("Shutting down client");
client.shutdown(true);
client.destroy();
System.out.println("Shut down client");
System.out.println("Shutting down server");
server.shutdown(true);
server.destroy();
System.out.println("Shut down server");
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.out.println("Program should terminate now; running threads: "+Arrays.asList(threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds())));
}
static class MyServant extends Servant implements InvokeHandler {
private static final String[] INTERFACES = new String[] { "type:body" };
public String[] _all_interfaces(POA poa, byte[] objectId) {
return INTERFACES;
}
public OutputStream _invoke(String method, InputStream input, ResponseHandler handler) throws SystemException {
System.out.println("server operation starts");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println("server operation ends");
return handler.createReply();
}
}
}
---------- END SOURCE ----------