This commit is contained in:
Dmitry Dmitriev 2015-11-20 17:16:58 +00:00
commit ae97daa5e1
4 changed files with 402 additions and 1 deletions

View File

@ -51,7 +51,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
# Add conditional directories here when needed.
ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc \
$(HOTSPOT_TOPDIR)/test/runtime/ThreadSignalMask
endif
ifeq ($(TOOLCHAIN_TYPE), solstudio)

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2015, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class Prog {
public static void main(String args[]) {
System.out.println("Java class invoked: " + args[0]);
}
}

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2015, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
import jdk.test.lib.Asserts;
/*
* @test
* @key cte_test
* @bug 4345157
* @summary JDK 1.3.0 alters thread signal mask
* @requires (os.simpleArch == "sparcv9")
* @library /testlibrary
* @compile Prog.java
* @run main/native ThreadSignalMask
*/
public class ThreadSignalMask {
public static void main(String args[]) throws Exception {
String testClasses = getSystemProperty("test.classes");
String testNativePath = getSystemProperty("test.nativepath");
String testJdk = getSystemProperty("test.jdk");
Path currentDirPath = Paths.get(".");
Path classFilePath = Paths.get(testClasses,
Prog.class.getSimpleName() + ".class");
// copy Prog.class file to be invoked from native
Files.copy(classFilePath,
currentDirPath.resolve(Prog.class.getSimpleName() + ".class"),
StandardCopyOption.REPLACE_EXISTING);
Path executableFilePath = Paths.get(testNativePath,
ThreadSignalMask.class.getSimpleName());
Path executableFileLocalPath = currentDirPath.resolve(
ThreadSignalMask.class.getSimpleName());
// copy compiled native executable ThreadSignalMask
Files.copy(executableFilePath,
executableFileLocalPath,
StandardCopyOption.REPLACE_EXISTING);
executableFileLocalPath.toFile().setExecutable(true);
long[] intervalsArray = {2000, 5000, 10000, 20000};
List<String> processArgs = Arrays.asList(
executableFileLocalPath.toString(),
testJdk);
ProcessBuilder pb = new ProcessBuilder(processArgs);
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
int result = 0;
for (long interval : intervalsArray) {
Process p = pb.start();
// sleep for a specified period of time to let native run
sleep(interval);
p.destroy();
// wait for process to finish, get exit value and validate it
result = p.waitFor();
System.out.println("Result = " + result);
if (result == 0) {
break;
}
}
Asserts.assertEquals(result, 0);
}
// Utility method to handle Thread.sleep
private static void sleep(long millis) throws InterruptedException {
System.out.println("Sleep for " + millis);
Thread.sleep(millis);
}
// Utility method to retrieve and validate system properties
private static String getSystemProperty(String propertyName) throws Error {
String systemProperty = System.getProperty(propertyName, "").trim();
System.out.println(propertyName + " = " + systemProperty);
if (systemProperty.isEmpty()) {
throw new Error("TESTBUG: property " + propertyName + " is empty");
}
return systemProperty;
}
}

View File

