8d94626bb3
Rewrote test in Java with a number of improvements and conditional exclusion using make file Reviewed-by: dholmes, ctornqvi, ddmitriev
254 lines
7.0 KiB
C
254 lines
7.0 KiB
C
/*
|
|
* 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;
|
|
}
|