From 9b431c9bba018a2dd2bb6850cfd674b51207bf49 Mon Sep 17 00:00:00 2001
Date: Thu, 19 Oct 2023 01:37:43 +0000
Subject: [PATCH 3/5] change value of GCLockerRetryAllocationCount from 2 to
 1000 to avoid OOM

---
 hotspot/src/share/vm/runtime/globals.hpp      |   2 +-
 .../g1/TestGcLockerEvacFailureThreaded.java   | 124 ++++++++++++++++++
 2 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 hotspot/test/gc/g1/TestGcLockerEvacFailureThreaded.java

diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index fdd9db149..65806a475 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -1575,7 +1575,7 @@ class CommandLineFlags {
           "How much the GC can expand the eden by while the GC locker "     \
           "is active (as a percentage)")                                    \
                                                                             \
-  diagnostic(uintx, GCLockerRetryAllocationCount, 2,                        \
+  diagnostic(uintx, GCLockerRetryAllocationCount, 1000,                     \
           "Number of times to retry allocations when "                      \
           "blocked by the GC locker")                                       \
                                                                             \
diff --git a/hotspot/test/gc/g1/TestGcLockerEvacFailureThreaded.java b/hotspot/test/gc/g1/TestGcLockerEvacFailureThreaded.java
new file mode 100644
index 000000000..74accd951
--- /dev/null
+++ b/hotspot/test/gc/g1/TestGcLockerEvacFailureThreaded.java
@@ -0,0 +1,124 @@
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.zip.GZIPOutputStream;
+
+import com.oracle.java.testlibrary.ProcessTools;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+/*
+ * @test TestGcLockerEvacFailureThreaded.java
+ * @bug 8048556 8137099
+ * @summary Ensure that GCLocker does not cause early program termination.
+ * @key gc
+ * @library /testlibrary
+ */
+public class TestGcLockerEvacFailureThreaded {
+  public static void main(String[] args) throws Exception {
+    System.out.println("Beginning test\n");
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
+                                                              "-Xmx64m",
+                                                              TestGcLocker.class.getName());
+
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+    System.out.println("Output:\n" + output.getOutput());
+
+    output.shouldNotContain("java.lang.OutOfMemoryError");
+    output.shouldHaveExitValue(0);
+  }
+
+  /**
+   * Tests whether GCLocker terminates the application when forced to spin multiple times.
+   * We cause a long-running native call during which a GC is invoked by another thread.
+   */
+  static class TestGcLocker {
+
+    private static int gzipItemLengthBytes = 10500;
+    private static int nGzipItems = 3500;
+    private static int aliveDataItems = (int) (nGzipItems * 0.7);
+
+    private static int nThreads = 500;
+    private static int loopSize = 1000;
+
+    private static List<byte[]> dataToBeGzipped = new ArrayList<>(nGzipItems);
+
+    private static List<byte[]> aliveData = new ArrayList<>(aliveDataItems);
+
+    private static Random randomGenerator = new Random();
+
+    private static volatile boolean cont = true;
+
+    private static void createData(int gzipItemLengthBytes, int nGzipItems) throws IOException {
+	for (int gzipDataIndex = 0; gzipDataIndex < nGzipItems; gzipDataIndex++) {
+	    ByteBuffer buffer = ByteBuffer.allocate(gzipItemLengthBytes);
+	    for (int i = 0; i < gzipItemLengthBytes/4; i++) { // since integer is 4 bytes
+	        int randomInt = randomGenerator.nextInt(100);
+	        buffer.putInt(randomInt);
+	    }
+	    byte[] data = buffer.array();
+	    dataToBeGzipped.add(data);
+	}
+
+	for (int i = 0; i < aliveDataItems; i++) {
+	    aliveData.add(new byte[0]);
+	}
+
+	for (int gzipDataIndex = 0; gzipDataIndex < nGzipItems; gzipDataIndex++) {
+	    native_critical_section(dataToBeGzipped.get(gzipDataIndex));
+	}
+
+    }
+
+    public static void runTest(int loopSize) {
+	try {
+	    int i = 0;
+	    while (cont && (i < loopSize)) {
+	        i++;
+	        try {
+	            native_critical_section(dataToBeGzipped.get(i % nGzipItems));
+	        } catch (OutOfMemoryError e) {
+	            cont = false; //Remove this if you still want to continue after OOME
+	            e.printStackTrace();
+	        }
+	    }
+
+	} catch (IOException e) {
+	    cont = true;
+	    e.printStackTrace();
+	}
+    }
+
+    private static void native_critical_section(byte[] data) throws IOException {
+	try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); GZIPOutputStream gzos = new GZIPOutputStream(bos)) {
+	    gzos.write(data);
+	    gzos.finish();
+	    byte[] compressedData = bos.toByteArray();
+	    int index = randomGenerator.nextInt(aliveDataItems);
+	    aliveData.set(index, compressedData);
+	}
+    }
+
+    public static void main(String[] args) throws InterruptedException, IOException {
+	createData(gzipItemLengthBytes, nGzipItems);
+
+	System.gc(); //This will tell us the resident set size
+
+	for (int i = 0; i < nThreads; i++) {
+	    Thread t = new Thread() {
+	        public void run() {
+	            runTest(loopSize);
+	        }
+	    };
+	    t.start();
+	}
+	System.out.println("Threads started");
+    }
+  }
+}
+
-- 
2.19.1

