1 /*
   2  * Copyright (c) 2015, 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 }