Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -31,10 +31,9 @@
* may be delayed longer than expected. While this is not a spec violation
* (because there are no timeliness guarantees for any of these garbage
* collection-related events), the user might expect that an unreferenced()
* invocation for an object whose last client has terminated abnorally
* invocation for an object whose last client has terminated abnormally
* should occur on relatively the same time order as the lease value
* granted.
* @author Peter Jones
*
* @library ../../../testlibrary
* @modules java.rmi/sun.rmi.registry
Expand All @@ -45,34 +44,38 @@
* @run main/othervm LeaseCheckInterval
*/

import java.nio.file.Files;
import java.nio.file.Path;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import java.time.Duration;
import java.time.Instant;

public class LeaseCheckInterval implements Remote, Unreferenced {

public static final String BINDING = "LeaseCheckInterval";
// lease expiry time (milliseconds)
private static final long LEASE_VALUE = 10000;
private static final long TIMEOUT = 20000;
// the maximum allowed duration between the lease expiration and
// the Unreferenced.unreferenced() callback method to be invoked
private static final Duration EXPECTED_MAX_DURATION = Duration.ofMinutes(1);

private Object lock = new Object();
private final Object lock = new Object();
private boolean unreferencedInvoked = false;

@Override
public void unreferenced() {
System.err.println("unreferenced() method invoked");
System.err.println("[" + Instant.now() + "] unreferenced() method invoked");
synchronized (lock) {
unreferencedInvoked = true;
lock.notify();
}
}

public static void main(String[] args) throws Exception {

System.err.println("\nRegression test for bug 4285878\n");

/*
* Set the duration of leases granted to a very small value, so that
* we can test if expirations are detected in a roughly comparable
Expand All @@ -90,37 +93,48 @@ public static void main(String[] args) throws Exception {

Registry localRegistry = TestLibrary.createRegistryOnEphemeralPort();
int registryPort = TestLibrary.getRegistryPort(localRegistry);
System.err.println("created local registry");
System.err.println("created local registry on port " + registryPort);

localRegistry.bind(BINDING, obj);
System.err.println("bound remote object in local registry");

Path outputFile = Files.createTempFile(Path.of("."), "4285878-", ".txt");
synchronized (obj.lock) {
System.err.println("starting remote client VM...");
jvm = new JavaVM("SelfTerminator", "-Drmi.registry.port=" +
registryPort, "");
registryPort, outputFile.toAbsolutePath().toString());
// launch the self terminating java application which will lookup
// the bound object and then terminate itself. before terminating
// it will write the time at which it is terminating, into the
// output file
jvm.start();

System.err.println("waiting for unreferenced() callback...");
obj.lock.wait(TIMEOUT);

if (obj.unreferencedInvoked) {
System.err.println("TEST PASSED: " +
"unreferenced() invoked in timely fashion");
do {
System.err.println("waiting for unreferenced() callback...");
obj.lock.wait();
} while (!obj.unreferencedInvoked); // repeat the loop to take into account
// spurious wakeups
Instant waitEndedAt = Instant.now();
// should never happen
assert obj.unreferencedInvoked : "unreference() not invoked";

final String content = Files.readString(outputFile);
System.err.println("content in " + outputFile + ": " + content);
// parse the time, representing the time at which the SelfTerminator
// application termination started
final Instant terminationStartedAt = Instant.parse(content);
final Duration waitDuration = Duration.between(terminationStartedAt,
waitEndedAt);
System.out.println("wait completed in " + waitDuration);
if (waitDuration.compareTo(EXPECTED_MAX_DURATION) > 0) {
throw new RuntimeException("Took unexpectedly long (duration=" +
waitDuration + ") to invoke Unreferenced.unreferenced()," +
" expected max duration=" + EXPECTED_MAX_DURATION);
} else {
throw new RuntimeException(
"TEST FAILED: unreferenced() not invoked after " +
((double) TIMEOUT / 1000.0) + " seconds");
System.err.println("TEST PASSED: unreferenced() invoked in timely" +
" fashion (duration=" + waitDuration + ")");
}
}

} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
throw new RuntimeException(
"TEST FAILED: unexpected exception: " + e.toString());
}
} finally {
if (jvm != null) {
jvm.destroy();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -21,26 +21,38 @@
* questions.
*/

/*
*
*/

import java.nio.file.Files;
import java.nio.file.Path;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.time.Instant;

public class SelfTerminator {

public static void main(String[] args) {
public static void main(String[] args) throws Exception {
try {
log("main() invoked");
Path outputFile = Path.of(args[0]);
log("output file " + outputFile);
int registryPort =
Integer.parseInt(System.getProperty("rmi.registry.port"));
Registry registry =
LocateRegistry.getRegistry("", registryPort);
Remote stub = registry.lookup(LeaseCheckInterval.BINDING);
log("looked up binding, now terminating the process");
// write out the time at which we are terminating the process
Files.writeString(outputFile, Instant.now().toString());
Runtime.getRuntime().halt(0);
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable t) {
log("failure: " + t);
t.printStackTrace();
throw t; // propagate any failures and fail the process
}
}

private static void log(final String message) {
final Instant now = Instant.now();
System.err.println("[" + now + "] " + SelfTerminator.class.getName() + " - " + message);
}
}