1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #define _POSIX_PTHREAD_SEMANTICS // to enable POSIX semantics for certain common APIs 25 26 #include <jni.h> 27 #include <dlfcn.h> 28 #include <limits.h> 29 #include <pthread.h> 30 #include <signal.h> 31 #include <errno.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <stdlib.h> 35 36 void *handle; 37 char *error; 38 char path[PATH_MAX]; 39 40 jint(JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL; 41 42 JavaVM *jvm; 43 44 // method to perform dlclose on an open dynamic library handle 45 void closeHandle() { 46 dlclose(handle); 47 if ((error = dlerror()) != NULL) { 48 fputs("Error occurred while closing handle\n", stderr); 49 } 50 } 51 52 // method to exit with a fail status 53 void fail() { 54 if (handle) { 55 closeHandle(); 56 } 57 exit(1); 58 } 59 60 // method to handle occurred error and fail 61 void handleError(char *messageTitle, char *messageBody) { 62 fprintf(stderr, "%s: %s\n", messageTitle, messageBody); 63 fail(); 64 } 65 66 // method to load the dynamic library libjvm 67 void loadJVM() { 68 char lib[PATH_MAX]; 69 snprintf(lib, sizeof (lib), "%s/lib/server/libjvm.so", path); 70 handle = dlopen(lib, RTLD_LAZY); 71 if (!handle) { 72 handleError(dlerror(), "2"); 73 } 74 fputs("Will load JVM...\n", stdout); 75 76 // find the address of function 77 *(void **) (&jni_create_java_vm) = dlsym(handle, "JNI_CreateJavaVM"); 78 if ((error = dlerror()) != NULL) { 79 handleError(error, "3"); 80 } 81 82 fputs("JVM loaded okay.\n", stdout); 83 } 84 85 // method to get created jvm environment 86 JNIEnv* initJVM() { 87 JNIEnv *env = NULL; 88 JavaVMInitArgs vm_args; 89 JavaVMOption options[1]; 90 jint res; 91 92 options[0].optionString = "-Xrs"; 93 94 vm_args.version = JNI_VERSION_1_2; 95 vm_args.nOptions = 1; 96 vm_args.options = options; 97 vm_args.ignoreUnrecognized = JNI_FALSE; 98 99 fputs("Will create JVM...\n", stdout); 100 101 res = (*jni_create_java_vm)(&jvm, &env, &vm_args); 102 if (res < 0) { 103 handleError("Can't create Java VM", strerror(res)); 104 } 105 106 fputs("JVM created OK!\n", stdout); 107 return env; 108 } 109 110 // method to invoke java method from java class 111 void callJava(JNIEnv *env) { 112 jclass cls; 113 jmethodID mid; 114 jstring jstr; 115 jobjectArray args; 116 117 cls = (*env)->FindClass(env, "Prog"); 118 if (cls == 0) { 119 handleError("FindClass", "Can't find Prog class"); 120 } 121 122 mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V"); 123 if (mid == 0) { 124 handleError("GetStaticMethodID", "Can't find Prog.main"); 125 } 126 127 jstr = (*env)->NewStringUTF(env, "from C!"); 128 if (jstr == 0) { 129 handleError("NewStringUTF", "Out of memory"); 130 } 131 args = (*env)->NewObjectArray(env, 1, 132 (*env)->FindClass(env, "java/lang/String"), jstr); 133 if (args == 0) { 134 handleError("NewObjectArray", "Out of memory"); 135 } 136 (*env)->CallStaticVoidMethod(env, cls, mid, args); 137 138 } 139 140 // method to load, init jvm and then invoke java method 141 void* loadAndCallJava(void* x) { 142 JNIEnv *env; 143 144 fputs("Some thread will create JVM.\n", stdout); 145 loadJVM(); 146 env = initJVM(); 147 148 fputs("Some thread will call Java.\n", stdout); 149 150 callJava(env); 151 152 if ((*jvm)->DetachCurrentThread(jvm) != 0) 153 fputs("Error: thread not detached!\n", stderr); 154 fputs("Some thread exiting.\n", stdout); 155 return env; 156 } 157 158 int main(int argc, char **argv) { 159 JNIEnv *env; 160 sigset_t set; 161 pthread_t thr1; 162 pthread_attr_t attr; 163 size_t ss = 0; 164 int sig; 165 int rc; // return code for pthread_* methods 166 167 // verify input 168 if (argc != 2) { 169 handleError("usage", "a.out jdk_path"); 170 } 171 // copy input jdk path into a char buffer 172 strncpy(path, argv[1], PATH_MAX); 173 // add null termination character 174 path[PATH_MAX - 1] = '\0'; 175 176 fputs("Main thread will set signal mask.\n", stdout); 177 178 // initialize the signal set 179 sigemptyset(&set); 180 // add a number of signals to a signal set 181 sigaddset(&set, SIGPIPE); 182 sigaddset(&set, SIGTERM); 183 sigaddset(&set, SIGHUP); 184 sigaddset(&set, SIGINT); 185 186 // examine and change mask of blocked signal 187 if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL))) { 188 // handle error if occurred 189 handleError("main: pthread_sigmask() error", strerror(rc)); 190 } 191 192 // initializes the thread attributes object with default attribute values 193 if ((rc = pthread_attr_init(&attr))) { 194 // handle error if occurred 195 handleError("main: pthread_attr_init() error", strerror(rc)); 196 } 197 198 ss = 1024 * 1024; 199 // set the stack size attribute of the thread attributes object 200 if ((rc = pthread_attr_setstacksize(&attr, ss))) { 201 // handle error if occurred 202 handleError("main: pthread_attr_setstacksize() error", strerror(rc)); 203 } 204 // get the stack size attribute of the thread attributes object 205 if ((rc = pthread_attr_getstacksize(&attr, &ss))) { 206 // handle error if occurred 207 handleError("main: pthread_attr_getstacksize() error", strerror(rc)); 208 } 209 fprintf(stderr, "Stack size: %zu\n", ss); 210 211 // start a new thread in the calling process, 212 // loadAndCallJava logic is passed as a start_routine argument 213 if ((rc = pthread_create(&thr1, NULL, loadAndCallJava, NULL))) { 214 // handle error if occurred 215 handleError("main: pthread_create() error", strerror(rc)); 216 } 217 218 // initialize the signal set 219 sigemptyset(&set); 220 // add a number of signals to a signal set 221 sigaddset(&set, SIGTERM); 222 sigaddset(&set, SIGHUP); 223 sigaddset(&set, SIGINT); 224 225 fputs("Main thread waiting for signal.\n", stdout); 226 227 do { 228 int err; 229 230 sig = 0; 231 err = sigwait(&set, &sig); 232 if (err != 0) { 233 // print error message if unexpected signal occurred 234 fprintf(stderr, "main: sigwait() error: %s\n", strerror(err)); 235 } else { 236 // print success message and exit if expected signal occurred 237 // this branch generally acts when JVM executes destroy() 238 fprintf(stdout, "main: sigwait() got: %d\nSucceed!\n", sig); 239 exit(0); 240 } 241 } while (sig != SIGTERM && sig != SIGINT); // exit the loop condition 242 243 // join with a terminated thread 244 if ((rc = pthread_join(thr1, NULL))) { 245 // handle error if occurred 246 handleError("main: pthread_join() error", strerror(rc)); 247 } 248 249 // close an open dynamic library handle 250 closeHandle(); 251 fputs("Main thread exiting.\n", stdout); 252 return 0; 253 }