/* * Copyright (c) 2007, 2018, 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. */ #include #include #include #include #include #include #include #include #include /* * This is the main program to test the signal chaining/ handling functionality * See bugs 6277077 and 6414402 */ #define TRUE 1 #define FALSE 0 typedef int boolean; static JNIEnv *env; static JavaVM *vm; // static int sigid = 0; // Define the test pass/ fail codes, may be we can use // nsk/share/native/native_consts.h in future static int TEST_PASSED=0; static int TEST_FAILED=1; // This variable is used to notify whether signal has been received or not. static volatile sig_atomic_t sig_received = 0; static char *mode = 0; static char *scenario = 0; static char *signal_name; static int signal_num = -1; static JavaVMOption *options = 0; static int numOptions = 0; typedef struct { int sigNum; const char* sigName; } signalDefinition; static signalDefinition signals[] = { {SIGINT, "SIGINT"}, {SIGQUIT, "SIGQUIT"}, {SIGILL, "SIGILL"}, {SIGTRAP, "SIGTRAP"}, {SIGIOT, "SIGIOT"}, #ifdef SIGEMT {SIGEMT, "SIGEMT"}, #endif {SIGFPE, "SIGFPE"}, {SIGBUS, "SIGBUS"}, {SIGSEGV, "SIGSEGV"}, {SIGSYS, "SIGSYS"}, {SIGPIPE, "SIGPIPE"}, {SIGALRM, "SIGALRM"}, {SIGTERM, "SIGTERM"}, {SIGUSR1, "SIGUSR1"}, {SIGUSR2, "SIGUSR2"}, #ifdef SIGCLD {SIGCLD, "SIGCLD"}, #endif #ifdef SIGPWR {SIGPWR, "SIGPWR"}, #endif {SIGWINCH, "SIGWINCH"}, {SIGURG, "SIGURG"}, #ifdef SIGPOLL {SIGPOLL, "SIGPOLL"}, #endif {SIGSTOP, "SIGSTOP"}, {SIGTSTP, "SIGTSTP"}, {SIGCONT, "SIGCONT"}, {SIGTTIN, "SIGTTIN"}, {SIGTTOU, "SIGTTOU"}, {SIGVTALRM, "SIGVTALRM"}, {SIGPROF, "SIGPROF"}, {SIGXCPU, "SIGXCPU"}, {SIGXFSZ, "SIGXFSZ"}, #ifdef SIGWAITING {SIGWAITING, "SIGWAITING"}, #endif #ifdef SIGLWP {SIGLWP, "SIGLWP"}, #endif #ifdef SIGFREEZE {SIGFREEZE, "SIGFREEZE"}, #endif #ifdef SIGTHAW {SIGTHAW, "SIGTHAW"}, #endif #ifdef SIGLOST {SIGLOST, "SIGLOST"}, #endif #ifdef SIGXRES {SIGXRES, "SIGXRES"}, #endif {SIGHUP, "SIGHUP"} }; boolean isSupportedSigScenario () { if ( (!strcmp(scenario, "nojvm")) || (!strcmp(scenario, "prepre")) || (!strcmp(scenario, "prepost")) || (!strcmp(scenario, "postpost")) || (!strcmp(scenario, "postpre")) ) { // printf("%s is a supported scenario\n", scenario); return TRUE; } else { printf("ERROR: %s is not a supported scenario\n", scenario); return FALSE; } } boolean isSupportedSigMode () { if ( (!strcmp(mode, "sigset")) || (!strcmp(mode, "sigaction")) ) { // printf("%s is a supported mode\n", mode); return TRUE; } else { printf("ERROR: %s is not a supported mode\n", mode); return FALSE; } } int getSigNumBySigName(const char* sigName) { int signals_len, sigdef_len, total_sigs, i=0; if (sigName == NULL) return -1; signals_len = sizeof(signals); sigdef_len = sizeof(signalDefinition); total_sigs = signals_len / sigdef_len; for (i = 0; i < total_sigs; i++) { // printf("Inside for loop, i = %d\n", i); if (!strcmp(sigName, signals[i].sigName)) return signals[i].sigNum; } return -1; } // signal handler void handler(int sig) { printf("%s: signal handler for signal %d has been processed\n", signal_name, signal_num); sig_received = 1; } // Initialize VM with given options void initVM() { JavaVMInitArgs vm_args; int i =0; jint result; vm_args.nOptions = numOptions; vm_args.version = JNI_VERSION_1_2; vm_args.ignoreUnrecognized = JNI_FALSE; vm_args.options = options; /* try hardcoding options JavaVMOption option1[2]; option1[0].optionString="-XX:+PrintCommandLineFlags"; option1[1].optionString="-Xrs"; */ vm_args.options=options; vm_args.nOptions=numOptions; // Print the VM options in use printf("initVM: numOptions = %d\n", vm_args.nOptions); for (i = 0; i < vm_args.nOptions; i++) { printf("\tvm_args.options[%d].optionString = %s\n", i, vm_args.options[i].optionString); } // Initialize VM with given options result = JNI_CreateJavaVM( &vm, (void **) &env, &vm_args ); // Did the VM initialize successfully ? if (result != 0) { printf("ERROR: cannot create Java VM.\n"); exit(TEST_FAILED); } (*vm)->AttachCurrentThread(vm, (void **) &env, (void *) 0); printf("initVM: JVM started and attached\n"); } // Function to set up signal handler void setSignalHandler() { int retval = 0 ; if (!strcmp(mode, "sigaction")) { struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; retval = sigaction(signal_num, &act, 0); if (retval != 0) { printf("ERROR: failed to set signal handler using function %s, error=%s\n", mode, strerror(errno)); exit(TEST_FAILED); } } // end - dealing with sigaction else if (!strcmp(mode, "sigset")) { sigset(signal_num, handler); } // end dealing with sigset printf("%s: signal handler using function '%s' has been set\n", signal_name, mode); } // Function to invoke given signal void invokeSignal() { int pid, retval; sigset_t new_set, old_set; pid = getpid(); retval = 0; // we need to unblock the signal in case it was previously blocked by JVM // and as result inherited by child process // (this is at least the case for SIGQUIT in case -Xrs flag is not used). // Otherwise the test will timeout. sigemptyset(&new_set); sigaddset(&new_set, signal_num); sigprocmask(SIG_UNBLOCK, &new_set, &old_set); if (retval != 0) { printf("ERROR: failed to unblock signal, error=%s\n", strerror(errno)); exit(TEST_FAILED); } // send the signal retval = kill(pid, signal_num); if (retval != 0) { printf("ERROR: failed to send signal %s, error=%s\n", signal_name, strerror(errno)); exit(TEST_FAILED); } // set original mask for the signal retval = sigprocmask(SIG_SETMASK, &old_set, NULL); if (retval != 0) { printf("ERROR: failed to set original mask for signal, error=%s\n", strerror(errno)); exit(TEST_FAILED); } printf("%s: signal has been sent successfully\n", signal_name); } // Usage function void printUsage() { printf("Usage: sigtest -sig {signal_name} -mode {signal | sigset | sigaction } -scenario {nojvm | postpre | postpost | prepre | prepost}> [-vmopt jvm_option] \n"); printf("\n"); exit(TEST_FAILED); } // signal handler BEFORE VM initialization AND // Invoke signal BEFORE VM exits void scen_prepre() { setSignalHandler(); initVM(); invokeSignal(); (*vm)->DestroyJavaVM(vm); } // signal handler BEFORE VM initialization AND // Invoke signal AFTER VM exits void scen_prepost() { setSignalHandler(); initVM(); (*vm)->DestroyJavaVM(vm); invokeSignal(); } // signal handler AFTER VM initialization AND // Invoke signal BEFORE VM exits void scen_postpre() { initVM(); setSignalHandler(); invokeSignal(); (*vm)->DestroyJavaVM(vm); } // signal handler AFTER VM initializationAND // Invoke signal AFTER VM exits void scen_postpost() { initVM(); setSignalHandler(); (*vm)->DestroyJavaVM(vm); invokeSignal(); } // signal handler with no JVM in picture void scen_nojvm() { setSignalHandler(); invokeSignal(); } void run() { // print the current scenario if (!strcmp(scenario, "postpre")) scen_postpre(); else if (!strcmp(scenario, "postpost")) scen_postpost(); else if (!strcmp(scenario, "prepre")) scen_prepre(); else if (!strcmp(scenario, "prepost")) scen_prepost(); else if (!strcmp(scenario, "nojvm")) scen_nojvm(); } // main main int main(int argc, char **argv) { int i=0, j; signal_num = -1; signal_name = NULL; // Parse the arguments and find out how many vm args we have for (i=1; i= argc ) { printUsage(); } signal_name = argv[i]; } else if (!strcmp(argv[i], "-mode")) { i++; if ( i >= argc ) { printUsage(); } mode = argv[i]; } else if (!strcmp(argv[i], "-scenario")) { i++; if ( i >= argc ) { printUsage(); } scenario = argv[i]; } else if (!strcmp(argv[i], "-vmopt")) { i++; if ( i >= argc ) { printUsage(); } numOptions++; } else { printUsage(); } } if ( !isSupportedSigScenario() || !isSupportedSigMode() ) { printUsage(); } // get signal number by it's name signal_num = getSigNumBySigName(signal_name); if (signal_num == -1) { printf("%s: unknown signal, perhaps is not supported on this platform, ignore\n", signal_name); exit(TEST_PASSED); } j = 0; // Initialize given number of VM options if (numOptions > 0) { options = (JavaVMOption *) malloc(numOptions * sizeof(JavaVMOption)); for (i=0; i= argc ) { printUsage(); } options[j].optionString = argv[i]; j++; } } } // do signal invocation printf("%s: start testing: signal_num=%d, mode=%s, scenario=%s\n", signal_name, signal_num, mode, scenario); run(); while (!sig_received) { sleep(1); printf("%s: waiting for getting signal 1sec ...\n", signal_name); } printf("%s: signal has been received\n", signal_name); free(options); return (sig_received ? TEST_PASSED : TEST_FAILED); }