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 }