@ -0,0 +1,253 @@
/*
* Copyright (c) 2015, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#define _POSIX_PTHREAD_SEMANTICS // to enable POSIX semantics for certain common APIs
#include <jni.h>
#include <dlfcn.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void *handle;
char *error;
char path[PATH_MAX];
jint(JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL;
JavaVM *jvm;
// method to perform dlclose on an open dynamic library handle
void closeHandle() {
dlclose(handle);
if ((error = dlerror()) != NULL) {
fputs("Error occurred while closing handle\n", stderr);
}
}
// method to exit with a fail status
void fail() {
if (handle) {
closeHandle();
}
exit(1);
}
// method to handle occurred error and fail
void handleError(char *messageTitle, char *messageBody) {
fprintf(stderr, "%s: %s\n", messageTitle, messageBody);
fail();
}
// method to load the dynamic library libjvm
void loadJVM() {
char lib[PATH_MAX];
snprintf(lib, sizeof (lib), "%s/lib/sparcv9/server/libjvm.so", path);
handle = dlopen(lib, RTLD_LAZY);
if (!handle) {
handleError(dlerror(), "2");
}
fputs("Will load JVM...\n", stdout);
// find the address of function
*(void **) (&jni_create_java_vm) = dlsym(handle, "JNI_CreateJavaVM");
if ((error = dlerror()) != NULL) {
handleError(error, "3");
}
fputs("JVM loaded okay.\n", stdout);
}
// method to get created jvm environment
JNIEnv* initJVM() {
JNIEnv *env = NULL;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
jint res;
options[0].optionString = "-Xrs";
vm_args.version = JNI_VERSION_1_2;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_FALSE;
fputs("Will create JVM...\n", stdout);
res = (*jni_create_java_vm)(&jvm, &env, &vm_args);
if (res < 0) {
handleError("Can't create Java VM", strerror(res));
}
fputs("JVM created OK!\n", stdout);
return env;
}
// method to invoke java method from java class
void callJava(JNIEnv *env) {
jclass cls;
jmethodID mid;
jstring jstr;
jobjectArray args;
cls = (*env)->FindClass(env, "Prog");
if (cls == 0) {
handleError("FindClass", "Can't find Prog class");
}
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
if (mid == 0) {
handleError("GetStaticMethodID", "Can't find Prog.main");
}
jstr = (*env)->NewStringUTF(env, "from C!");
if (jstr == 0) {
handleError("NewStringUTF", "Out of memory");
}
args = (*env)->NewObjectArray(env, 1,
(*env)->FindClass(env, "java/lang/String"), jstr);
if (args == 0) {
handleError("NewObjectArray", "Out of memory");
}
(*env)->CallStaticVoidMethod(env, cls, mid, args);
}
// method to load, init jvm and then invoke java method
void* loadAndCallJava(void* x) {
JNIEnv *env;
fputs("Some thread will create JVM.\n", stdout);
loadJVM();
env = initJVM();
fputs("Some thread will call Java.\n", stdout);
callJava(env);
if ((*jvm)->DetachCurrentThread(jvm) != 0)
fputs("Error: thread not detached!\n", stderr);
fputs("Some thread exiting.\n", stdout);
return env;
}
int main(int argc, char **argv) {
JNIEnv *env;
sigset_t set;
pthread_t thr1;
pthread_attr_t attr;
size_t ss = 0;
int sig;
int rc; // return code for pthread_* methods
// verify input
if (argc != 2) {
handleError("usage", "a.out jdk_path");
}
// copy input jdk path into a char buffer
strncpy(path, argv[1], PATH_MAX);
// add null termination character
path[PATH_MAX - 1] = '\0';
fputs("Main thread will set signal mask.\n", stdout);
// initialize the signal set
sigemptyset(&set);
// add a number of signals to a signal set
sigaddset(&set, SIGPIPE);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
// examine and change mask of blocked signal
if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL))) {
// handle error if occurred
handleError("main: pthread_sigmask() error", strerror(rc));
}
// initializes the thread attributes object with default attribute values
if ((rc = pthread_attr_init(&attr))) {
// handle error if occurred
handleError("main: pthread_attr_init() error", strerror(rc));
}
ss = 1024 * 1024;
// set the stack size attribute of the thread attributes object
if ((rc = pthread_attr_setstacksize(&attr, ss))) {
// handle error if occurred
handleError("main: pthread_attr_setstacksize() error", strerror(rc));
}
// get the stack size attribute of the thread attributes object
if ((rc = pthread_attr_getstacksize(&attr, &ss))) {
// handle error if occurred
handleError("main: pthread_attr_getstacksize() error", strerror(rc));
}
fprintf(stderr, "Stack size: %zu\n", ss);
// start a new thread in the calling process,
// loadAndCallJava logic is passed as a start_routine argument
if ((rc = pthread_create(&thr1, NULL, loadAndCallJava, NULL))) {
// handle error if occurred
handleError("main: pthread_create() error", strerror(rc));
}
// initialize the signal set
sigemptyset(&set);
// add a number of signals to a signal set
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
fputs("Main thread waiting for signal.\n", stdout);
do {
int err;
sig = 0;
err = sigwait(&set, &sig);
if (err != 0) {
// print error message if unexpected signal occurred
fprintf(stderr, "main: sigwait() error: %s\n", strerror(err));
} else {
// print success message and exit if expected signal occurred
// this branch generally acts when JVM executes destroy()
fprintf(stdout, "main: sigwait() got: %d\nSucceed!\n", sig);
exit(0);
}
} while (sig != SIGTERM && sig != SIGINT); // exit the loop condition
// join with a terminated thread
if ((rc = pthread_join(thr1, NULL))) {
// handle error if occurred
handleError("main: pthread_join() error", strerror(rc));
}
// close an open dynamic library handle
closeHandle();
fputs("Main thread exiting.\n", stdout);
return 0;
}