1 /*
   2  * Copyright (c) 2007, 2018, 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 #include <jni.h>
  25 #include <signal.h>
  26 #include <stdarg.h>
  27 #include <stdio.h>
  28 #include <ctype.h>
  29 #include <string.h>
  30 #include <stdlib.h>
  31 #include <unistd.h>
  32 #include <errno.h>
  33 
  34 /*
  35  * This is the main program to test the signal chaining/ handling functionality
  36  * See bugs 6277077 and 6414402
  37  */
  38 
  39 #define TRUE  1
  40 #define FALSE 0
  41 typedef int boolean;
  42 
  43 static JNIEnv *env;
  44 static JavaVM *vm;
  45 
  46 // static int sigid = 0;
  47 
  48 // Define the test pass/ fail codes, may be we can use
  49 // nsk/share/native/native_consts.h in future
  50 static int TEST_PASSED=0;
  51 static int TEST_FAILED=1;
  52 
  53 // This variable is used to notify whether signal has been received or not.
  54 static volatile sig_atomic_t sig_received = 0;
  55 
  56 static char *mode = 0;
  57 static char *scenario = 0;
  58 static char *signal_name;
  59 static int signal_num = -1;
  60 
  61 static JavaVMOption *options = 0;
  62 static int numOptions = 0;
  63 
  64 typedef struct
  65 {
  66     int sigNum;
  67     const char* sigName;
  68 } signalDefinition;
  69 
  70 static signalDefinition signals[] =
  71 {
  72     {SIGINT, "SIGINT"},
  73     {SIGQUIT, "SIGQUIT"},
  74     {SIGILL, "SIGILL"},
  75     {SIGTRAP, "SIGTRAP"},
  76     {SIGIOT, "SIGIOT"},
  77 #ifdef SIGEMT
  78     {SIGEMT, "SIGEMT"},
  79 #endif
  80     {SIGFPE, "SIGFPE"},
  81     {SIGBUS, "SIGBUS"},
  82     {SIGSEGV, "SIGSEGV"},
  83     {SIGSYS, "SIGSYS"},
  84     {SIGPIPE, "SIGPIPE"},
  85     {SIGALRM, "SIGALRM"},
  86     {SIGTERM, "SIGTERM"},
  87     {SIGUSR1, "SIGUSR1"},
  88     {SIGUSR2, "SIGUSR2"},
  89 #ifdef SIGCLD
  90     {SIGCLD, "SIGCLD"},
  91 #endif
  92 #ifdef SIGPWR
  93     {SIGPWR, "SIGPWR"},
  94 #endif
  95     {SIGWINCH, "SIGWINCH"},
  96     {SIGURG, "SIGURG"},
  97 #ifdef SIGPOLL
  98     {SIGPOLL, "SIGPOLL"},
  99 #endif
 100     {SIGSTOP, "SIGSTOP"},
 101     {SIGTSTP, "SIGTSTP"},
 102     {SIGCONT, "SIGCONT"},
 103     {SIGTTIN, "SIGTTIN"},
 104     {SIGTTOU, "SIGTTOU"},
 105     {SIGVTALRM, "SIGVTALRM"},
 106     {SIGPROF, "SIGPROF"},
 107     {SIGXCPU, "SIGXCPU"},
 108     {SIGXFSZ, "SIGXFSZ"},
 109 #ifdef SIGWAITING
 110     {SIGWAITING, "SIGWAITING"},
 111 #endif
 112 #ifdef SIGLWP
 113     {SIGLWP, "SIGLWP"},
 114 #endif
 115 #ifdef SIGFREEZE
 116     {SIGFREEZE, "SIGFREEZE"},
 117 #endif
 118 #ifdef SIGTHAW
 119     {SIGTHAW, "SIGTHAW"},
 120 #endif
 121 #ifdef SIGLOST
 122     {SIGLOST, "SIGLOST"},
 123 #endif
 124 #ifdef SIGXRES
 125     {SIGXRES, "SIGXRES"},
 126 #endif
 127     {SIGHUP, "SIGHUP"}
 128 };
 129 
 130 boolean isSupportedSigScenario ()
 131 {
 132     if ( (!strcmp(scenario, "nojvm")) || (!strcmp(scenario, "prepre")) || (!strcmp(scenario, "prepost")) ||
 133                 (!strcmp(scenario, "postpost")) || (!strcmp(scenario, "postpre")) )
 134     {
 135         // printf("%s is a supported scenario\n", scenario);
 136         return TRUE;
 137     }
 138     else
 139     {
 140         printf("ERROR: %s is not a supported scenario\n", scenario);
 141         return FALSE;
 142     }
 143 }
 144 
 145 boolean isSupportedSigMode ()
 146 {
 147     if ( (!strcmp(mode, "sigset")) || (!strcmp(mode, "sigaction")) )
 148     {
 149         // printf("%s is a supported mode\n", mode);
 150         return TRUE;
 151     }
 152     else
 153     {
 154         printf("ERROR: %s is not a supported mode\n", mode);
 155         return FALSE;
 156     }
 157 }
 158 
 159 int getSigNumBySigName(const char* sigName)
 160 {
 161     int signals_len, sigdef_len, total_sigs, i=0;
 162 
 163     if (sigName == NULL) return -1;
 164 
 165     signals_len = sizeof(signals);
 166     sigdef_len = sizeof(signalDefinition);
 167     total_sigs = signals_len / sigdef_len;
 168     for (i = 0; i < total_sigs; i++)
 169     {
 170         // printf("Inside for loop, i = %d\n", i);
 171         if (!strcmp(sigName, signals[i].sigName))
 172             return signals[i].sigNum;
 173     }
 174 
 175     return -1;
 176 }
 177 
 178 // signal handler
 179 void handler(int sig)
 180 {
 181     printf("%s: signal handler for signal %d has been processed\n", signal_name, signal_num);
 182     sig_received = 1;
 183 }
 184 
 185 // Initialize VM with given options
 186 void initVM()
 187 {
 188     JavaVMInitArgs vm_args;
 189     int i =0;
 190     jint result;
 191 
 192     vm_args.nOptions = numOptions;
 193     vm_args.version = JNI_VERSION_1_2;
 194     vm_args.ignoreUnrecognized = JNI_FALSE;
 195     vm_args.options = options;
 196 
 197 /* try hardcoding options
 198     JavaVMOption option1[2];
 199     option1[0].optionString="-XX:+PrintCommandLineFlags";
 200     option1[1].optionString="-Xrs";
 201 */
 202     vm_args.options=options;
 203     vm_args.nOptions=numOptions;
 204 
 205     // Print the VM options in use
 206     printf("initVM: numOptions = %d\n", vm_args.nOptions);
 207     for (i = 0; i < vm_args.nOptions; i++)
 208     {
 209         printf("\tvm_args.options[%d].optionString = %s\n", i, vm_args.options[i].optionString);
 210     }
 211 
 212     // Initialize VM with given options
 213     result = JNI_CreateJavaVM( &vm, (void **) &env, &vm_args );
 214 
 215     // Did the VM initialize successfully ?
 216     if (result != 0)
 217     {
 218         printf("ERROR: cannot create Java VM.\n");
 219         exit(TEST_FAILED);
 220     }
 221 
 222     (*vm)->AttachCurrentThread(vm, (void **) &env,  (void *) 0);
 223     printf("initVM: JVM started and attached\n");
 224 }
 225 
 226 // Function to set up signal handler
 227 void setSignalHandler()
 228 {
 229     int retval = 0 ;
 230 
 231     if (!strcmp(mode, "sigaction"))
 232     {
 233         struct sigaction act;
 234         act.sa_handler = handler;
 235         sigemptyset(&act.sa_mask);
 236         act.sa_flags = 0;
 237         retval = sigaction(signal_num, &act, 0);
 238         if (retval != 0) {
 239            printf("ERROR: failed to set signal handler using function %s, error=%s\n", mode, strerror(errno));
 240            exit(TEST_FAILED);
 241         }
 242     } // end - dealing with sigaction
 243     else if (!strcmp(mode, "sigset"))
 244     {
 245         sigset(signal_num, handler);
 246     } // end dealing with sigset
 247     printf("%s: signal handler using function '%s' has been set\n", signal_name, mode);
 248 }
 249 
 250 // Function to invoke given signal
 251 void invokeSignal()
 252 {
 253     int pid, retval;
 254     sigset_t new_set, old_set;
 255 
 256     pid = getpid();
 257     retval = 0;
 258 
 259     // we need to unblock the signal in case it was previously blocked by JVM
 260     // and as result inherited by child process
 261     // (this is at least the case for SIGQUIT in case -Xrs flag is not used).
 262     // Otherwise the test will timeout.
 263     sigemptyset(&new_set);
 264     sigaddset(&new_set, signal_num);
 265     sigprocmask(SIG_UNBLOCK, &new_set, &old_set);
 266     if (retval != 0) {
 267         printf("ERROR: failed to unblock signal, error=%s\n", strerror(errno));
 268         exit(TEST_FAILED);
 269     }
 270 
 271     // send the signal
 272     retval = kill(pid, signal_num);
 273     if (retval != 0)
 274     {
 275         printf("ERROR: failed to send signal %s, error=%s\n", signal_name, strerror(errno));
 276         exit(TEST_FAILED);
 277     }
 278 
 279     // set original mask for the signal
 280     retval = sigprocmask(SIG_SETMASK, &old_set, NULL);
 281     if (retval != 0) {
 282         printf("ERROR: failed to set original mask for signal, error=%s\n", strerror(errno));
 283         exit(TEST_FAILED);
 284     }
 285 
 286     printf("%s: signal has been sent successfully\n", signal_name);
 287 }
 288 
 289 // Usage function
 290 void printUsage()
 291 {
 292     printf("Usage: sigtest -sig {signal_name} -mode {signal | sigset | sigaction } -scenario {nojvm | postpre | postpost | prepre | prepost}> [-vmopt jvm_option] \n");
 293     printf("\n");
 294     exit(TEST_FAILED);
 295 }
 296 
 297 // signal handler BEFORE VM initialization AND
 298 // Invoke signal BEFORE VM exits
 299 void scen_prepre()
 300 {
 301     setSignalHandler();
 302     initVM();
 303     invokeSignal();
 304     (*vm)->DestroyJavaVM(vm);
 305 }
 306 
 307 // signal handler BEFORE VM initialization AND
 308 // Invoke signal AFTER VM exits
 309 void scen_prepost()
 310 {
 311     setSignalHandler();
 312     initVM();
 313     (*vm)->DestroyJavaVM(vm);
 314     invokeSignal();
 315 }
 316 
 317 // signal handler AFTER VM initialization AND
 318 // Invoke signal BEFORE VM exits
 319 void scen_postpre()
 320 {
 321     initVM();
 322     setSignalHandler();
 323     invokeSignal();
 324     (*vm)->DestroyJavaVM(vm);
 325 }
 326 
 327 // signal handler AFTER VM initializationAND
 328 // Invoke signal AFTER VM exits
 329 void scen_postpost()
 330 {
 331     initVM();
 332     setSignalHandler();
 333     (*vm)->DestroyJavaVM(vm);
 334     invokeSignal();
 335 }
 336 
 337 // signal handler with no JVM in picture
 338 void scen_nojvm()
 339 {
 340     setSignalHandler();
 341     invokeSignal();
 342 }
 343 
 344 void run()
 345 {
 346     // print the current scenario
 347     if (!strcmp(scenario, "postpre"))
 348         scen_postpre();
 349     else if (!strcmp(scenario, "postpost"))
 350         scen_postpost();
 351     else if (!strcmp(scenario, "prepre"))
 352         scen_prepre();
 353     else if (!strcmp(scenario, "prepost"))
 354         scen_prepost();
 355     else if (!strcmp(scenario, "nojvm"))
 356         scen_nojvm();
 357 }
 358 
 359 // main main
 360 int main(int argc, char **argv)
 361 {
 362     int i=0, j;
 363 
 364     signal_num = -1;
 365     signal_name = NULL;
 366 
 367     // Parse the arguments and find out how many vm args we have
 368     for (i=1; i<argc; i++)
 369     {
 370         if (! strcmp(argv[i], "-sig") )
 371         {
 372             i++;
 373             if ( i >= argc )
 374             {
 375                 printUsage();
 376             }
 377             signal_name = argv[i];
 378 
 379         }
 380         else if (!strcmp(argv[i], "-mode"))
 381         {
 382             i++;
 383             if ( i >= argc )
 384             {
 385                 printUsage();
 386             }
 387             mode = argv[i];
 388         }
 389         else if (!strcmp(argv[i], "-scenario"))
 390         {
 391             i++;
 392             if ( i >= argc )
 393             {
 394                 printUsage();
 395             }
 396             scenario = argv[i];
 397         }
 398         else if (!strcmp(argv[i], "-vmopt"))
 399         {
 400             i++;
 401             if ( i >= argc )
 402             {
 403                 printUsage();
 404             }
 405             numOptions++;
 406         }
 407         else
 408         {
 409             printUsage();
 410         }
 411     }
 412 
 413     if ( !isSupportedSigScenario() || !isSupportedSigMode() )
 414     {
 415         printUsage();
 416     }
 417 
 418     // get signal number by it's name
 419     signal_num = getSigNumBySigName(signal_name);
 420     if (signal_num == -1)
 421     {
 422       printf("%s: unknown signal, perhaps is not supported on this platform, ignore\n",
 423             signal_name);
 424       exit(TEST_PASSED);
 425     }
 426 
 427     j = 0;
 428     // Initialize given number of VM options
 429     if (numOptions > 0)
 430     {
 431         options = (JavaVMOption *) malloc(numOptions * sizeof(JavaVMOption));
 432         for (i=0; i<argc; i++)
 433         {
 434             // parse VM options
 435             if (!strcmp(argv[i], "-vmopt"))
 436             {
 437                 i++;
 438                 if ( i >= argc )
 439                 {
 440                     printUsage();
 441                 }
 442                 options[j].optionString = argv[i];
 443                 j++;
 444             }
 445         }
 446     }
 447 
 448     // do signal invocation
 449     printf("%s: start testing: signal_num=%d,  mode=%s, scenario=%s\n", signal_name, signal_num, mode, scenario);
 450     run();
 451 
 452     while (!sig_received) {
 453       sleep(1);
 454       printf("%s: waiting for getting signal 1sec ...\n", signal_name);
 455     }
 456 
 457     printf("%s: signal has been received\n", signal_name);
 458 
 459     free(options);
 460 
 461     return (sig_received ? TEST_PASSED : TEST_FAILED);
 462 }