fb139cff1a
Reviewed-by: dholmes, stuefe
470 lines
11 KiB
C
470 lines
11 KiB
C
/*
|
|
* Copyright (c) 2007, 2020, 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 <jni.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
/*
|
|
* 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"))
|
|
{
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
#endif
|
|
sigset(signal_num, handler);
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
} // 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; i++)
|
|
{
|
|
if (! strcmp(argv[i], "-sig") )
|
|
{
|
|
i++;
|
|
if ( 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; i++)
|
|
{
|
|
// parse VM options
|
|
if (!strcmp(argv[i], "-vmopt"))
|
|
{
|
|
i++;
|
|
if ( 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);
|
|
}
|