1 /*
 2  * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
 3  * Copyright (c) 2021, BELLSOFT. All rights reserved.
 4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 5  *
 6  * This code is free software; you can redistribute it and/or modify it
 7  * under the terms of the GNU General Public License version 2 only, as
 8  * published by the Free Software Foundation.
 9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * LoadLibraryUnloadTest ensures all objects (NativeLibrary) are deallocated
27  * when loaded in concurrent mode.
28  */
29 /*
30  * @test
31  * @bug 8266310 8289919 8293282
32  * @summary Checks that JNI_OnLoad is invoked only once when multiple threads
33  *          call System.loadLibrary concurrently, and JNI_OnUnload is invoked
34  *          when the native library is loaded from a custom class loader.
35  * @library /test/lib
36  * @build LoadLibraryUnload p.Class1
37  * @run main/othervm/native LoadLibraryUnloadTest
38  */
39 
40 import jdk.test.lib.Asserts;
41 import jdk.test.lib.process.OutputAnalyzer;
42 
43 import static jdk.test.lib.process.ProcessTools.*;
44 
45 public class LoadLibraryUnloadTest {
46 
47     private static String testClassPath = System.getProperty("test.classes");
48     private static String testLibraryPath = System.getProperty("test.nativepath");
49 
50     private final static long countLines(OutputAnalyzer output, String string) {
51         return output.asLines()
52                      .stream()
53                      .filter(s -> s.contains(string))
54                      .count();
55     }
56 
57     private final static void dump(OutputAnalyzer output) {
58         output.asLines()
59               .stream()
60               .forEach(s -> System.out.println(s));
61     }
62 
63     public static void main(String[] args) throws Throwable {
64 
65         OutputAnalyzer outputAnalyzer = executeCommand(createTestJavaProcessBuilder(
66                 "-Dtest.classes=" + testClassPath,
67                 "-Djava.library.path=" + testLibraryPath,
68                 "LoadLibraryUnload"));
69         dump(outputAnalyzer);
70 
71         Asserts.assertTrue(
72                 countLines(outputAnalyzer, "Native library loaded from Class1.") == 2,
73                 "Native library expected to be loaded in 2 threads.");
74 
75         long refCount = countLines(outputAnalyzer, "Native library loaded.");
76 
77         Asserts.assertTrue(refCount > 0, "Failed to load native library.");
78 
79         System.out.println("Native library loaded in " + refCount + " threads");
80 
81         Asserts.assertTrue(refCount == 1, "Native library is loaded more than once.");
82 
83         Asserts.assertTrue(
84                 countLines(outputAnalyzer, "Native library unloaded.") == refCount,
85                 "Failed to unload native library");
86 
87         Asserts.assertEquals(0, outputAnalyzer.getExitValue(),
88                 "LoadLibraryUnload exit value not zero");
89     }
90 }